View Javadoc
1   /*
2    * $Source$
3    * $Revision$
4    *
5    * Copyright (C) 2000 William Chesters
6    * 
7    * Part of Melati (http://melati.org), a framework for the rapid
8    * development of clean, maintainable web applications.
9    *
10   * Melati is free software; Permission is granted to copy, distribute
11   * and/or modify this software under the terms either:
12   *
13   * a) the GNU General Public License as published by the Free Software
14   *    Foundation; either version 2 of the License, or (at your option)
15   *    any later version,
16   *
17   *    or
18   *
19   * b) any version of the Melati Software License, as published
20   *    at http://melati.org
21   *
22   * You should have received a copy of the GNU General Public License and
23   * the Melati Software License along with this program;
24   * if not, write to the Free Software Foundation, Inc.,
25   * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA to obtain the
26   * GNU General Public License and visit http://melati.org to obtain the
27   * Melati Software License.
28   *
29   * Feel free to contact the Developers of Melati (http://melati.org),
30   * if you would like to work out a different arrangement than the options
31   * outlined here.  It is our intention to allow Melati to be used by as
32   * wide an audience as possible.
33   *
34   * This program is distributed in the hope that it will be useful,
35   * but WITHOUT ANY WARRANTY; without even the implied warranty of
36   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
37   * GNU General Public License for more details.
38   *
39   * Contact details for copyright holder:
40   *
41   *     William Chesters <williamc At paneris.org>
42   *     http://paneris.org/~williamc
43   *     Obrechtstraat 114, 2517VX Den Haag, The Netherlands
44   */
45  
46  package org.melati.poem;
47  
48  import org.melati.poem.util.Cache;
49  
50  import java.util.Enumeration;
51  import java.util.List;
52  import java.io.PrintStream;
53  import java.sql.ResultSet;
54  import java.sql.SQLException;
55  
56  /**
57   * A table.
58   *
59   * @since 14-Apr-2008
60   */
61  public interface Table<P extends Persistent>  {
62      /**
63       * The database to which the table is attached.
64       * @return the db
65       */
66      Database getDatabase();
67  
68      /**
69       * Initialise the table.
70       */
71      void init();
72      /**
73       * Do stuff immediately after table initialisation.
74       * <p>
75       * This base method clears the column info caches and adds a listener
76       * to the column info table to maintain the caches.
77       * <p>
78       * It may be overridden to perform other actions. For example to
79       * ensure required rows exist in tables that define numeric ID's for
80       * codes.
81       *
82       * @see #notifyColumnInfo(ColumnInfo)
83       * @see #clearColumnInfoCaches()
84       */
85      void postInitialise();
86      
87      /**
88       * Create the (possibly overridden) TableInfo if it has not yet been created.
89       */
90      void createTableInfo();
91      /**
92       * The table's programmatic name.  Identical with its name in the DSD (if the
93       * table was defined there) and in its <TT>tableinfo</TT> entry.
94       * This will normally be the same as the name in the RDBMS itself, however that name
95       * may be translated to avoid DBMS specific name clashes.
96       *
97       * @return the table name, case as defined in the DSD
98       * @see org.melati.poem.dbms.Dbms#melatiName(String)
99       */
100     String getName();
101 
102     /**
103      * @return table name quoted using the DBMS' specific quoting rules.
104      */
105     String quotedName();
106 
107     /**
108      * The human-readable name of the table.  POEM itself doesn't use this, but
109      * it's available to applications and Melati's generic admin system as a
110      * default label for the table and caption for its records.
111       * @return The human-readable name of the table
112       */
113     String getDisplayName();
114 
115     /**
116      * A brief description of the table's function.  POEM itself doesn't use
117      * this, but it's available to applications and Melati's generic admin system
118      * as a default label for the table and caption for its records.
119      * @return the brief description
120      */
121     String getDescription();
122 
123     /**
124      * The category of this table.  POEM itself doesn't use
125      * this, but it's available to applications and Melati's generic admin system
126      * as a default label for the table and caption for its records.
127      *
128      * @return the category
129      */
130     TableCategory getCategory();
131 
132     /**
133      * @return the {@link org.melati.poem.TableInfo} for this table
134      */
135     TableInfo getInfo();
136 
137     /**
138      * The troid (<TT>id</TT>) of the table's entry in the <TT>tableinfo</TT>
139      * table.  It will always have one (except during initialisation, which the
140      * application programmer will never see).
141      *
142      * @return id in TableInfo metadata table
143      */
144     Integer tableInfoID();
145 
146     /**
147      * The table's column with a given name.  If the table is defined in the DSD
148      * under the name <TT><I>foo</I></TT>, there will be an
149      * application-specialised <TT>Table</TT> subclass, called
150      * <TT><I>Foo</I>Table</TT> (and available as <TT>get<I>Foo</I>Table</TT>
151      * from the application-specialised <TT>Database</TT> subclass) which has
152      * extra named methods for accessing the table's predefined <TT>Column</TT>s.
153      *
154      * @param nameP name of column to get
155      * @return column of that name
156      * @throws org.melati.poem.NoSuchColumnPoemException if there is no column with that name
157      */
158     Column<?> getColumn(String nameP) throws NoSuchColumnPoemException;
159 
160     /**
161      * All the table's columns.
162      *
163      * @return an <TT>Enumeration</TT> of <TT>Column</TT>s
164      * @see org.melati.poem.Column
165      */
166     Enumeration<Column<?>> columns();
167 
168     /**
169      * A list of all the table's columns.
170      */
171     List<Column<?>> getColumns(); 
172     
173     /**
174      * @return the number of columns in this table.
175      */
176     int getColumnsCount();
177 
178     /**
179      * @param columnInfoID the Id for the Column table
180      * @return the Column with a TROID equal to columnInfoID
181      */
182     Column<?> columnWithColumnInfoID(int columnInfoID);
183 
184     /**
185      * The table's troid column.  Every table in a POEM database must have a
186      * troid (table row ID, or table-unique non-nullable integer primary key),
187      * often but not necessarily called <TT>id</TT>, so that it can be
188      * conveniently `named'.
189      *
190      * @return the id column
191      * @see #getObject(Integer)
192      */
193     Column<Integer> troidColumn();
194 
195     /**
196      * @return The table's deleted-flag column, if any.
197      */
198     Column<Boolean> deletedColumn();
199 
200     /**
201      * The table's primary display column, the Troid column if not set.
202      * This is the column used to represent records from the table
203      * concisely in reports or whatever.  It is determined
204      * at initialisation time by examining the <TT>Column</TT>s
205      * <TT>getPrimaryDisplay()</TT> flags.
206      *
207      * @return the table's display column, or <TT>null</TT> if it hasn't got one
208      *
209      * see Column#setColumnInfo
210      * @see org.melati.poem.ReferencePoemType#_stringOfCooked
211      * @see org.melati.poem.DisplayLevel#primary
212      */
213     Column<?> displayColumn();
214 
215     /**
216      * @param column the display column to set
217      */
218     void setDisplayColumn(Column<?> column);
219 
220     /**
221      * In a similar manner to the primary display column, each table can have
222      * one primary criterion column.
223      * <p>
224      * The Primary Criterion is the main grouping field of the table,
225      * ie the most important non-unique type field.
226      * <p>
227      * For example the Primary Criterion for a User table might be Nationality.
228      *
229      * @return the search column, if any
230      * @see org.melati.poem.Searchability
231      */
232     Column<?> primaryCriterionColumn();
233 
234     /**
235      * @param column the search column to set
236      */
237     void setSearchColumn(Column<?> column);
238 
239     /**
240      * If the troidColumn has yet to be set then returns an empty string.
241      *
242      * @return comma separated list of the columns to order by
243      */
244     String defaultOrderByClause();
245 
246     /**
247      * Clear caches.
248      */
249     void clearColumnInfoCaches();
250 
251     /**
252      * Clears columnInfo caches, normally a no-op.
253      *
254      * @param infoP the possibly null ColumnInfo meta-data persistent
255      */
256     void notifyColumnInfo(ColumnInfo infoP);
257 
258     /**
259      * Return columns at a display level in display order.
260      *
261      * @param level the {@link org.melati.poem.DisplayLevel} to select
262      * @return an Enumeration of columns at the given level
263      */
264     Enumeration<Column<?>> displayColumns(DisplayLevel level);
265 
266     /**
267      * @param level the {@link org.melati.poem.DisplayLevel} to select
268      * @return the number of columns at a display level.
269      */
270     int displayColumnsCount(DisplayLevel level);
271 
272     /**
273      * The table's columns for detailed display in display order.
274      *
275      * @return an <TT>Enumeration</TT> of <TT>Column</TT>s
276      * @see org.melati.poem.Column
277      * @see #displayColumns(org.melati.poem.DisplayLevel)
278      * @see org.melati.poem.DisplayLevel#detail
279      */
280     Enumeration<Column<?>> getDetailDisplayColumns();
281 
282     /**
283      * @return the number of columns at display level <tt>Detail</tt>
284      */
285     int getDetailDisplayColumnsCount();
286 
287     /**
288      * The table's columns designated for display in a record, in display order.
289      *
290      * @return an <TT>Enumeration</TT> of <TT>Column</TT>s
291      * @see org.melati.poem.Column
292      * @see #displayColumns(org.melati.poem.DisplayLevel)
293      * @see org.melati.poem.DisplayLevel#record
294      */
295     Enumeration<Column<?>> getRecordDisplayColumns();
296 
297     /**
298      * @return the number of columns at display level <tt>Record</tt>
299      */
300     int getRecordDisplayColumnsCount();
301 
302     /**
303      * The table's columns designated for display in a record summary, in display
304      * order.
305      *
306      * @return an <TT>Enumeration</TT> of <TT>Column</TT>s
307      * @see org.melati.poem.Column
308      * @see #displayColumns(org.melati.poem.DisplayLevel)
309      * @see org.melati.poem.DisplayLevel#summary
310      */
311     Enumeration<Column<?>> getSummaryDisplayColumns();
312 
313     /**
314      * @return the number of columns at display level <tt>Summary</tt>
315      */
316     int getSummaryDisplayColumnsCount();
317 
318     /**
319      * The table's columns designated for use as search criteria, in display
320      * order.
321      *
322      * @return an <TT>Enumeration</TT> of <TT>Column</TT>s
323      * @see org.melati.poem.Column
324      */
325     Enumeration<Column<?>> getSearchCriterionColumns();
326 
327     /**
328      * @return the number of columns which are searchable
329      */
330     int getSearchCriterionColumnsCount();
331 
332     /**
333      * Use this for DDL statements, ie those which alter the structure of the db.
334      * Postgresql in particular does not like DDL statements being executed within a transaction.
335      *
336      * @param sql the SQL DDL statement to execute
337      * @throws org.melati.poem.StructuralModificationFailedPoemException
338      */
339     void dbModifyStructure(String sql)
340         throws StructuralModificationFailedPoemException;
341 
342     /**
343      * Constraints are not used in POEM, but you might want to use them if
344      * exporting the db or using schema visualisation tools.
345      */
346     void dbAddConstraints();
347 
348     /**
349      * When deleting a table and used in tests.
350      */
351     void invalidateTransactionStuffs();
352 
353     /**
354      * @param transaction possibly null if working with the committed transaction
355      * @param persistent the Persistent to load
356      */
357     void load(PoemTransaction transaction, Persistent persistent);
358 
359     /**
360      * The Transaction cannot be null, as this is trapped in
361      * #deleteLock(SessionToken).
362      * @param troid id of row to delete
363      * @param transaction a non-null transaction
364      */
365     void delete(Integer troid, PoemTransaction transaction);
366 
367     /**
368      * @param transaction our PoemTransaction
369      * @param p the Persistent to write
370      */
371     void writeDown(PoemTransaction transaction, Persistent p);
372 
373     /**
374      * Invalidate table cache.
375      *
376      * NOTE Invalidated cache elements are reloaded when next read
377      */
378     void uncache();
379 
380     /**
381      * @param maxSize new maximum size
382      */
383     void trimCache(int maxSize);
384 
385     /**
386      * @return the Cache Info object
387      */
388     Cache.Info getCacheInfo();
389 
390     /**
391      * Add a {@link org.melati.poem.TableListener} to this Table.
392      */
393     void addListener(TableListener listener);
394 
395     /**
396      * Notify the table that one if its records is about to be changed in a
397      * transaction.  You can (with care) use this to support cacheing of
398      * frequently-used facts about the table's records.
399      *
400      * @param transaction the transaction in which the change will be made
401      * @param persistent  the record to be changed
402      */
403     void notifyTouched(PoemTransaction transaction, Persistent persistent);
404 
405     /**
406      * @return the Transaction serial
407      */
408     long serial(PoemTransaction transaction);
409 
410     /**
411      * Lock this record.
412      */
413     void readLock();
414 
415     /**
416      * The object from the table with a given troid.
417      *
418      * @param troid       Every record (object) in a POEM database must have a
419      *                    troid (table row ID, or table-unique non-nullable
420      *                    integer primary key), often but not necessarily called
421      *                    <TT>id</TT>, so that it can be conveniently `named' for
422      *                    retrieval by this method.
423      *
424      * @return A <TT>Persistent</TT> of the record with the given troid;
425      *         or, if the table was defined in the DSD under the name
426      *         <TT><I>foo</I></TT>, an application-specialised subclass
427      *         <TT><I>Foo</I></TT> of <TT>Persistent</TT>.  In that case, there
428      *         will also be an application-specialised <TT>Table</TT> subclass,
429      *         called <TT><I>Foo</I>Table</TT> (and available as
430      *         <TT>get<I>Foo</I>Table</TT> from the application-specialised
431      *         <TT>Database</TT> subclass), which has a matching method
432      *         <TT>get<I>Foo</I>Object</TT> for obtaining the specialised object
433      *         under its own type.  Note that no access checks are done at this
434      *         stage: you may not be able to do anything with the object handle
435      *         returned from this method without provoking a
436      *         <TT>PoemAccessException</TT>.
437      *
438      * @exception org.melati.poem.NoSuchRowPoemException
439      *                if there is no row in the table with the given troid
440      *
441      * @see org.melati.poem.Persistent#getTroid()
442      */
443     P getObject(Integer troid) throws NoSuchRowPoemException;
444 
445     /**
446      * The object from the table with a given troid.  See previous.
447      *
448      * @param troid the table row id
449      * @return the Persistent
450      * @throws org.melati.poem.NoSuchRowPoemException if not found
451      * @see #getObject(Integer)
452      */
453     Persistent getObject(int troid) throws NoSuchRowPoemException;
454 
455     /**
456      * The from clause has been added as an argument because it is
457      * inextricably linked to the when clause, but the default is
458      * {@link #quotedName()}.
459      *
460      * It is the programmer's responsibility to ensure that the where clause
461      * is suitable for the target DBMS.
462      *
463      * @param fromClause Comma separated list of table names or null for default.
464      * @param whereClause SQL fragment
465      * @param orderByClause Comma separated list
466      * @param includeDeleted Flag as to whether to include soft deleted records
467      * @param excludeUnselectable Whether to append unselectable exclusion SQL
468      * TODO Should work within some kind of limit
469      * @return an SQL SELECT statement put together from the arguments and
470      * default order by clause.
471      */
472     String selectionSQL(String fromClause, String whereClause,
473                                String orderByClause, boolean includeDeleted,
474                                boolean excludeUnselectable);
475 
476     /**
477      * It is the programmer's responsibility to ensure that the where clause
478      * is suitable for the target DBMS.
479      *
480      * @return an {@link java.util.Enumeration} of Troids satisfying the criteria.
481      */
482     Enumeration<Integer> troidSelection(String whereClause, String orderByClause,
483                                       boolean includeDeleted,
484                                       PoemTransaction transaction);
485 
486     /**
487      *
488      * @see #troidSelection(String, String, boolean, org.melati.poem.PoemTransaction)
489      * @param criteria Represents selection criteria possibly on joined tables
490      * @param transaction A transaction or null for
491      *                    {@link org.melati.poem.PoemThread#transaction()}
492      * @return a selection of troids given arguments specifying a query
493      */
494     Enumeration<Integer> troidSelection(Persistent criteria, String orderByClause,
495                                       boolean includeDeleted,
496                                       boolean excludeUnselectable,
497                                       PoemTransaction transaction);
498 
499     /**
500      * @param flag whether to remember or forget
501      */
502     void rememberAllTroids(boolean flag);
503 
504     /**
505      * @param limit the limit to set
506      */
507     void setCacheLimit(Integer limit);
508 
509     /**
510      * A <TT>SELECT</TT>ion of troids of objects from the table meeting given
511      * criteria.
512      *
513      * It is the programmer's responsibility to ensure that the where clause
514      * is suitable for the target DBMS.
515      *
516      * If the orderByClause is null, then the default order by clause is applied.
517      * If the orderByClause is an empty string, ie "", then no ordering is
518      * applied.
519      *
520      * @param whereClause an SQL snippet
521      * @param orderByClause an SQL snippet
522      * @param includeDeleted whether to include deleted records, if any
523      *
524      * @return an <TT>Enumeration</TT> of <TT>Integer</TT>s, which can be mapped
525      *         onto <TT>Persistent</TT> objects using <TT>getObject</TT>;
526      *         or you can just use <TT>selection</TT>
527      *
528      * @see #getObject(Integer)
529      * @see #selection(String, String, boolean)
530      */
531     Enumeration<Integer> troidSelection(String whereClause, String orderByClause,
532                                       boolean includeDeleted)
533         throws SQLPoemException;
534 
535     /**
536      * All the objects in the table.
537      *
538      * @return An <TT>Enumeration</TT> of <TT>Persistent</TT>s, or, if the table
539      *         was defined in the DSD under the name <TT><I>foo</I></TT>, of
540      *         application-specialised subclasses <TT><I>Foo</I></TT>.  Note
541      *         that no access checks are done at this stage: you may not be able
542      *         to do anything with some of the object handles in the enumeration
543      *         without provoking a <TT>PoemAccessException</TT>.  If the table
544      *         has a <TT>deleted</TT> column, the objects flagged as deleted will
545      *         be passed over.
546      * @see Selectable#selection()
547      */
548     Enumeration<P> selection() throws SQLPoemException;
549 
550     /**
551      * A <TT>SELECT</TT>ion of objects from the table meeting given criteria.
552      * This is one way to run a search against the database and return the
553      * results as a series of typed POEM objects.
554      *
555      * It is the programmer's responsibility to ensure that the where clause
556      * is suitable for the target DBMS.
557      *
558      * @param whereClause         SQL <TT>SELECT</TT>ion criteria for the search:
559      *                            the part that should appear after the
560      *                            <TT>WHERE</TT> keyword
561      *
562      * @return An <TT>Enumeration</TT> of <TT>Persistent</TT>s, or, if the table
563      *         was defined in the DSD under the name <TT><I>foo</I></TT>, of
564      *         application-specialised subclasses <TT><I>Foo</I></TT>.  Note
565      *         that no access checks are done at this stage: you may not be able
566      *         to do anything with some of the object handles in the enumeration
567      *         without provoking a <TT>PoemAccessException</TT>.  If the table
568      *         has a <TT>deleted</TT> column, the objects flagged as deleted will
569      *         be passed over.
570      *
571      * @see org.melati.poem.Column#selectionWhereEq(Object)
572      */
573     Enumeration<P> selection(String whereClause)
574         throws SQLPoemException;
575 
576     /**
577      * Get an object satisfying the where clause.
578      * It is the programmer's responsibility to use this in a
579      * context where only one result will be found, if more than one
580      * actually exist only the first will be returned.
581      *
582      * It is the programmer's responsibility to ensure that the where clause
583      * is suitable for the target DBMS.
584      *
585      * @param whereClause         SQL <TT>SELECT</TT>ion criteria for the search:
586      *                            the part that should appear after the
587      *                            <TT>WHERE</TT> keyword
588      * @return the first item satisfying criteria
589      */
590     Persistent firstSelection(String whereClause);
591 
592     /**
593      * A <TT>SELECT</TT>ion of objects from the table meeting given criteria,
594      * possibly including those flagged as deleted.
595      *
596      * If the orderByClause is null, then the default order by clause is applied.
597      * If the orderByClause is an empty string, ie "", then no ordering is
598      * applied.
599      *
600      * It is the programmer's responsibility to ensure that the where clause
601      * is suitable for the target DBMS.
602      *
603      * @param includeDeleted      whether to return objects flagged as deleted
604      *                            (ignored if the table doesn't have a
605      *                            <TT>deleted</TT> column)
606      * @return a ResultSet as an Enumeration
607      * @see #selection(String)
608      */
609     Enumeration<P> selection(String whereClause, String orderByClause,
610                                   boolean includeDeleted)
611         throws SQLPoemException;
612 
613     /**
614      * Return a selection of rows given an exemplar.
615      *
616      * @param criteria Represents selection criteria possibly on joined tables
617      * @return an enumeration of like objects
618      * @see #selection(String, String, boolean)
619      */
620     Enumeration<P> selection(Persistent criteria)
621         throws SQLPoemException;
622 
623     /**
624      * Return a selection of rows given arguments specifying a query.
625      *
626      * @see #selection(String, String, boolean)
627      * @param criteria Represents selection criteria possibly on joined tables
628      * @param orderByClause Comma separated list
629      * @return an enumeration of like objects with the specified ordering
630      */
631     Enumeration<P> selection(Persistent criteria, String orderByClause)
632         throws SQLPoemException;
633 
634     /**
635      * Return a selection of rows given arguments specifying a query.
636      *
637      * @see #selection(String, String, boolean)
638      * @param criteria Represents selection criteria possibly on joined tables
639      * @param orderByClause Comma separated list
640      * @param excludeUnselectable Whether to append unselectable exclusion SQL
641      * @return an enumeration of like Persistents
642      */
643     Enumeration<P> selection(Persistent criteria, String orderByClause,
644                                   boolean includeDeleted, boolean excludeUnselectable)
645         throws SQLPoemException;
646 
647 
648     /**
649      * @param whereClause the SQL fragment to count the results of
650      * @return the SQL string for the current SQL dialect
651      */
652     String countSQL(String whereClause);
653 
654     /**
655      * Return an SQL statement to count rows put together from the arguments.
656      *
657      * It is the programmer's responsibility to ensure that the where clause
658      * is suitable for the target DBMS.
659      *
660      * @param fromClause Comma separated list of table names
661      * @return the SQL query
662      */
663     String countSQL(String fromClause, String whereClause,
664                            boolean includeDeleted, boolean excludeUnselectable);
665 
666     /**
667      * It is the programmer's responsibility to ensure that the where clause
668      * is suitable for the target DBMS.
669      *
670      * @return the number records satisfying criteria.
671      */
672     int count(String whereClause,
673                      boolean includeDeleted, boolean excludeUnselectable)
674         throws SQLPoemException;
675 
676     /**
677      * It is the programmer's responsibility to ensure that the where clause
678      * is suitable for the target DBMS.
679      *
680      * @return the number records satisfying criteria.
681      */
682     int count(String whereClause, boolean includeDeleted)
683         throws SQLPoemException;
684 
685     /**
686      * It is the programmer's responsibility to ensure that the where clause
687      * is suitable for the target DBMS.
688      *
689      * @return the number of records satisfying criteria.
690      */
691     int count(String whereClause)
692         throws SQLPoemException;
693 
694     /**
695      * @return the number of records in this table.
696      */
697     int count()
698         throws SQLPoemException;
699 
700     /**
701      * It is the programmer's responsibility to ensure that the where clause
702      * is suitable for the target DBMS.
703      *
704      * @param whereClause the SQL criteria
705      * @return whether any  records satisfy criteria.
706      */
707     boolean exists(String whereClause) throws SQLPoemException;
708 
709     /**
710      * @param persistent a {@link org.melati.poem.Persistent} with some fields filled in
711      * @return whether any  records exist with the same fields filled
712      */
713     boolean exists(Persistent persistent);
714 
715     /**
716      * Append an SQL logical expression to the given buffer to match rows
717      * according to criteria represented by the given object.
718      * <p>
719      * This default selects rows for which the non-null fields in the
720      * given object match, but subtypes may add other criteria.
721      * <p>
722      * The column names are now qualified with the table name so that
723      * subtypes can append elements of a join but there is no filtering
724      * by canselect columns.
725      *
726      * TODO Add mechanism for searching for Nulls (that would be query
727      * constructs as per SQL parse tree, but efferent not afferent)
728      *
729      * @see #notifyColumnInfo(org.melati.poem.ColumnInfo)
730      * @see #clearColumnInfoCaches()
731      */
732     void appendWhereClause(StringBuffer clause, Persistent persistent);
733 
734     /**
735      * Return an SQL WHERE clause to select rows that match the non-null
736      * fields of the given object.
737      * <p>
738      * This does not filter out any rows with a capability the user
739      * does not have in a canselect column, nor did it ever filter
740      * out rows deleted according to a "deleted" column.
741      * But the caller usually gets a second chance to do both.
742      * @return an SQL fragment
743      */
744     String whereClause(Persistent criteria);
745 
746     /**
747      * Return an SQL WHERE clause to select rows using the given object
748      * as a selection criteria and optionally deleted rows or those
749      * included rows the user is not capable of selecting.
750      * <p>
751      * This is currently implemented in terms of
752      * {@link org.melati.poem.Table#appendWhereClause(StringBuffer, org.melati.poem.Persistent)}.
753      * @return an SQL fragment
754      */
755     String whereClause(Persistent criteria,
756                               boolean includeDeleted, boolean excludeUnselectable);
757 
758     /**
759      * @return an SQL fragment
760      * @see #cnfWhereClause(java.util.Enumeration, boolean, boolean)
761      * @see #whereClause(org.melati.poem.Persistent)
762      */
763     String cnfWhereClause(Enumeration<P> persistents);
764 
765     /**
766      * Return a Conjunctive Normal Form (CNF) where clause.
767      * See http://en.wikipedia.org/wiki/Conjunctive_normal_form.
768      *
769      * @return an SQL fragment
770      */
771     String cnfWhereClause(Enumeration<P> persistents,
772                                  boolean includeDeleted, boolean excludeUnselectable);
773 
774     /**
775      * All the objects in the table which refer to a given object.  If none of
776      * the table's columns are reference columns, the <TT>Enumeration</TT>
777      * returned will obviously be empty.
778      * <p>
779      * It is not guaranteed to be quick to execute!
780      *
781      * @return an <TT>Enumeration</TT> of <TT>Persistent</TT>s
782      */
783 
784     Enumeration<P> referencesTo(Persistent object);
785 
786     /**
787      * All the columns in the table which refer to the given table.
788      *
789      * @param table the table to count the references within
790      * @return an Enumeration of Columns referring to the specified Table
791      */
792     Enumeration<Column<?>> referencesTo(Table<?> table);
793 
794     /**
795      * @return the current highest troid
796      */
797     int getMostRecentTroid();
798 
799     /**
800      * @param persistent unused parameter, but might be needed in another troid schema
801      * @return the next Troid
802      */
803     Integer troidFor(Persistent persistent);
804 
805     /**
806      * Write a new row containing the given object.
807      * <p>
808      * The given object will be assigned the next troid and its internal
809      * state will also be modified.
810      *
811      * @exception org.melati.poem.InitialisationPoemException The object failed validation
812      *   (currently one of its field values failed).
813      */
814     void create(Persistent p)
815          throws AccessPoemException, ValidationPoemException,
816             InitialisationPoemException;
817 
818     /**
819      * Create a new object (record) in the table.
820      *
821      * @param initialiser         A piece of code for setting the new object's
822      *                            initial values.  You'll probably want to define
823      *                            it as an anonymous class.
824      *
825      * @return A <TT>Persistent</TT> representing the new object, or, if the
826      *         table was defined in the DSD under the name <TT><I>foo</I></TT>,
827      *         an application-specialised subclass <TT><I>Foo</I></TT> of
828      *         <TT>Persistent</TT>.
829      *
830      * @exception org.melati.poem.AccessPoemException
831      *                if <TT>initialiser</TT> provokes one during its work (which
832      *                is unlikely, since POEM's standard checks are disabled
833      *                while it runs)
834      * @exception org.melati.poem.ValidationPoemException
835      *                if <TT>initialiser</TT> provokes one during its work
836      * @exception org.melati.poem.InitialisationPoemException
837      *                if the object is left by <TT>initialiser</TT> in a state in
838      *                which not all of its fields have legal values, or in which
839      *                the calling thread would not be allowed write access to the
840      *                object under its <TT>AccessToken</TT>---<I>i.e.</I> you
841      *                can't create objects you wouldn't be allowed to write to.
842      *
843      * @see org.melati.poem.Initialiser#init(Persistent)
844      * @see org.melati.poem.PoemThread#accessToken()
845      * @see #getCanCreate()
846      */
847     Persistent create(Initialiser initialiser)
848         throws AccessPoemException, ValidationPoemException,
849                InitialisationPoemException;
850 
851     /**
852      * @return A freshly minted floating <TT>Persistent</TT> object for this table,
853      * ie one without a troid set
854      */
855     Persistent newPersistent();
856 
857     /**
858      * It is the programmer's responsibility to ensure that the where clause
859      * is suitable for the target DBMS.
860      *
861      * @param whereClause the criteria
862      */
863     void delete_unsafe(String whereClause);
864 
865     /**
866      * The number of `extra' (non-DSD-defined) columns in the table.
867      */
868     int extrasCount();
869 
870     /**
871      * The capability required for reading records from the table, unless
872      * overridden in the record itself.  This simply comes from the table's
873      * record in the <TT>tableinfo</TT> table.
874      *
875      * @return the capability needed to read this table
876      */
877     Capability getDefaultCanRead();
878 
879     /**
880      * The capability required for updating records in the table, unless
881      * overridden in the record itself.  This simply comes from the table's
882      * record in the <TT>tableinfo</TT> table.
883      *
884      * @return the default  {@link org.melati.poem.Capability} required to write  a
885      *         {@link org.melati.poem.Persistent}, if any
886      */
887     Capability getDefaultCanWrite();
888 
889     /**
890      * The capability required for deleting records in the table, unless
891      * overridden in the record itself.  This simply comes from the table's
892      * record in the <TT>tableinfo</TT> table.
893      * @return the default  {@link org.melati.poem.Capability} required to delete a
894      *         {@link org.melati.poem.Persistent}, if any
895      */
896     Capability getDefaultCanDelete();
897 
898     /**
899      * The capability required for creating records in the table.  This simply
900      * comes from the table's record in the <TT>tableinfo</TT> table.
901      *
902      * @return the Capability required to write to this table
903      * @see #create(Initialiser)
904      */
905     Capability getCanCreate();
906 
907     /**
908      * @return the canReadColumn or the canSelectColumn or null
909      */
910     Column<Capability> canReadColumn();
911 
912     /**
913      * @return the canSelectColumn or null
914      */
915     Column<Capability> canSelectColumn();
916 
917     /**
918      * @return the canWriteColumn or null
919      */
920     Column<Capability> canWriteColumn();
921 
922     /**
923      * @return the canDeleteColumn or null
924      */
925     Column<Capability> canDeleteColumn();
926 
927     /**
928      * Add a {@link org.melati.poem.Column} to the database and the {@link org.melati.poem.TableInfo} table.
929      *
930      * @param infoP the meta data about the {@link org.melati.poem.Column}
931      * @return the newly added column
932      */
933     Column<?> addColumnAndCommit(ColumnInfo infoP) throws PoemException;
934 
935     /**
936      * @param columnInfo metadata about the column to delete, which is itself deleted
937      */
938     void deleteColumnAndCommit(ColumnInfo columnInfo) throws PoemException;
939 
940     /**
941      * A concise string to stand in for the table.  The table's name and a
942      * description of where it was defined (the DSD, the metadata tables or the
943      * JDBC metadata).
944      * {@inheritDoc}
945      * @see Object#toString()
946      */
947     String toString();
948 
949     /**
950      * Print some diagnostic information about the contents and consistency of
951      * POEM's cache for this table to stderr.
952      */
953     void dumpCacheAnalysis();
954 
955     /**
956      * Print information about the structure of the table to stdout.
957      */
958     void dump();
959 
960     /**
961      * Print information to PrintStream.
962      *
963      * @param ps PrintStream to dump to
964      */
965     void dump(PrintStream ps);
966 
967     /**
968      * A mechanism for caching a selection of records.
969      *
970      * It is the programmer's responsibility to ensure that the where clause
971      * is suitable for the target DBMS.
972      *
973      * @param whereClause raw SQL selection clause appropriate for this DBMS
974      * @param orderByClause which field to order by or null
975      * @return the results
976      */
977     CachedSelection<P> cachedSelection(String whereClause,
978                                              String orderByClause);
979 
980     /**
981      * A mechanism for caching a record count.
982      *
983      * It is the programmer's responsibility to ensure that the where clause
984      * is suitable for the target DBMS.
985      *
986      * @param whereClause raw SQL selection clause appropriate for this DBMS
987      * @param includeDeleted whether to include soft deleted records
988      * @return a cached count
989      */
990     CachedCount cachedCount(String whereClause, boolean includeDeleted);
991 
992     /**
993      * A mechanism for caching a record count.
994      *
995      * It is the programmer's responsibility to ensure that the where clause
996      * is suitable for the target DBMS.
997      *
998      * @param whereClause raw SQL selection clause appropriate for this DBMS
999      * @param includeDeleted whether to include soft deleted records
1000      * @param excludeUnselectable whether to exclude columns which cannot be selected
1001      * @return a cached count
1002      */
1003     CachedCount cachedCount(String whereClause, boolean includeDeleted,
1004                                    boolean excludeUnselectable);
1005 
1006     /**
1007      * A mechanism for caching a record count.
1008      *
1009      * @param criteria a {@link org.melati.poem.Persistent} with selection fields filled
1010      * @param includeDeleted whether to include soft deleted records
1011      * @param excludeUnselectable whether to exclude columns which cannot be selected
1012      * @return a cached count
1013      */
1014     CachedCount cachedCount(Persistent criteria, boolean includeDeleted,
1015                                    boolean excludeUnselectable);
1016 
1017     /**
1018      * @param criteria a Persistent to extract where clause from
1019      * @return a CachedCount of records matching Criteria
1020      */
1021     CachedCount cachedCount(Persistent criteria);
1022 
1023     /**
1024      * A mechanism for caching a record count.
1025      *
1026      * It is the programmer's responsibility to ensure that the where clause
1027      * is suitable for the target DBMS.
1028      *
1029      * @param whereClause raw SQL selection clause appropriate for this DBMS
1030      * @return a cached count
1031      */
1032     CachedCount cachedCount(String whereClause);
1033 
1034     /**
1035      * @return a cached count of all records in the table, 
1036      * obeying includedDeleted and other exclusions
1037      */
1038     CachedCount cachedCount();
1039 
1040     /**
1041      * A mechanism for caching an existance.
1042      *
1043      * It is the programmer's responsibility to ensure that the where clause
1044      * is suitable for the target DBMS.
1045      *
1046      * NOTE It is possible for the count to be written simultaneously,
1047      * but the cache will end up with the same result.
1048      *
1049      * @param whereClause raw SQL selection clause appropriate for this DBMS
1050      * @return a cached exists
1051      */
1052     CachedExists cachedExists(String whereClause);
1053 
1054     /**
1055      * A mechanism for caching a record count.
1056      *
1057      * It is the programmer's responsibility to ensure that the where clause
1058      * is suitable for the target DBMS.
1059      *
1060      * @param whereClause raw SQL selection clause appropriate for this DBMS
1061      * @param orderByClause raw SQL order clause appropriate for this DBMS
1062      * @param nullable whether the ReferencePoemType is nullable
1063      * @return a {@link org.melati.poem.RestrictedReferencePoemType}
1064      */
1065     RestrictedReferencePoemType<?> cachedSelectionType(String whereClause,
1066                                      String orderByClause, boolean nullable);
1067 
1068     /**
1069      * Make up a <TT>Field</TT> object whose possible values are a selected
1070      * subset of the records in the table.  You can make a "dropdown" offering a
1071      * choice of your green customers by putting this in your handler
1072      *
1073      * <BLOCKQUOTE><PRE>
1074      * context.put("greens",
1075      *             melati.getDatabase().getCustomerTable().cachedSelectionField(
1076      *                 "colour = 'green'", null, true, null, "greens"));
1077      * </PRE></BLOCKQUOTE>
1078      *
1079      * and this in your template
1080      *
1081      * <BLOCKQUOTE><PRE>
1082      *   Select a customer: $ml.input($greens)
1083      * </PRE></BLOCKQUOTE>
1084      *
1085      * The list of member records is implicitly cached---permanently, and however
1086      * big it turns out to be.  So don't go mad with this.  It is recomputed on
1087      * demand if the contents of the table are changed.  The <TT>whereClause</TT>
1088      * and <TT>orderByClause</TT> you pass in are checked to see if you have
1089      * asked for the same list before, so however many times you call this
1090      * method, you should only trigger actual <TT>SELECT</TT>s when the table
1091      * contents have changed.  The list is also transaction-safe, in that it will
1092      * always reflect the state of affairs within your transaction even if you
1093      * haven't done a commit.
1094      *
1095      * It is the programmer's responsibility to ensure that the where clause
1096      * is suitable for the target DBMS.
1097      *
1098      * @param whereClause         an SQL expression (the bit after the
1099      *                            <TT>SELECT</TT> ... <TT>WHERE</TT>) for picking
1100      *                            out the records you want
1101      *
1102      * @param orderByClause       a comma-separated list of column names which
1103      *                            determine the order in which the records are
1104      *                            presented; if this is <TT>null</TT>, the
1105      *                            <TT>displayorderpriority</TT> attributes of the
1106      *                            table's columns determine the order
1107      *
1108      * @param nullable            whether to allow a blank <TT>NULL</TT> option
1109      *                            as the first possibility
1110      *
1111      * @param selectedTroid       the troid of the record to which the
1112      *                            <TT>SELECT</TT> field should initially be set
1113      *
1114      * @param nameP               the HTML name attribute of the field,
1115      *                            <I>i.e.</I>
1116      *                            <TT>&lt;SELECT NAME=<I>name</I>&gt;</TT>
1117      * @return a Field object
1118      */
1119     Field<?> cachedSelectionField(
1120         String whereClause, String orderByClause, boolean nullable,
1121         Integer selectedTroid, String nameP);
1122 
1123     /**
1124      * Don't call this in your application code.
1125      * Columns should be defined either in the DSD (in which
1126      * case the boilerplate code generated by the preprocessor will call this
1127      * method) or directly in the RDBMS (in which case the initialisation code
1128      * will).
1129      */
1130     void defineColumn(Column<?> column)
1131         throws DuplicateColumnNamePoemException,
1132                DuplicateTroidColumnPoemException,
1133                DuplicateDeletedColumnPoemException;
1134 
1135     /**
1136      * @return incremented extra columns index
1137      */
1138     int getNextExtrasIndex();
1139 
1140     /**
1141      * @param tableInfo the TableInfo to set
1142      */
1143     void setTableInfo(TableInfo tableInfo);
1144 
1145     /**
1146      * @return the {@link org.melati.poem.TableInfo} for this table.
1147      */
1148     TableInfo getTableInfo();
1149 
1150     /**
1151      * @return a DBMS table type eg TEXT 
1152      */
1153     String getDbmsTableType();
1154     
1155 
1156     /**
1157      * Match columnInfo with this Table's columns.
1158      * Conversely, create a ColumnInfo for any columns which don't have one.
1159      */
1160     void unifyWithColumnInfo() throws PoemException;
1161 
1162     /** Unify SQL REMARKS with table.description.
1163      * 
1164      * @param tableDescriptions a JDBC {@link java.sql.ResultSet} with cursor at current row
1165      */
1166     void unifyWithMetadata(ResultSet tableDescriptions) throws SQLException;
1167     
1168     /**
1169      * Unify the JDBC description of this tables columns with the
1170      * meta data held in the {@link org.melati.poem.TableInfo}
1171      *
1172      * @param colDescs a JDBC {@link java.sql.ResultSet} describing the columns with cursor at current row
1173      * @param primaryKey name of primary key column
1174      */
1175     void unifyWithDB(ResultSet colDescs, String primaryKey)
1176         throws PoemException;
1177 
1178     String defaultDisplayName();
1179 
1180     String defaultDescription();
1181 
1182     int defaultDisplayOrder();
1183 
1184     Integer defaultCacheLimit();
1185 
1186     boolean defaultRememberAllTroids();
1187 
1188     String defaultCategory();
1189 
1190 
1191 }