Melati is an open source, Java-based infrastructure for the rapid and convenient development of web-based database applications. It addresses the following problems typically encountered in the development of complex sites:
Melati was influenced in its development by the ground-breaking Webmacro templating system, which allows for a clean divide between the HTML (WML, ...) page design and the program.
Since Velocity has arrived Melati has become template engine agnostic. It works with all versions of Velocity and was shown to work with a home grown templating engine (Jtemplater).
Melati fits into and encourages a Model / Controller / View (MVC) approach to systems design.
Melati can render both field values and input controls such as <INPUT>s and <SELECT>s automatically, using JDBC field information enriched with web-settable preferences. It also adds Javascript triggers for validating input values on the client side before submission, according to the fields' types. Links between related fields are resolved transparently, so that they seem like Java references.
Melati offers a generic database admin system which allows searching/browsing of any table, and editing of both the contents and the structure of any part of the database, without the need for customised admin pages: data entry and editing "out of the box", just like you get with desktop database packages.
All database accesses made through Melati are subjected to low-level checks via a user/group/capability mechanism, configurable by the administrator. Either cookies or HTTP Basic Authentication (the mechanism commonly used for password protection of static pages) can be used to maintain the user ID in a session.
Melati's easy-to-use persistence mechanism can present a predefined subset of the database to the programmer as a collection of Java objects, with statically typed set/get methods, which happen to store their state in the database. She can add Java methods to these objects (table rows), and express the application logic in a much more natural way than she could using JDBC directly.
Each Java thread (such as that processing a single servlet request) is associated with a different concurrent database transaction, and runs with different access permissions depending on the user on whose behalf it is working.
Intensively-used tables can be transparently cached on a least-recently-used basis (and the cache behaves correctly with respect to transactions).
Standard queries (including simple joins) can be transparently cached so that an up-to-date result is recomputed on demand. It's easy to make automatically-refreshing higher-level database-dependent objects as well. This cacheing mechanism is also transaction-safe!
The entry points to a Melati application are a set of one or more servlets derived from TemplateServlet. There are subtypes for different template engines. It takes care of determining the Melati username associated with the client, and the `logical database' on which the servlet should operate from the path info: for instance, the URL
http://melati.org/db/org.melati.admin.Admin/melatitest/user/View
asks the Admin servlet (Admin.java) to " View the user table of the melatitest database". This scheme has the (admittedly minor) advantage that it makes possible the use of concise relative URLs for many purposes.
If it has not already been encountered by the running virtual machine, the logical database name is mapped to JDBC connection details via the config file org.melati.LogicalDatabase.properties. When the first JDBC connection has been established (i.e. once per JVM), a picture is built up of how the structure-database ought to look, drawing on the programmer's compile-time Data Structure Definition (DSD), if any, and on the type-rich metadata set up by the administrator using the generic admin interface. This picture is then unified, or reconciled, with the actual database structure reported by JDBC's DatabaseMetadata. In effect, the structures specified by the three sources are added together and merged; any tables or columns present in the underlying DBMS but not specified by the programmer or administrator are incorporated (and have default metadata records created for them), while conversely any tables or columns specified by the programmer or administrator but not present in the DBMS are created. If the unification cannot be completed consistently (e.g. if the underlying database has been incompatibly altered), the connection is aborted.
The end result of all this as far as the Java code is concerned is a natural and convenient representation of the database in terms of Database, Table and Column objects. Columns have rich PoemType types which include information such as the target of a reference (link) or the default height of a text field; but in general one works directly in terms of Persistent objects representing the rows in the database.
In coding up the application logic, the programmer accesses the rows' fields using statically named and typed methods autogenerated at compile time from the Data Structure Definition. For more on this, see the Melati POEM User Guide.
Template writers can simply ask for the appropriate field value and let the MarkupLanguage of their choice render it appropriately. For instance, assuming that an application servlet has set $product to refer to some Persistent object, one could say
#set $Response.ContentType = "text/html" #set $ml = $melati.HTMLMarkupLanguage <HTML> <BODY> <P> You have asked for a $ml.rendered($product.NameField), which has to come from $ml.rendered($product.CountryField) at a cost of $ml.rendered($product.Country.PriceField). <P> </BODY> </HTML>
The ...Field idiom returns a value wrapped up with a PoemType which the markup language $ml (set to HTML at the top of the template) knows how to render. Note the phrase $product.Country.PriceField, in which a reference (link) to a record in the country table is transparently followed.
Generating input controls for objects' fields is just as easy. The following simplified fragment of a template from the generic admin system (Edit.wm, also illustrates how you can iterate over all the fields in an object without having to know their names:
<TABLE> #foreach $field in $object { <TR> <TD> $ml.rendered($field.DisplayName) </TD><TD> $ml.input($field) </TD> </TR> } </TABLE>
Behind the simple phrase $ml.input($field), Melati is
Part of the point of having type-specific templates is that they can carry JavaScript (VBScript, ...) routines for client-side validation of the values entered or otherwise selected by the user. For instance, this is template/webmacro/templets/html/org.melati.poem.IntegerPoemType.wm :
<INPUT NAME="field_$ml.rendered($field.Name)" SIZE=$field.Width VALUE="$ml.Attr.rendered($field.RawString)"> <SCRIPT LANGUAGE=JavaScript1.2> add_integer("field_$ml.escaped($field.Name)", "$ml.escaped($field.DisplayName)", !$field.Type.Nullable) </SCRIPT>
You can see at the top and bottom of Edit.wm how these JavaScript fragments fit into the overall template.
Melati's home on the web, http://melati.org , provides information, mailing lists and CVS access.
See the Example.
The README has installation details.
Document | Description | |
---|---|---|
org.melati.poem |
Of interest to programmers. Melati POEM (Persistent Object Engine for Melati) is what gives Melati its object-oriented view of the underlying relational database. It maintains type information about database fields, and handles connection pooling, cacheing and access control. POEM is independent of the rest of Melati and could be used for non-web applications.
|
|
org.melati.poem.prepro |
Of interest to programmers. POEM's preprocessor is responsible for turning concise, Java-style "Data Structure Definitions" into boilerplate code for creating a corresponding relational database and representing it as a collection of typed objects.
|
|
org.melati.template |
Of interest to page authors.
Melati's API is Template Engine agnostic. Melati can be used with
Webmacro or Velocity or both, as Webmacro templates are converted
on-the-fly to Velocity templates.
|
|
org.melati.admin
|
Of interest to most users. The generic database administration system supports "out of the box" content editing. |
Go on, ask a question on the Mailing Lists!