1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24 package org.dbforms.event.datalist.dao;
25
26 import org.apache.commons.logging.Log;
27 import org.apache.commons.logging.LogFactory;
28
29 import org.dbforms.config.Constants;
30 import org.dbforms.config.DbFormsConfigRegistry;
31 import org.dbforms.config.Field;
32 import org.dbforms.config.FieldTypes;
33 import org.dbforms.config.FieldValue;
34 import org.dbforms.config.FieldValues;
35 import org.dbforms.config.JDBCDataHelper;
36 import org.dbforms.config.ResultSetVector;
37 import org.dbforms.interfaces.DbEventInterceptorData;
38
39 import org.dbforms.util.FileHolder;
40 import org.dbforms.util.UniqueIDGenerator;
41 import org.dbforms.util.Util;
42
43 import java.sql.Connection;
44 import java.sql.PreparedStatement;
45 import java.sql.ResultSet;
46 import java.sql.ResultSetMetaData;
47 import java.sql.SQLException;
48 import java.sql.Statement;
49
50 import java.util.ArrayList;
51 import java.util.HashMap;
52 import java.util.Iterator;
53 import java.util.List;
54 import java.util.Map;
55 import java.util.Vector;
56
57 /***
58 * Special implementation of DataSource. This is the default class and deals
59 * with JDBC Connections.
60 *
61 * @author hkk
62 */
63 public class DataSourceJDBC extends AbstractDataSource {
64 private static Log logCat = LogFactory.getLog(DataSourceJDBC.class);
65
66 private Connection connection;
67
68 private List data;
69
70 private Map keys;
71
72 private ResultSet rs;
73
74 private Statement stmt;
75
76 private String connectionName;
77
78 private String query;
79
80 private String sqlFilter;
81
82 private String tableList;
83
84 private String whereClause;
85
86 private FieldValue[] filterConstraint;
87
88 private FieldValue[] orderConstraint;
89
90 private FieldValue[] sqlFilterParams;
91
92 private boolean calcRowCount = false;
93
94 private boolean fetchedAll = false;
95
96 private int colCount;
97
98 private int rowCount = 0;
99
100 /***
101 * Creates a new DataSourceJDBC object.
102 */
103 public DataSourceJDBC() {
104 data = new ArrayList();
105 keys = new HashMap();
106 }
107
108 /***
109 * DOCUMENT ME!
110 *
111 * @param calcRowCount
112 * The calcRowCount to set.
113 */
114 public void setCalcRowCount(boolean calcRowCount) {
115 this.calcRowCount = calcRowCount;
116 }
117
118 /***
119 * DOCUMENT ME!
120 *
121 * @return Returns the calcRowCount.
122 */
123 public boolean isCalcRowCount() {
124 return calcRowCount;
125 }
126
127 /***
128 * Set the tableList and whererClause attributes used to build the SQL
129 * Select condition.
130 *
131 * @param tableList
132 * the table list string
133 * @param whereClause
134 * the SQL where clause string
135 */
136 public void setSelect(String tableList, String whereClause) {
137 this.tableList = tableList;
138 this.whereClause = whereClause;
139 }
140
141 /***
142 * Set the filterConstraint and orderConstraint used to build the SQL Select
143 * condition.
144 *
145 * @param filterConstraint
146 * FieldValue array used to build a cumulation of rules for
147 * filtering fields.
148 * @param orderConstraint
149 * FieldValue array used to build a cumulation of rules for
150 * ordering (sorting) and restricting fields.
151 * @param sqlFilter
152 * sql condition to add to where clause
153 * @param sqlFilterParams
154 * list of FieldValues to fill the sqlFilter with
155 */
156 public void setSelect(FieldValue[] filterConstraint,
157 FieldValue[] orderConstraint, String sqlFilter,
158 FieldValue[] sqlFilterParams) {
159 this.filterConstraint = filterConstraint;
160 this.orderConstraint = orderConstraint;
161 this.sqlFilter = sqlFilter;
162 this.sqlFilterParams = sqlFilterParams;
163 }
164
165 /***
166 * performs a delete in the DataSource
167 *
168 * @param interceptorData
169 * DOCUMENT ME!
170 * @param keyValuesStr
171 * keyValueStr to the row to update <br>
172 * key format: FieldID ":" Length ":" Value <br>
173 * example: if key id = 121 and field id=2 then keyValueStr
174 * contains "2:3:121" <br>
175 * If the key consists of more than one fields, the key values
176 * are seperated through "-" <br>
177 * example: value of field 1=12, value of field 3=1992, then
178 * we'll get "1:2:12-3:4:1992"
179 *
180 * @throws SQLException
181 */
182 public int doDelete(DbEventInterceptorData interceptorData,
183 String keyValuesStr) throws SQLException {
184 int res = 0;
185 FieldValues fieldValues = null;
186
187
188 if (getTable().containsDiskblob()) {
189 ResultSet diskblobs = null;
190 StringBuffer queryBuf = new StringBuffer();
191 queryBuf.append(getTable().getDisblobSelectStatement());
192 queryBuf.append(" WHERE ");
193 queryBuf.append(getTable().getWhereClauseForKeyFields(keyValuesStr));
194
195 PreparedStatement diskblobsPs = interceptorData.getConnection()
196 .prepareStatement(queryBuf.toString());
197
198 try {
199 getTable().populateWhereClauseWithKeyFields(keyValuesStr,
200 diskblobsPs, 1);
201
202 diskblobs = diskblobsPs.executeQuery();
203
204 try {
205 ResultSetVector rsv = new ResultSetVector(getTable(),
206 getTable().getDiskblobs());
207 rsv.addResultSet(interceptorData, diskblobs);
208
209 if (!ResultSetVector.isNull(rsv)) {
210 rsv.moveFirst();
211 fieldValues = rsv.getCurrentRowAsFieldValues();
212 }
213 } finally {
214 diskblobs.close();
215 }
216 } finally {
217 diskblobsPs.close();
218 }
219 }
220
221
222 PreparedStatement ps = interceptorData.getConnection()
223 .prepareStatement(getTable().getDeleteStatement(keyValuesStr));
224
225 try {
226
227
228
229 getTable().populateWhereClauseWithKeyFields(keyValuesStr, ps, 1);
230
231
232 res = ps.executeUpdate();
233
234 if (fieldValues != null) {
235 deleteBlobFilesFromDisk(fieldValues);
236 }
237 } finally {
238 ps.close();
239 }
240 return res;
241 }
242
243 /***
244 * Performs an insert into the DataSource
245 *
246 * @param interceptorData
247 * DOCUMENT ME!
248 * @param fieldValues
249 * FieldValues to insert
250 *
251 * @throws SQLException
252 */
253 public int doInsert(DbEventInterceptorData interceptorData,
254 FieldValues fieldValues) throws SQLException {
255 String query = getTable().getInsertStatement(fieldValues);
256
257 PreparedStatement ps = interceptorData.getConnection()
258 .prepareStatement(query);
259
260 int res = 0;
261 try {
262
263 fillWithData(ps, fieldValues);
264 res = ps.executeUpdate();
265 } finally {
266 ps.close();
267 }
268
269
270 saveBlobFilesToDisk(fieldValues);
271 return res;
272 }
273
274 /***
275 * Performs an update into the DataSource
276 *
277 * @param interceptorData
278 * DOCUMENT ME!
279 * @param fieldValues
280 * FieldValues to update
281 * @param keyValuesStr
282 * keyValueStr to the row to update <br>
283 * key format: FieldID ":" Length ":" Value <br>
284 * example: if key id = 121 and field id=2 then keyValueStr
285 * contains "2:3:121" <br>
286 * If the key consists of more than one fields, the key values
287 * are seperated through "-" <br>
288 * example: value of field 1=12, value of field 3=1992, then
289 * we'll get "1:2:12-3:4:1992"
290 *
291 * @throws SQLException
292 */
293 public int doUpdate(DbEventInterceptorData interceptorData,
294 FieldValues fieldValues, String keyValuesStr) throws SQLException {
295 int res = 0;
296
297 String query = getTable().getUpdateStatement(fieldValues, keyValuesStr);
298 PreparedStatement ps = interceptorData.getConnection()
299 .prepareStatement(query);
300 try {
301 int col = fillWithData(ps, fieldValues);
302 getTable().populateWhereClauseWithKeyFields(keyValuesStr, ps, col);
303
304
305 res = ps.executeUpdate();
306 logCat.info("update rows: " + String.valueOf(res));
307
308 } finally {
309 ps.close();
310 }
311
312
313 saveBlobFilesToDisk(fieldValues);
314 return res;
315 }
316
317 /***
318 * set the connection parameter for the DataSouce. virtual method, if you
319 * need the connection data you must override the method In this special
320 * case we need our own connection to save it in the session.
321 *
322 * @param con
323 * the JDBC Connection object
324 * @param dbConnectionName
325 * name of the used db connection. Can be used to get an own db
326 * connection, e.g. to hold it during the session (see
327 * DataSourceJDBC for example!)
328 */
329 protected void setConnection(Connection con, String dbConnectionName) {
330 close();
331
332
333 connectionName = Util.isNull(dbConnectionName) ? "default"
334 : dbConnectionName;
335 }
336
337 /***
338 * Get the requested row as array of objects.
339 *
340 * @param i
341 * the row number
342 *
343 * @return the requested row as array of objects
344 *
345 * @throws SQLException
346 * if any error occurs
347 */
348 protected final Object[] getRow(int i) throws SQLException {
349 Object[] result = null;
350
351 if (i >= 0) {
352 if (i < data.size()) {
353 result = (Object[]) data.get(i);
354 } else {
355 if (!fetchedAll) {
356 while (rs.next()) {
357 addRow();
358 if (i < data.size()) {
359 result = (Object[]) data.get(i);
360 break;
361 }
362 }
363 checkResultSetEnd();
364 }
365 }
366 }
367
368 return result;
369 }
370
371 /***
372 * Release all the resources holded by this datasource. <br>
373 * Clean the underlying data and keys vectors, then close the JDBC
374 * resultSet, statement and connection objects.
375 */
376 protected final void close() {
377 if (data != null) {
378 data.clear();
379 }
380
381 if (keys != null) {
382 keys.clear();
383 }
384
385 closeConnection();
386
387
388 fetchedAll = false;
389 }
390
391 /***
392 * Find the first row of the internal data vector.
393 *
394 * @param startRow
395 * the string identifying the initial row
396 *
397 * @return the start row position
398 *
399 * @throws SQLException
400 * if any error occurs
401 */
402 protected final int findStartRow(String startRow) throws SQLException {
403 int result = 0;
404 boolean found = false;
405
406 if (startRow != null) {
407 Integer i = (Integer) keys.get(startRow);
408
409 if (i != null) {
410 result = i.intValue();
411 found = true;
412 }
413
414 if (!found && !fetchedAll) {
415 while (rs.next()) {
416 String key = addRow();
417
418 if (startRow.equals(key)) {
419 result = data.size() - 1;
420
421 break;
422 }
423 }
424
425 checkResultSetEnd();
426 }
427 }
428
429 return result;
430 }
431
432 /***
433 * return true if there are more records to fetch then the given record
434 * number
435 *
436 * @param i
437 * index of last fetched row.
438 *
439 * @return true if there are more records to fetch then the given record
440 * number
441 *
442 * @throws SQLException
443 */
444 protected final boolean hasMore(int i) throws SQLException {
445 return !fetchedAll || (i < data.size());
446 }
447
448 /***
449 * Open this datasource and initialize its resources.
450 *
451 * @throws SQLException
452 * if any error occurs
453 */
454 protected void open() throws SQLException {
455 if (!fetchedAll && (rs == null)) {
456 if ((connection == null) || connection.isClosed()) {
457 try {
458 this.connection = DbFormsConfigRegistry.instance().lookup()
459 .getConnection(connectionName);
460 } catch (Exception e) {
461 logCat.error("open", e);
462 }
463 }
464
465 if (connection == null) {
466 throw new SQLException("no connection found!");
467 }
468
469 if (Util.isNull(whereClause)) {
470 query = getTable().getSelectQuery(getTable().getFields(),
471 filterConstraint, orderConstraint, sqlFilter,
472 Constants.COMPARE_NONE);
473 stmt = connection.prepareStatement(query);
474
475 if (stmt == null) {
476 throw new SQLException("no statement: " + query);
477 }
478
479
480
481 rs = getTable().getDoSelectResultSet(filterConstraint,
482 orderConstraint, sqlFilterParams,
483 Constants.COMPARE_NONE, (PreparedStatement) stmt);
484 } else {
485 query = getTable().getFreeFormSelectQuery(
486 getTable().getFields(), whereClause, tableList);
487 stmt = connection.createStatement();
488
489 if (stmt == null) {
490 throw new SQLException("no statement");
491 }
492
493 rs = stmt.executeQuery(query);
494 }
495
496 ResultSetMetaData rsmd = rs.getMetaData();
497 colCount = rsmd.getColumnCount();
498
499 if (isCalcRowCount()) {
500 Field f = new Field();
501 f.setName("count(*) cnt");
502 Vector v = new Vector();
503 v.add(f);
504
505 ResultSet prs = null;
506 if (Util.isNull(whereClause)) {
507 String pquery = getTable().getSelectQuery(v,
508 filterConstraint, orderConstraint, sqlFilter,
509 Constants.COMPARE_NONE);
510 PreparedStatement pstmt = connection
511 .prepareStatement(pquery);
512
513 if (pstmt == null) {
514 throw new SQLException("no statement: " + pquery);
515 }
516
517 prs = getTable().getDoSelectResultSet(filterConstraint,
518 orderConstraint, sqlFilterParams,
519 Constants.COMPARE_NONE, pstmt);
520 } else {
521 String pquery = getTable().getFreeFormSelectQuery(v,
522 whereClause, tableList);
523 Statement pstmt = connection.createStatement();
524
525 if (pstmt == null) {
526 throw new SQLException("no statement");
527 }
528
529 prs = pstmt.executeQuery(pquery);
530 }
531 prs.next();
532 rowCount = prs.getInt(prs.findColumn("cnt"));
533 }
534 }
535 }
536
537 /***
538 * Get the size of the data vector.
539 *
540 * @return the size of the data vector
541 *
542 * @throws SQLException
543 * if any error occurs
544 */
545 protected final int size() throws SQLException {
546
547
548
549
550
551
552 if (!fetchedAll) {
553 while (rs.next()) {
554 try {
555 addRow();
556 } catch (Exception e) {
557 logCat.error("size", e);
558 break;
559 }
560 }
561 closeConnection();
562 }
563 return data.size();
564 }
565
566 /***
567 * DOCUMENT ME!
568 *
569 * @return Returns the rowCount.
570 */
571 protected int getRowCount() {
572 return rowCount;
573 }
574
575 private String addRow() throws SQLException {
576 Integer j = new Integer(data.size());
577 Object[] objectRow = new Object[colCount];
578 String[] stringRow = new String[colCount];
579
580 for (int i = 0; i < colCount; i++) {
581 objectRow[i] = JDBCDataHelper.getData(rs, getTable().getField(i)
582 .getEscaper(), i + 1);
583 stringRow[i] = (objectRow[i] != null) ? objectRow[i].toString()
584 : null;
585 }
586
587 data.add(objectRow);
588
589 String key = getTable().getKeyPositionString(stringRow);
590 keys.put(key, j);
591
592 return key;
593 }
594
595 private void checkResultSetEnd() throws SQLException {
596 if (rs.next()) {
597 addRow();
598 } else {
599 closeConnection();
600 }
601 }
602
603 private void closeConnection() {
604 fetchedAll = true;
605
606 if (rs != null) {
607 try {
608 rs.close();
609 } catch (SQLException e) {
610 logCat.info("closeConnection", e);
611 }
612 rs = null;
613 }
614
615 if (stmt != null) {
616 try {
617 stmt.close();
618 } catch (SQLException e) {
619 logCat.info("closeConnection", e);
620 }
621 stmt = null;
622 }
623
624 if (connection != null) {
625 try {
626 if (!connection.isClosed()) {
627 connection.close();
628 }
629 } catch (SQLException e) {
630 logCat.info("closeConnection", e);
631 }
632 connection = null;
633 }
634 }
635
636
637
638 private int fillWithData(PreparedStatement ps, FieldValues fieldValues)
639 throws SQLException {
640
641
642 Iterator e = fieldValues.keys();
643 int col = 1;
644
645 while (e.hasNext()) {
646 String fieldName = (String) e.next();
647 Field curField = getTable().getFieldByName(fieldName);
648
649 if ((curField != null) && !getTable().isCalcField(curField.getId()) && Util.isNull(curField.getExpression())) {
650 FieldValue fv = fieldValues.get(fieldName);
651
652 logCat.debug("Retrieved curField:" + curField.getName()
653 + " type:" + curField.getType());
654
655 int fieldType = curField.getType();
656 Object value = null;
657
658 if (fieldType == FieldTypes.BLOB) {
659
660
661 if (fv.getFileHolder() == null) {
662
663
664 value = fv.getFieldValue();
665 } else {
666 value = fv.getFileHolder();
667 }
668 } else if (fieldType == FieldTypes.DISKBLOB) {
669 FileHolder fileHolder = fv.getFileHolder();
670
671
672 String fileName = fileHolder.getFileName();
673
674
675 if (curField.hasEncodedSet()) {
676 int dotIndex = fileName.lastIndexOf('.');
677 String suffix = (dotIndex != -1) ? fileName
678 .substring(dotIndex) : "";
679 fileHolder.setFileName(UniqueIDGenerator.getUniqueID()
680 + suffix);
681
682
683
684 value = fileHolder.getFileName();
685 } else {
686
687
688 value = fileName;
689 }
690 } else {
691
692
693 value = fv.getFieldValueAsObject();
694 }
695
696 logCat.info("field=" + curField.getName() + " col=" + col
697 + " value=" + value + " type=" + fieldType);
698 JDBCDataHelper.fillWithData(ps, curField.getEscaper(), col,
699 value, fieldType, getTable().getBlobHandlingStrategy());
700 col++;
701 }
702 }
703
704 return col;
705 }
706 }