001: package com.workingdogs.village;
002:
003: /*
004: * Licensed to the Apache Software Foundation (ASF) under one
005: * or more contributor license agreements. See the NOTICE file
006: * distributed with this work for additional information
007: * regarding copyright ownership. The ASF licenses this file
008: * to you under the Apache License, Version 2.0 (the
009: * "License"); you may not use this file except in compliance
010: * with the License. You may obtain a copy of the License at
011: *
012: * http://www.apache.org/licenses/LICENSE-2.0
013: *
014: * Unless required by applicable law or agreed to in writing,
015: * software distributed under the License is distributed on an
016: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017: * KIND, either express or implied. See the License for the
018: * specific language governing permissions and limitations
019: * under the License.
020: */
021:
022: import java.sql.Connection;
023: import java.sql.ResultSet;
024: import java.sql.SQLException;
025:
026: import java.util.Enumeration;
027:
028: /**
029: * This class is used for doing select/insert/delete/update on the database. A TableDataSet cannot be used to join multiple tables
030: * for an update, if you need join functionality on a select, you should use a <a href="QueryDataSet.html">QueryDataSet</a>.
031: *
032: * <P>
033: * Here is an example usage for this code that gets the first 10 records where column "a" = 1:
034: * <PRE>
035: * KeyDef kd = new KeyDef().setAttrib("column");
036: * TableDataSet tds = new TableDataSet(connection, "table_name", kd );
037: * tds.where ("a=1" ); // WHERE a = 1
038: * tds.fetchRecords(10); // fetch first 10 records where column a=1
039: * for ( int i=0;i< tds.size(); i++ )
040: * {
041: * Record rec = tds.getRecord(i); // zero based
042: * String columnA = rec.getValue("a");
043: * if ( columnA.equals ("1") )
044: * System.out.print ("We got a column!");
045: * }
046: * tds.close();
047: * </PRE>
048: * </p>
049: *
050: * <P>
051: * It is important to remember to always close() the TableDataSet when you are finished with it.
052: * </p>
053: *
054: * <P>
055: * As you can see, using a TableDataSet makes doing selects from the database trivial. You do not need to write any SQL and it
056: * makes it easy to cache a TableDataSet for future use within your application.
057: * </p>
058: *
059: * @author <a href="mailto:jon@latchkey.com">Jon S. Stevens</a>
060: * @version $Revision: 568 $
061: */
062: public class TableDataSet extends DataSet {
063: /** the optimistic locking column value */
064: private String optimisticLockingCol;
065:
066: /** the value for the sql where clause */
067: private String where = null;
068:
069: /** the value for the sql order by clause */
070: private String order = null;
071:
072: /** the value for the sql other clause */
073: private String other = null;
074:
075: // by default this is false;
076:
077: /** TODO: DOCUMENT ME! */
078: private boolean refreshOnSave = false;
079:
080: /**
081: * Default constructor.
082: *
083: * @exception SQLException
084: * @exception DataSetException
085: */
086: public TableDataSet() throws SQLException, DataSetException {
087: super ();
088: }
089:
090: /**
091: * Creates a new TableDataSet object.
092: *
093: * @param conn TODO: DOCUMENT ME!
094: * @param tableName TODO: DOCUMENT ME!
095: *
096: * @throws SQLException TODO: DOCUMENT ME!
097: * @throws DataSetException TODO: DOCUMENT ME!
098: */
099: public TableDataSet(Connection conn, String tableName)
100: throws SQLException, DataSetException {
101: super (conn, tableName);
102: }
103:
104: /**
105: * Creates a new TableDataSet object.
106: *
107: * @param conn TODO: DOCUMENT ME!
108: * @param schema TODO: DOCUMENT ME!
109: * @param keydef TODO: DOCUMENT ME!
110: *
111: * @throws SQLException TODO: DOCUMENT ME!
112: * @throws DataSetException TODO: DOCUMENT ME!
113: */
114: public TableDataSet(Connection conn, Schema schema, KeyDef keydef)
115: throws SQLException, DataSetException {
116: super (conn, schema, keydef);
117: }
118:
119: /**
120: * Creates a new TableDataSet object.
121: *
122: * @param conn TODO: DOCUMENT ME!
123: * @param tableName TODO: DOCUMENT ME!
124: * @param keydef TODO: DOCUMENT ME!
125: *
126: * @throws SQLException TODO: DOCUMENT ME!
127: * @throws DataSetException TODO: DOCUMENT ME!
128: */
129: public TableDataSet(Connection conn, String tableName, KeyDef keydef)
130: throws SQLException, DataSetException {
131: super (conn, tableName, keydef);
132: }
133:
134: /**
135: * Creates a new TableDataSet object.
136: *
137: * @param conn TODO: DOCUMENT ME!
138: * @param tableName TODO: DOCUMENT ME!
139: * @param columns TODO: DOCUMENT ME!
140: *
141: * @throws SQLException TODO: DOCUMENT ME!
142: * @throws DataSetException TODO: DOCUMENT ME!
143: */
144: public TableDataSet(Connection conn, String tableName,
145: String columns) throws SQLException, DataSetException {
146: super (conn, tableName, columns);
147: }
148:
149: /**
150: * Creates a new TableDataSet object.
151: *
152: * @param conn TODO: DOCUMENT ME!
153: * @param tableName TODO: DOCUMENT ME!
154: * @param columns TODO: DOCUMENT ME!
155: * @param keydef TODO: DOCUMENT ME!
156: *
157: * @throws SQLException TODO: DOCUMENT ME!
158: * @throws DataSetException TODO: DOCUMENT ME!
159: */
160: public TableDataSet(Connection conn, String tableName,
161: String columns, KeyDef keydef) throws SQLException,
162: DataSetException {
163: super (conn, tableName, columns, keydef);
164: }
165:
166: /**
167: * Use the TDS fetchRecords instead of the DataSet.fetchRecords
168: *
169: * @return an instance of myself
170: *
171: * @exception SQLException
172: * @exception DataSetException
173: */
174: public DataSet fetchRecords() throws SQLException, DataSetException {
175: return fetchRecords(-1);
176: }
177:
178: /**
179: * Use the TDS fetchRecords instead of the DataSet.fetchRecords
180: *
181: * @param max
182: *
183: * @return an instance of myself
184: *
185: * @exception SQLException
186: * @exception DataSetException
187: */
188: public DataSet fetchRecords(int max) throws SQLException,
189: DataSetException {
190: return fetchRecords(0, max);
191: }
192:
193: /**
194: * Fetch start to max records. start is at Record 0
195: *
196: * @param start
197: * @param max
198: *
199: * @return an instance of myself
200: *
201: * @exception SQLException
202: * @exception DataSetException
203: */
204: public DataSet fetchRecords(int start, int max)
205: throws SQLException, DataSetException {
206: buildSelectString();
207:
208: return super .fetchRecords(start, max);
209: }
210:
211: /**
212: * this is a string that contains the columns for the table that this TableDataSet represents.
213: *
214: * @return columns separated by ","
215: */
216: public String attributes() {
217: return super .getColumns();
218: }
219:
220: /**
221: * Returns the KeyDef for the DataSet
222: *
223: * @return a keydef
224: */
225: public KeyDef keydef() {
226: return super .keydef();
227: }
228:
229: /**
230: * Returns the ResultSet for the DataSet
231: *
232: * @return a ResultSet
233: *
234: * @throws SQLException TODO: DOCUMENT ME!
235: * @throws DataSetException TODO: DOCUMENT ME!
236: */
237: public ResultSet resultSet() throws SQLException, DataSetException {
238: return super .resultSet();
239: }
240:
241: /**
242: * Returns the Schema for the DataSet
243: *
244: * @return a Schema
245: */
246: public Schema schema() {
247: return super .schema();
248: }
249:
250: /**
251: * Saves all the records in the DataSet.
252: *
253: * @return total number of records updated/inserted/deleted
254: *
255: * @throws SQLException TODO: DOCUMENT ME!
256: * @throws DataSetException TODO: DOCUMENT ME!
257: */
258: public int save() throws SQLException, DataSetException {
259: return save(connection(), false);
260: }
261:
262: /**
263: * Saves all the records in the DataSet with the intransaction boolean value.
264: *
265: * @param intransaction TODO: DOCUMENT ME!
266: *
267: * @return total number of records updated/inserted/deleted
268: *
269: * @throws SQLException TODO: DOCUMENT ME!
270: * @throws DataSetException TODO: DOCUMENT ME!
271: */
272: public int save(boolean intransaction) throws SQLException,
273: DataSetException {
274: return save(connection(), intransaction);
275: }
276:
277: /**
278: * Saves all the records in the DataSet with the given connection and intransaction boolean value.
279: *
280: * @param conn TODO: DOCUMENT ME!
281: * @param intransaction TODO: DOCUMENT ME!
282: *
283: * @return total number of records updated/inserted/deleted
284: *
285: * @throws SQLException TODO: DOCUMENT ME!
286: * @throws DataSetException TODO: DOCUMENT ME!
287: */
288: public int save(Connection conn, boolean intransaction)
289: throws SQLException, DataSetException {
290: int j = 0;
291:
292: for (Enumeration e = records.elements(); e.hasMoreElements();) {
293: Record rec = (Record) e.nextElement();
294: rec.save(conn);
295: j++;
296: }
297:
298: // now go through and remove any records
299: // that were previously marked as a zombie by the
300: // delete process
301: removeDeletedRecords();
302:
303: return j;
304: }
305:
306: /**
307: * Not yet implemented
308: *
309: * @param conn TODO: DOCUMENT ME!
310: *
311: * @return TODO: DOCUMENT ME!
312: *
313: * @throws SQLException TODO: DOCUMENT ME!
314: * @throws DataSetException TODO: DOCUMENT ME!
315: */
316: public int saveWithoutStatusUpdate(Connection conn)
317: throws SQLException, DataSetException {
318: throw new DataSetException("Not yet implemented!");
319: }
320:
321: /**
322: * Hell if I know what this does.
323: *
324: * @return TODO: DOCUMENT ME!
325: */
326: public String debugInfo() {
327: return "Not yet implemented!";
328: }
329:
330: /**
331: * Removes any records that are marked as a zombie.
332: *
333: * @throws DataSetException TODO: DOCUMENT ME!
334: */
335: public void removeDeletedRecords() throws DataSetException {
336: for (Enumeration e = records.elements(); e.hasMoreElements();) {
337: Record rec = (Record) e.nextElement();
338:
339: if (rec.isAZombie()) {
340: removeRecord(rec);
341: }
342: }
343: }
344:
345: /**
346: * Sets the table column used for optomistic locking.
347: *
348: * @param olc TODO: DOCUMENT ME!
349: */
350: public void setOptimisticLockingColumn(String olc) {
351: this .optimisticLockingCol = olc;
352: }
353:
354: /**
355: * Gets the table column used for optomistic locking.
356: *
357: * @return string
358: */
359: public String optimisticLockingCol() {
360: return this .optimisticLockingCol;
361: }
362:
363: /**
364: * Sets the value for the SQL portion of the WHERE statement
365: *
366: * @param where TODO: DOCUMENT ME!
367: *
368: * @return instance of self
369: *
370: * @throws DataSetException TODO: DOCUMENT ME!
371: */
372: public TableDataSet where(String where) throws DataSetException {
373: if (where == null) {
374: throw new DataSetException(
375: "null not allowed for where clause");
376: }
377:
378: this .where = where;
379:
380: return this ;
381: }
382:
383: /**
384: * Gets the value of the SQL portion of WHERE.
385: *
386: * @return string
387: */
388: String getWhere() {
389: return this .where;
390: }
391:
392: /**
393: * Sets the value for the SQL portion of the ORDER statement
394: *
395: * @param order TODO: DOCUMENT ME!
396: *
397: * @return instance of self
398: *
399: * @throws DataSetException TODO: DOCUMENT ME!
400: */
401: public TableDataSet order(String order) throws DataSetException {
402: if (order == null) {
403: throw new DataSetException(
404: "null not allowed for order clause");
405: }
406:
407: this .order = order;
408:
409: return this ;
410: }
411:
412: /**
413: * Gets the value of the SQL portion of ORDER.
414: *
415: * @return string
416: */
417: String getOrder() {
418: return this .order;
419: }
420:
421: /**
422: * Sets the value for the SQL portion of the OTHER statement
423: *
424: * @param other TODO: DOCUMENT ME!
425: *
426: * @return instance of self
427: *
428: * @throws DataSetException TODO: DOCUMENT ME!
429: */
430: public TableDataSet other(String other) throws DataSetException {
431: if (other == null) {
432: throw new DataSetException(
433: "null not allowed for other clause");
434: }
435:
436: this .other = other;
437:
438: return this ;
439: }
440:
441: /**
442: * Gets the value of the SQL portion of OTHER.
443: *
444: * @return string
445: */
446: String getOther() {
447: return this .other;
448: }
449:
450: /**
451: * This method refreshes all of the Records stored in this TableDataSet.
452: *
453: * @param conn TODO: DOCUMENT ME!
454: *
455: * @throws SQLException TODO: DOCUMENT ME!
456: * @throws DataSetException TODO: DOCUMENT ME!
457: */
458: public void refresh(Connection conn) throws SQLException,
459: DataSetException {
460: for (Enumeration e = records.elements(); e.hasMoreElements();) {
461: Record rec = (Record) e.nextElement();
462: rec.refresh(conn);
463: }
464: }
465:
466: /**
467: * Setting this causes each Record to refresh itself when a save() is performed on it.
468: *
469: * <P>
470: * Default value is false.
471: * </p>
472: *
473: * @param val TODO: DOCUMENT ME!
474: */
475: public void setRefreshOnSave(boolean val) {
476: this .refreshOnSave = val;
477: }
478:
479: /**
480: * Setting this causes each Record to refresh itself when a save() is performed on it.
481: *
482: * <P>
483: * Default value is false.
484: * </p>
485: *
486: * @return true if it is on; false otherwise
487: */
488: public boolean refreshOnSave() {
489: return this .refreshOnSave;
490: }
491:
492: /**
493: * This sets additional SQL for the table name. The string appears after the table name. Sybase users would set this to
494: * "HOLDLOCK" to get repeatable reads.
495: *
496: * <P>
497: * FIXME: Is this right? I don't use Sybase.
498: * </p>
499: *
500: * @param tq TODO: DOCUMENT ME!
501: *
502: * @return an instance of self
503: */
504: public TableDataSet tableQualifier(String tq) {
505: // go directly to schema() cause it is where tableName is stored
506: schema().appendTableName(tq);
507:
508: return this ;
509: }
510:
511: /**
512: * The name of the table for which this TableDataSet was created.
513: *
514: * @return string
515: *
516: * @throws DataSetException TODO: DOCUMENT ME!
517: */
518: public String tableName() throws DataSetException {
519: return super .tableName();
520: }
521:
522: /**
523: * Not yet implemented
524: *
525: * @exception SQLException
526: * @exception DataSetException
527: */
528: public void updateStatus() throws SQLException, DataSetException {
529: throw new DataSetException("Not yet implemented!");
530: }
531:
532: /**
533: * Builds the select string that was used to populate this TableDataSet.
534: *
535: * @return SQL select string
536: *
537: * @throws DataSetException TODO: DOCUMENT ME!
538: */
539: public String getSelectString() throws DataSetException {
540: buildSelectString();
541:
542: return this .selectString.toString();
543: }
544:
545: /**
546: * Used by getSelectString to build the select string that was used to populate this TableDataSet.
547: *
548: * @throws DataSetException TODO: DOCUMENT ME!
549: */
550: private void buildSelectString() throws DataSetException {
551: if (selectString == null) {
552: selectString = new StringBuffer(256);
553: } else {
554: selectString.setLength(0);
555: }
556:
557: selectString.append("SELECT ");
558: selectString.append(schema().attributes());
559: selectString.append(" FROM ");
560: selectString.append(schema().tableName());
561:
562: if ((this .where != null) && (this .where.length() > 0)) {
563: selectString.append(" WHERE " + this .where);
564: }
565:
566: if ((this .order != null) && (this .order.length() > 0)) {
567: selectString.append(" ORDER BY " + this .order);
568: }
569:
570: if ((this .other != null) && (this .other.length() > 0)) {
571: selectString.append(this.other);
572: }
573: }
574: }
|