POEM generates Table and Persistent classes from a Data Structure Definition (DSD) which contains a richer set of attributes than an SQL Data Definition Language (DDL) definition.
The inheritance hierarchy is a little convoluted, but it results in the classes which the
programmer should edit being in a single package, with the main bulk of the generated
files being created in a sub-directory (generated
).
A typical DSD for an object
MyObject
package org.myorg.myproject; table MyObject (displayorder = 2010) (description = "A thing") (category = "User") (seqcached) { Integer id (primary) (description = "The Table Row Object ID") (displaylevel = detail) (displayorder = 10); String name (size = 60) (displayname = "Full name") (description = "The thing's real name") (displayorderpriority = 0) (displaylevel = primary) (searchability = primary) (displayorder = 20) (indexed); ... }
Processing the DSD results in four files being generated:
org.myorg.myproject.MyObject.java
|
org.myorg.myproject.MyObjectTable.java
|
org.myorg.myproject.generated.MyObjectBase.java
|
org.myorg.myproject.generated.MyObjectTableBase.java
|
The class heirarchy for a standard generated table for records of type
MyObject
in package
org.myorg.myproject
would be:
java.lang.Object
|
org.melati.poem.Table
|
org.myorg.myproject.MyprojectTable
|
org.myorg.myproject.generated.MyObjectTableBase
|
org.myorg.myproject.MyObjectTable
|
This structure enables the programmer to override any method inheritted from
org.melati.poem.Table
either on a per table basis or for all tables within the project.
It also enables the POEM metadata tables and the project tables to be treated separately.
For example project tables could have a different unique key (TROID) allocation
algorithm from that used for the metadata tables by overridingtroidFor(Persistent persistent)
.
The DSD supports abstract tables and table extension, where the extended table may be abstract.
An abstract table has its code generated in the same way as a concrete table, but it is not represented in the underlying database.
If you have a group of tables all of which have a field of the same type, (for example creation timestamp, updating user, parent record etc), then these fields can be defined in an abstract table and the target table can extend it. The POEM DSD itself uses this technique:
abstract table ValueInfo { String displayname (size = 60) (displayname = "Display name") (displayorder = 100) (description = "A user-friendly name for the field") (displayorderpriority = 2) (displaylevel = primary); .... } table ColumnInfo extends org.melati.poem.ValueInfo (displayorder = 3020) (displayname = "Column") (description = "Configuration information about a column in the database") (category = "System") (cachelimit = unlimited) (seqcached) { .... } table Setting extends org.melati.poem.ValueInfo (displayorder = 3040) (description = "A configurable Setting for the application, where a Setting can be of any object type") (category = "System") (cachelimit = unlimited) (seqcached) { .... }
Even if your tables do not share fields of common type you can still use this technique, as abstract tables do not have to contain any fields.
For example project tables can be made Treeable by defining an abstract table and extending from it in the DSD:
package org.myorg.myproject; abstract table MyProjectTreeable{ } table MyObject extends MyProjectTreeable (displayorder = 2010) (description = "A thing") (category = "User") (seqcached) { Integer id (primary) (description = "The Table Row Object ID") (displaylevel = detail) (displayorder = 10); String name (size = 60) (displayname = "Full name") (description = "The thing's real name") (displayorderpriority = 0) (displaylevel = primary) (searchability = primary) (displayorder = 20) (indexed); ... }
The resulting class hierarchy for the extended
MyObject
java.lang.Object
|
org.melati.poem.Persistent
|
org.myorg.myproject.generated.MyProjectTreeableBase
|
org.myorg.myproject.generated.MyProjectTreeable
|
org.myorg.myproject.generated.MyObjectBase
|
org.myorg.myproject.MyObject
|
and the corresponding class hierarchy for the extended
MyObjectTable
java.lang.Object
|
org.melati.poem.Table
|
org.myorg.myproject.MyProjectTable
|
org.myorg.myproject.generated.MyProjectTreeableTableBase
|
org.myorg.myproject.generated.MyProjectTreeableTable
|
org.myorg.myproject.generated.MyObjectBaseTable
|
org.myorg.myproject.MyObjectTable
|
Note that the Table class inherits from
org.myorg.myproject.MyProjectTable
but that
there is no equivalent for the
Persistent
itself, as extending from an abstract table
is more fine grained.
Once the processor has generated the sources you can modifyMyProjectTreeable.java
,
to implement an interface for example:
public class MyProjectTreeable extends MyProjectTreeableBase implements Treeable { /** * Constructor * for aPersistent
MyProjectTreeable
object. ** Description: * A treeable record. *
* * See org.melati.poem.prepro.TableDef#generateMainJava */ public MyProjectTreeable() { } // programmer's domain-specific code here /** * {@inheritDoc} * @see org.melati.util.Treeable#getChildren() */ public Treeable[] getChildren() { Enumeration kidsEnum = getDatabase().referencesTo(this); Vector kidsVector = EnumUtils.vectorOf(kidsEnum); Treeable[] kidsArray = new Treeable[kidsVector.size()]; kidsVector.copyInto(kidsArray); return kidsArray; } /** * {@inheritDoc} * @see org.melati.util.Treeable#getName() */ public String getName() { return displayString(); } }