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><SELECT NAME=<I>name</I>></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 }