org.melati.poem User Guide (document $Revision$)

Introduction

Melati and POEM

Melati is an open source, Java-based infrastructure for the rapid and convenient development of web-based database applications. This guide describes the API of Melati POEM (Persistent Object Engine For Melati): the layer which provides Melati with its object-oriented view of the underlying relational database. POEM is, in fact, independent of the rest of Melati and could be used on its own in non-web applications.

Other information

See also the POEM ODMG documentation which provides an ODMG compliant interface to Postgres - using POEM to do all the hard work.

See also the javadoc documentation for Melati's classes. The key classes are:

Anatomy of a POEM session

The following fragment (see Search.java) shows the general pattern in which POEM is used. First, the Database object is created and connected to the RDBMS using the standard JDBC "URL", username, and password:

final Database database = new PoemDatabase();
database.connect("jdbc:postgresql:williamc", "williamc", "*");

The details are stored and used to make as many independent JDBC Connections as needed (so-called "connection pooling").

Next, a simple task is performed, namely setting the name of user number five to William Chesters:

database.inSession(
    AccessToken.root,
    new PoemTask() {
      public void run() throws PoemException {
	User user5 = database.getUserTable().getUserObject(5);
	user5.setName("William Chesters");
      }
    });

Why the new PoemTask business? Every access to a Melati database must be made from inside a PoemTask passed to the database's inSession method. This is because everything done by the run() method you provide is carried out

  1. with a specific set of access Capabilitys determined by your session's AccessToken---the first argument to Database.inSession, and
  2. in the context of a single database transaction, which is implicitly committed at the end or rolled back if an exception is thrown.

In this example, the access token used is root, which simply allows you to do anything; but most often the token will correspond to a particular User, and Melati will make sure that your task cannot see/change any data to which the administrator has denied the user read/write access. Furthermore, it will not see any changes to the database made by other tasks which may be running at the same time, unless it does an explicit commit or rollback. The upshot is that once you have set your task running, you do not have worry about or even mention permissions or transactions at all.

Of course, when POEM is used as part of Melati, sessions are started automatically (by PoemServlet.doConfiguredRequest) with an appropriate access token, so Melati programmers never normally have to call inSession.

What is "user number five"? All records in a POEM database table must be uniquely identified by a so-called "troid" (for table row ID), i.e., every table must have a integer primary key, or non-null uniquely indexed integer field. Typically, the troid field is called id, but it need not be. The call database.getUserTable().getUserObject(5) returns an object representing the record from the user table with troid 5.

Where does the object's setName method come from? Every POEM database must contain various tables whose properties are declared at (POEM's) compile time in the "data structure definition" (or DSD) Poem.dsd, including user; the relevant excerpt is

table User {
  (primary) Integer id;
  String login (size = 20);
  String password (size = 20);
  String name (size = 60);
}

The POEM preprocessor turns this into boilerplate code which defines typed accessor methods like setName corresponding to the fields given in the DSD, and also ensures that the fields are present in the database when the application starts up (by creating them if necessary, or failing with an error message if an incompatibility is detected). Programmers are free to write their own application-specific DSDs so that they can take advantage of type-safe methods and automatic initialisation, but it's not mandatory, since all tables and fields (including any in the RDBMS which are not predeclared in the DSD) are also available via generic accessors in which their names appear as string arguments. In fact the example above could have been written as follows:

        ...
	Persistent user5 = database.getTable("user").getObject(5);
	user5.setValue("name", "William Chesters");
        ...

The database

Part of POEM's job is to maintain rich type information about the columns present in the database, so that Melati knows how to present them on web pages, POEM itself can guarantee that the values stored in them will be valid according to fairly fine-grained criteria, and the preprocessor can import those types into Java at compile time for the benefit of the application programmer.

How the database is represented

POEM provides a tidy Java-style view of the database, with objects representing the database itself, its tables, and their columns and rows.

The database

Each Database object corresponds to a single database (i.e. collection of tables) in the DBMS. Its function is to act as a container for Tables and as the carrier of POEM's top-level APIs.

Database itself is an abstract class. Each data structure definition file Bar.dsd gives rise to an extension of Database called BarDatabaseBase containing boilerplate code for accessing the tables declared in the DSD in a type-safe way, and a blank subclass of that called BarDatabase to which you can add methods of your own. It is BarDatabase that you should instantiate. Or, if you are not working with a DSD-defined schema, you should instantiate PoemDatabase (which is actually derived from a DSD file called Poem.dsd).

