Emeraldjb Patterns |
This section of documentation provides information on patterns included with the Emeraldjb generator.
Introduction
Emeraldjb Patterns are not Gang of Four patterns, nor are they MVC patterns. These are common aspects that the Emeraldjb team have come accross again and again in projects. They are cross-cutting patterns that exist in the use of data in enterprise systems, and which may be important to you now, or possibly in the future. They may also be simpler patterns, which provide a quick way to specify detail in the generated scripts and code.
The pattern code exists seperately from the Emeraldjb core and new patterns can be created simply, using aspect like point-cuts within the code generation engine. The code generation engine injects the current generation context into each pattern and provides access to the rich entity model at each point.
For now the Emeraldjb team will create new patterns as we want to enrich the offering. In future an Emeraldjb pattern API will be published; the pattern code has been designed behind an abstract factory, with strategies existing for each named pattern.
Patterns
Mysql: Table Type Pattern
| Why: | Older versions of MySQL require a table type specified for MySQL InnoDB table types. This allows the type to be specified. |
| Behaviour: | This will add the VALUE to the end of the create table syntax in the ddl. |
| Usage: | <PATTERN NAME="ddl.mysql.table_type" VALUE="InnoDB" /> |
Oracle Extras
| Why: | Oracles use of schemas, synonyms, sequences and so on dictates the need for additional information. This is done through a set of patterns which will result in a set of DDL for creation, drop, permission etc. |
| Behaviour: | If these values are not set then the Oracle DDL generator will use defaults. |
| Usage: |
<PATTERN NAME="ddl.oracle.owner" VALUE="the_schema_name"/> <PATTERN NAME="ddl.oracle.role.admin" VALUE="admin_role"/> <PATTERN NAME="ddl.oracle.role.read" VALUE="read_role"/> <PATTERN NAME="ddl.oracle.role.update" VALUE="update_role"/> <PATTERN NAME="ddl.oracle.role.dev" VALUE="developer_role"/> |
String Auto Fix pattern
| Why: |
This pattern allows the java classes to replace null with "" when marshalling to or from the database. A very simple mechanism which avoid potential null ptr exceptions in your code. The second part of the pattern allows the java code to auto truncate strings before insert. It may be that your project has certain description columns which need not be complete, and auto truncation may be preferable to a database exception, or client side validation. This truncation will also create constants for the string columns widths, allowing you to use the constants in any client side validation that you add. |
| Behaviour: |
Null fixing: The values objects convert nulls to "". Width fixing: A constant is added to the values object specifying the width. If the value is too wide for the column then the values objects will strip it down to length-3 and append "...". |
| Usage: | <PATTERN NAME="value.string_auto_fix" VALUE="null_only" /> |
Sequence Function Pattern
| Why: |
There are many cases where you do not want to use the in-built sequence mechanisms of the database. Your function must be static and must take a single string parameter. It must return an int value, and will possibly throw a SQL exception. Take a look at the implementation shipped with the generator to see. A good example with mySql could be a dual primary key, one of which is to be a sequenced number. |
| Behaviour: |
The code generator will split this string into an import statement and also into a function call within the insert function for the DAO implementation.
#import com.emeraldjb.runtime.patternSeqNum.SequenceGetter;
public theTableNameValues insert(theTableNameValues values,
Connection conn) throws SQLException
{
values.getTheColName(
SequenceGetter.getSequenceValue(table_name));
...
|
| Usage: |
<PATTERN NAME="ddl.use_sequence_func" VALUE="com.emeraldjb.runtime. patternSeqNum.SequenceGetter.getSequenceValue"/> <ENTITY> <NAME>PKEY_SEQS<NAME> <MEMBER TYPE="String" COL_LEN=254 >seq_name<MEMBER> <MEMBER TYPE="int" NULL_ALLOWED="FALSE" ><next_val<MEMBER> <PRIMARY_KEY COLS="seq_name">sequence_pk<PRIMARY_KEY> <ENTITY> |
Optimistic Locking Pattern
| Why: | Detecting that some other person or system has updated data between the point you read it and are writing it back with updates is a well known problem. One solution to detect such 'dirty data' is optimistic locking. |
| Behaviour: | A column is added to any table with this pattern - the column name is given by the pattern. This integer column is incremented automatically on updates and forms part of the where clause as well. A simple mechanism which detects 'dirty data'. |
| Usage: | <PATTERN NAME="ddl.locking.optimistic" VALUE="version"/> |
Audit Columns Pattern
| Why: | You will often want to add information about when a record was created and who by, this patterm means the audit columns are added to your schema automatically. |
| Behaviour: |
Four columns are added: dbcreated_at dbupdated_date dbcreated_by dbupdated_by The date columns are auto populated by the insert and update code, whereas the created_by and updated_by must be set by your application code. The dates will only be set at point of execution if they are currently null. If you have columns of the same name within an entity then the pattern may generate broken code. To disable the pattern for an entity and leave it live for the rest of the project, specify the pattern again within the entity, with a value of 0 (anything <1 will do). |
| Usage: |
<PATTERN NAME="ddl.audit" VALUE="25" COLUMN_TYPE="Date"/> The value specifies the length of the created_by and updated_by columns. The COLUMN_TYPE defaults to TIMESTAMP, but older oracle implementations will need Date types. i.e. For old oracle installs you will need the COLUMN_TYPE attribute. For all other situations you should not have the COLUMN_TYPE attribute. |
Archive Tables
| Why: |
Certain data in your system MUST be archived, with dates, who changed it, and this data can be mined to determine values at fixed times. This pattern created the archive tables, and adds code to all inserts, updates and deletes to record the new values, the times and the action. You could write all historic reports to mine these tables using sql similar to:
select * from ARCHIVE_FAULT f
WHERE f.ACTION<>'delete'
AND f.FAULT_ID=$P(id) AND f.VERSION IN (
SELECT f.FAULT_ID,MAX(f.VERSION) FROM ARCHIVE_FAULT
WHERE
f.FAULT_ID=$P(id)
AND f.DBUPDATED_AT<P(date)
GROUP BY f.FAULT_ID
)
|
| Behaviour: |
This pattern requires that the entity also uses the optimistic locking and audit patterns. A new table will be created for any archived table, named ARCHIVE_XXX where XXX is the table name. This table will have an additional column called DBAUDIT_ACTION. The table's primary key will be extended to include the optimistic locking column. The archive table will not have indexes or constraints on it, nor will it have an auto-incrementing primary key. Every successful insert, update or delete will insert into the archive table, populating the action field. An alternative is to use Emeraldjb to create the tables, and then write your own triggers to populate the archive tables. |
| Usage: |
<PATTERN NAME="ddl.locking.optimistic" VALUE="version" /> <PATTERN NAME="ddl.audit" VALUE="48" /> <PATTERN NAME="ddl.archive" VALUE="TRUE" /> |
Example
This example is from the FaultLog downloadable Emeraldjb project. The first set show the global patterns used within the faultlog project, and the only entity shown here is the fault entity which uses the audit and archive patterns in addition to the global ones.
<PROJECT NAME="LOG" > <PATTERN NAME="value.classpath" VALUE="com.tallsoft.faultlog.datavals" /> <PATTERN NAME="stream.classpath" VALUE="com.tallsoft.faultlog.datastream" /> <PATTERN NAME="stream.proto_version" VALUE="1" /> <PATTERN NAME="dao.classpath" VALUE="com.tallsoft.faultlog.datadao" /> <PATTERN NAME="ddl.mysql.table_type" VALUE="InnoDB" /> <PATTERN NAME="ddl.oracle.owner" VALUE="faultlog" /> <PATTERN NAME="ddl.oracle.role.admin" VALUE="fault_admin" /> <PATTERN NAME="ddl.oracle.role.read" VALUE="fault_read" /> <PATTERN NAME="ddl.oracle.role.update" VALUE="fault_update" /> <PATTERN NAME="ddl.oracle.role.developer" VALUE="fault_dev" /> <PATTERN NAME="ddl.locking.optimistic" VALUE="version" /> <PATTERN NAME="value.string_auto_fix" VALUE="null_only" /> <SECTION NAME="Faultlog" > ... <ENTITY NAME="FAULT" > <PATTERN NAME="ddl.audit" VALUE="48" /> <PATTERN NAME="ddl.archive" VALUE="TRUE" /> <JAVADOC> ...

