Fork me on GitHub

Extending POEM generated classes

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).

Standard POEM generated classes

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

Extending POEM generated Table classes

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).

Extending POEM generated Persistent classes

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 a
          Persistent
          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(); } }