Tables

Each Table object represents a single table in the DBMS. It acts as a container for the table's columns and provides methods for searching over and retrieval of the records in the table.

Each declaration table Foo in the DSD gives rise to an extension of Table called FooTableBase containing boilerplate code to express the application-specific schema of the table in a type-safe way.

How the database gets defined

The type information stored by the RDBMS and provided through JDBC's DatabaseMetaData facility is not sufficient for POEM's purposes (the more so since not all RDBMSs can record referential relationships between columns). So POEM synthesises the DatabaseMetaData with two other sources, one originating at compile time with the programmer and the other at run time with the database administrator.

The Data Structure Definition

The programmer's contribution is called the Data Structure Definition or DSD. It takes the form of a single text file containing a series of table definitions each resembling a Java class definition---or, better, a C structure definition, since at this stage no methods can be specified. POEM's own builtin special tables are defined in this way in org/melati/poem/Poem.dsd, which makes a good example of a DSD; the file format is described in detail in the documentation for the preprocessor which interprets them.

The table definitions are mapped by the preprocessor onto a series of automatically generated Java class definitions, which do two things: they bring the names and (enriched) types of the database fields into the static Java type system, making the application-level programming clearer and less error-prone, and they carry initialisation code which checks that the database is consistent with the DSD each time the application is started up (and creates any tables and/or columns which are missing). The programmer can subclass or otherwise use the typed Java representation of the database objects to build up the business logic of her system, letting POEM and the Java compiler do the work of ensuring that she is using the database in a consistent way and of creating and maintaining an appropriately structured schema in the RDBMS.

The metadata tables

The second function of the DSD-derived code---to provide automatic creation and subsequent verification of the predefined parts of the database---is a convenient service for the programmer, but could prove irritating to the database administrator if it meant that she had to edit a text file and recompile the application every time she wanted to add a field, even one which wasn't used in any Java-coded application logic, or just change the default width of a text box. So POEM stores its rich field-type information in special tables in the database itself, where it can be edited through a web interface (the generic admin system).

The tableinfo table describes the properties of each table in the database (including itself): its programmatic name, its displayname and displayorder (used by the Melati admin system), and the Capabilitys required for reading and writing its rows (where not overridden in the rows themselves, or in the application Java code---see the discussion of POEM's access control mechanism).

The columninfo table describes the properties of each column in the database (including its own). Like tableinfos, columninfos define a programmatic and a display name and a display order; in addition, they carry fields which jointly define the column's PoemType.

(Although there is in principle no reason why anyone should have to interact with these tables directly, a detailed description is provided in the POEM internals document.)

The JDBC metadata

coexistence with JDBC (though UPDATEs a bit trickier)

Persistence semantics

accessing objects cross-session ...

Access control

...


About this document

Readership and purpose

This document is also intended to give the wider open source community an insight into Melati POEM, so that they can give us feedback pre-release and evaluate the finished product in an informed manner.

History

The important points in the life of this document are listed below.

The CVS log for this document is:

$Log$
Revision 1.2 2006/12/13 11:49:53 timp
New javadoc and db mount points

Revision 1.1 2005/11/21 22:01:49 timp
Moved from site/doc

Revision 1.17 2003/07/11 23:47:41 timp
remove a few broken links

Revision 1.16 2003/04/21 22:17:22 timp
Broken link reported by SevenTwentyFour Inc

Revision 1.15 2003/03/04 22:01:47 jimw
Removed some broken links and a few misleading historical details.

Revision 1.14 2003/02/13 11:03:12 timp
change prepro url

Revision 1.13 2003/02/10 16:44:33 timp
Update hrefs

Revision 1.12 2002/11/25 15:56:09 timp
Broken link (reported by seventwentyfour.com)

Revision 1.11 2002/10/09 14:33:58 timp
Change javadoc URLs, validate HTML

Revision 1.10 2000/09/11 10:56:42 kimptoc
added some ODMG/POEM documentation

Revision 1.9 2000/03/25 16:03:40 williamc
Fix javadoc links for javadoc 1.2 and add reference to TailoredQuery

Revision 1.8 2000/03/18 10:34:11 williamc
Start sketching in Database section

Revision 1.7 2000/03/01 21:20:05 williamc
Fix a couple of typos

Revision 1.3 2000/02/27 21:19:14 williamc
Add table and field descriptions; fill out auto-initalisation from DSD