View Javadoc

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