View Javadoc

1   package com.workingdogs.village;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *   http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import java.sql.Connection;
23  import java.sql.ResultSet;
24  import java.sql.SQLException;
25  
26  import java.util.Enumeration;
27  
28  /***
29   * This class is used for doing select/insert/delete/update on the database. A TableDataSet cannot be used to join multiple tables
30   * for an update, if you need join functionality on a select, you should use a <a href="QueryDataSet.html">QueryDataSet</a>.
31   *
32   * <P>
33   * Here is an example usage for this code that gets the first 10 records where column "a" = 1:
34   * <PRE>
35   *  KeyDef kd = new KeyDef().setAttrib("column");
36   *  TableDataSet tds = new TableDataSet(connection, "table_name", kd );
37   *  tds.where ("a=1" ); // WHERE a = 1
38   *  tds.fetchRecords(10); // fetch first 10 records where column a=1
39   *  for ( int i=0;i< tds.size(); i++ )
40   *  {
41   *  Record rec = tds.getRecord(i); // zero based
42   *  String columnA = rec.getValue("a");
43   *  if ( columnA.equals ("1") )
44   *  System.out.print ("We got a column!");
45   *  }
46   *  tds.close();
47   *  </PRE>
48   * </p>
49   *
50   * <P>
51   * It is important to remember to always close() the TableDataSet when you are finished with it.
52   * </p>
53   *
54   * <P>
55   * As you can see, using a TableDataSet makes doing selects from the database trivial. You do not need to write any SQL and it
56   * makes it easy to cache a TableDataSet for future use within your application.
57   * </p>
58   *
59   * @author <a href="mailto:jon@latchkey.com">Jon S. Stevens</a>
60   * @version $Revision: 568 $
61   */
62  public class TableDataSet
63          extends DataSet
64  {
65      /*** the optimistic locking column value */
66      private String optimisticLockingCol;
67  
68      /*** the value for the sql where clause */
69      private String where = null;
70  
71      /*** the value for the sql order by clause */
72      private String order = null;
73  
74      /*** the value for the sql other clause */
75      private String other = null;
76  
77      // by default this is false;
78  
79      /*** TODO: DOCUMENT ME! */
80      private boolean refreshOnSave = false;
81  
82      /***
83       * Default constructor.
84       *
85       * @exception SQLException
86       * @exception DataSetException
87       */
88      public TableDataSet()
89              throws SQLException, DataSetException
90      {
91          super();
92      }
93  
94      /***
95       * Creates a new TableDataSet object.
96       *
97       * @param conn TODO: DOCUMENT ME!
98       * @param tableName TODO: DOCUMENT ME!
99       *
100      * @throws SQLException TODO: DOCUMENT ME!
101      * @throws DataSetException TODO: DOCUMENT ME!
102      */
103     public TableDataSet(Connection conn, String tableName)
104             throws SQLException, DataSetException
105     {
106         super(conn, tableName);
107     }
108 
109     /***
110      * Creates a new TableDataSet object.
111      *
112      * @param conn TODO: DOCUMENT ME!
113      * @param schema TODO: DOCUMENT ME!
114      * @param keydef TODO: DOCUMENT ME!
115      *
116      * @throws SQLException TODO: DOCUMENT ME!
117      * @throws DataSetException TODO: DOCUMENT ME!
118      */
119     public TableDataSet(Connection conn, Schema schema, KeyDef keydef)
120             throws SQLException, DataSetException
121     {
122         super(conn, schema, keydef);
123     }
124 
125     /***
126      * Creates a new TableDataSet object.
127      *
128      * @param conn TODO: DOCUMENT ME!
129      * @param tableName TODO: DOCUMENT ME!
130      * @param keydef TODO: DOCUMENT ME!
131      *
132      * @throws SQLException TODO: DOCUMENT ME!
133      * @throws DataSetException TODO: DOCUMENT ME!
134      */
135     public TableDataSet(Connection conn, String tableName, KeyDef keydef)
136             throws SQLException, DataSetException
137     {
138         super(conn, tableName, keydef);
139     }
140 
141     /***
142      * Creates a new TableDataSet object.
143      *
144      * @param conn TODO: DOCUMENT ME!
145      * @param tableName TODO: DOCUMENT ME!
146      * @param columns TODO: DOCUMENT ME!
147      *
148      * @throws SQLException TODO: DOCUMENT ME!
149      * @throws DataSetException TODO: DOCUMENT ME!
150      */
151     public TableDataSet(Connection conn, String tableName, String columns)
152             throws SQLException, DataSetException
153     {
154         super(conn, tableName, columns);
155     }
156 
157     /***
158      * Creates a new TableDataSet object.
159      *
160      * @param conn TODO: DOCUMENT ME!
161      * @param tableName TODO: DOCUMENT ME!
162      * @param columns TODO: DOCUMENT ME!
163      * @param keydef TODO: DOCUMENT ME!
164      *
165      * @throws SQLException TODO: DOCUMENT ME!
166      * @throws DataSetException TODO: DOCUMENT ME!
167      */
168     public TableDataSet(Connection conn, String tableName, String columns, KeyDef keydef)
169             throws SQLException, DataSetException
170     {
171         super(conn, tableName, columns, keydef);
172     }
173 
174     /***
175      * Use the TDS fetchRecords instead of the DataSet.fetchRecords
176      *
177      * @return an instance of myself
178      *
179      * @exception SQLException
180      * @exception DataSetException
181      */
182     public DataSet fetchRecords()
183             throws SQLException, DataSetException
184     {
185         return fetchRecords(-1);
186     }
187 
188     /***
189      * Use the TDS fetchRecords instead of the DataSet.fetchRecords
190      *
191      * @param max
192      *
193      * @return an instance of myself
194      *
195      * @exception SQLException
196      * @exception DataSetException
197      */
198     public DataSet fetchRecords(int max)
199             throws SQLException, DataSetException
200     {
201         return fetchRecords(0, max);
202     }
203 
204     /***
205      * Fetch start to max records. start is at Record 0
206      *
207      * @param start
208      * @param max
209      *
210      * @return an instance of myself
211      *
212      * @exception SQLException
213      * @exception DataSetException
214      */
215     public DataSet fetchRecords(int start, int max)
216             throws SQLException, DataSetException
217     {
218         buildSelectString();
219 
220         return super.fetchRecords(start, max);
221     }
222 
223     /***
224      * this is a string that contains the columns for the table that this TableDataSet represents.
225      *
226      * @return columns separated by ","
227      */
228     public String attributes()
229     {
230         return super.getColumns();
231     }
232 
233     /***
234      * Returns the KeyDef for the DataSet
235      *
236      * @return a keydef
237      */
238     public KeyDef keydef()
239     {
240         return super.keydef();
241     }
242 
243     /***
244      * Returns the ResultSet for the DataSet
245      *
246      * @return a ResultSet
247      *
248      * @throws SQLException TODO: DOCUMENT ME!
249      * @throws DataSetException TODO: DOCUMENT ME!
250      */
251     public ResultSet resultSet()
252             throws SQLException, DataSetException
253     {
254         return super.resultSet();
255     }
256 
257     /***
258      * Returns the Schema for the DataSet
259      *
260      * @return a Schema
261      */
262     public Schema schema()
263     {
264         return super.schema();
265     }
266 
267     /***
268      * Saves all the records in the DataSet.
269      *
270      * @return total number of records updated/inserted/deleted
271      *
272      * @throws SQLException TODO: DOCUMENT ME!
273      * @throws DataSetException TODO: DOCUMENT ME!
274      */
275     public int save()
276             throws SQLException, DataSetException
277     {
278         return save(connection(), false);
279     }
280 
281     /***
282      * Saves all the records in the DataSet with the intransaction boolean value.
283      *
284      * @param intransaction TODO: DOCUMENT ME!
285      *
286      * @return total number of records updated/inserted/deleted
287      *
288      * @throws SQLException TODO: DOCUMENT ME!
289      * @throws DataSetException TODO: DOCUMENT ME!
290      */
291     public int save(boolean intransaction)
292             throws SQLException, DataSetException
293     {
294         return save(connection(), intransaction);
295     }
296 
297     /***
298      * Saves all the records in the DataSet with the given connection and intransaction boolean value.
299      *
300      * @param conn TODO: DOCUMENT ME!
301      * @param intransaction TODO: DOCUMENT ME!
302      *
303      * @return total number of records updated/inserted/deleted
304      *
305      * @throws SQLException TODO: DOCUMENT ME!
306      * @throws DataSetException TODO: DOCUMENT ME!
307      */
308     public int save(Connection conn, boolean intransaction)
309             throws SQLException, DataSetException
310     {
311         int j = 0;
312 
313         for (Enumeration e = records.elements(); e.hasMoreElements();)
314         {
315             Record rec = (Record) e.nextElement();
316             rec.save(conn);
317             j++;
318         }
319 
320         // now go through and remove any records
321         // that were previously marked as a zombie by the
322         // delete process
323         removeDeletedRecords();
324 
325         return j;
326     }
327 
328     /***
329      * Not yet implemented
330      *
331      * @param conn TODO: DOCUMENT ME!
332      *
333      * @return TODO: DOCUMENT ME!
334      *
335      * @throws SQLException TODO: DOCUMENT ME!
336      * @throws DataSetException TODO: DOCUMENT ME!
337      */
338     public int saveWithoutStatusUpdate(Connection conn)
339             throws SQLException, DataSetException
340     {
341         throw new DataSetException("Not yet implemented!");
342     }
343 
344     /***
345      * Hell if I know what this does.
346      *
347      * @return TODO: DOCUMENT ME!
348      */
349     public String debugInfo()
350     {
351         return "Not yet implemented!";
352     }
353 
354     /***
355      * Removes any records that are marked as a zombie.
356      *
357      * @throws DataSetException TODO: DOCUMENT ME!
358      */
359     public void removeDeletedRecords()
360             throws DataSetException
361     {
362         for (Enumeration e = records.elements(); e.hasMoreElements();)
363         {
364             Record rec = (Record) e.nextElement();
365 
366             if (rec.isAZombie())
367             {
368                 removeRecord(rec);
369             }
370         }
371     }
372 
373     /***
374      * Sets the table column used for optomistic locking.
375      *
376      * @param olc TODO: DOCUMENT ME!
377      */
378     public void setOptimisticLockingColumn(String olc)
379     {
380         this.optimisticLockingCol = olc;
381     }
382 
383     /***
384      * Gets the table column used for optomistic locking.
385      *
386      * @return string
387      */
388     public String optimisticLockingCol()
389     {
390         return this.optimisticLockingCol;
391     }
392 
393     /***
394      * Sets the value for the SQL portion of the WHERE statement
395      *
396      * @param where TODO: DOCUMENT ME!
397      *
398      * @return instance of self
399      *
400      * @throws DataSetException TODO: DOCUMENT ME!
401      */
402     public TableDataSet where(String where)
403             throws DataSetException
404     {
405         if (where == null)
406         {
407             throw new DataSetException("null not allowed for where clause");
408         }
409 
410         this.where = where;
411 
412         return this;
413     }
414 
415     /***
416      * Gets the value of the SQL portion of WHERE.
417      *
418      * @return string
419      */
420     String getWhere()
421     {
422         return this.where;
423     }
424 
425     /***
426      * Sets the value for the SQL portion of the ORDER statement
427      *
428      * @param order TODO: DOCUMENT ME!
429      *
430      * @return instance of self
431      *
432      * @throws DataSetException TODO: DOCUMENT ME!
433      */
434     public TableDataSet order(String order)
435             throws DataSetException
436     {
437         if (order == null)
438         {
439             throw new DataSetException("null not allowed for order clause");
440         }
441 
442         this.order = order;
443 
444         return this;
445     }
446 
447     /***
448      * Gets the value of the SQL portion of ORDER.
449      *
450      * @return string
451      */
452     String getOrder()
453     {
454         return this.order;
455     }
456 
457     /***
458      * Sets the value for the SQL portion of the OTHER statement
459      *
460      * @param other TODO: DOCUMENT ME!
461      *
462      * @return instance of self
463      *
464      * @throws DataSetException TODO: DOCUMENT ME!
465      */
466     public TableDataSet other(String other)
467             throws DataSetException
468     {
469         if (other == null)
470         {
471             throw new DataSetException("null not allowed for other clause");
472         }
473 
474         this.other = other;
475 
476         return this;
477     }
478 
479     /***
480      * Gets the value of the SQL portion of OTHER.
481      *
482      * @return string
483      */
484     String getOther()
485     {
486         return this.other;
487     }
488 
489     /***
490      * This method refreshes all of the Records stored in this TableDataSet.
491      *
492      * @param conn TODO: DOCUMENT ME!
493      *
494      * @throws SQLException TODO: DOCUMENT ME!
495      * @throws DataSetException TODO: DOCUMENT ME!
496      */
497     public void refresh(Connection conn)
498             throws SQLException, DataSetException
499     {
500         for (Enumeration e = records.elements(); e.hasMoreElements();)
501         {
502             Record rec = (Record) e.nextElement();
503             rec.refresh(conn);
504         }
505     }
506 
507     /***
508      * Setting this causes each Record to refresh itself when a save() is performed on it.
509      *
510      * <P>
511      * Default value is false.
512      * </p>
513      *
514      * @param val TODO: DOCUMENT ME!
515      */
516     public void setRefreshOnSave(boolean val)
517     {
518         this.refreshOnSave = val;
519     }
520 
521     /***
522      * Setting this causes each Record to refresh itself when a save() is performed on it.
523      *
524      * <P>
525      * Default value is false.
526      * </p>
527      *
528      * @return true if it is on; false otherwise
529      */
530     public boolean refreshOnSave()
531     {
532         return this.refreshOnSave;
533     }
534 
535     /***
536      * This sets additional SQL for the table name. The string appears after the table name. Sybase users would set this to
537      * "HOLDLOCK" to get repeatable reads.
538      *
539      * <P>
540      * FIXME: Is this right? I don't use Sybase.
541      * </p>
542      *
543      * @param tq TODO: DOCUMENT ME!
544      *
545      * @return an instance of self
546      */
547     public TableDataSet tableQualifier(String tq)
548     {
549         // go directly to schema() cause it is where tableName is stored
550         schema().appendTableName(tq);
551 
552         return this;
553     }
554 
555     /***
556      * The name of the table for which this TableDataSet was created.
557      *
558      * @return string
559      *
560      * @throws DataSetException TODO: DOCUMENT ME!
561      */
562     public String tableName()
563             throws DataSetException
564     {
565         return super.tableName();
566     }
567 
568     /***
569      * Not yet implemented
570      *
571      * @exception SQLException
572      * @exception DataSetException
573      */
574     public void updateStatus()
575             throws SQLException, DataSetException
576     {
577         throw new DataSetException("Not yet implemented!");
578     }
579 
580     /***
581      * Builds the select string that was used to populate this TableDataSet.
582      *
583      * @return SQL select string
584      *
585      * @throws DataSetException TODO: DOCUMENT ME!
586      */
587     public String getSelectString()
588             throws DataSetException
589     {
590         buildSelectString();
591 
592         return this.selectString.toString();
593     }
594 
595     /***
596      * Used by getSelectString to build the select string that was used to populate this TableDataSet.
597      *
598      * @throws DataSetException TODO: DOCUMENT ME!
599      */
600     private void buildSelectString()
601             throws DataSetException
602     {
603         if (selectString == null)
604         {
605             selectString = new StringBuffer(256);
606         }
607         else
608         {
609             selectString.setLength(0);
610         }
611 
612         selectString.append("SELECT ");
613         selectString.append(schema().attributes());
614         selectString.append(" FROM ");
615         selectString.append(schema().tableName());
616 
617         if ((this.where != null) && (this.where.length() > 0))
618         {
619             selectString.append(" WHERE " + this.where);
620         }
621 
622         if ((this.order != null) && (this.order.length() > 0))
623         {
624             selectString.append(" ORDER BY " + this.order);
625         }
626 
627         if ((this.other != null) && (this.other.length() > 0))
628         {
629             selectString.append(this.other);
630         }
631     }
632 }