org.melati Functional Specification (document $Revision: 1.1 $)

# `org.melati` Functional Specification (document $Revision: 1.1 $)

This document provides a specification of the ways in which the system interacts with users. See also the system's master QA document.

## Paneris programmers; the open-source community

For an incomplete sketch of part of the API, look at the `javadoc` documentation.

### Data structure definition

The data structure definition is a single file which describes, in a form similar to a series of Java class declarations, the tables and fields which the program definitely expects to find in the database. If a field `foo` is declared in this file, it may be used in a type-safe way by the Java code, via automatically generated `getFoo`/`setFoo` method pairs; furthermore, the programmer has the opportunity to override those methods or add further operations in order to express the `business logic' of the `persistent classes' in a convenient and familiar way.

However, the data structure definition is not exclusive: other tables and fields may be present in the underlying RDBMS database, and they will be available for generic processing in dynamically generated reports and forms. These undefined fields can also be referred to by their literal names, albeit in a non-type-safe way, by the programmer if she does not wish to go to the trouble of putting them in the data structure definition.

#### Dataflow

The data structure definition is processed into a set of machine-generated Java files, including a Java schema representation whose job is to initialise (and subsequently check the consistency of) the running database when the Melati application is started up.

#### Annotated example

The following snippet shows part of the data structure definition for an invoicing system. It is followed by a key explaining what the various constructs mean.

>     table Invoice {
>       (primary) int id;
>       Date taxDate;
>       (indexed) Party issuer;	     // a reference
>       (unique) String number (maxlength = 10);
>       (indexed) Party receiver;
>       InvoiceLine.invoice Subset lines;  // proposed for an owned list
>       Textarea notes (width = 50, height = 5);
>     }

>     table InvoiceLine {
>       (primary) int id;
>       Product product (combo);
>       (indexed) Invoice.id invoice;
>     }

>     (cachelimit = 1000) table Party {
>       (primary) int id;
>       (unique) String name;
>     }

`table` |  | Each `table` declaration corresponds to one table in the underlying database and one Java class. The system can autogenerate both a base definition for the class, including transparent marshalling, and, optionally, the database table (using SQL `CREATE` `TABLE` and `CREATE` `INDEX` commands).
field definitions |  | A table's fields are basically declared in the familiar `type` `name;` format. For instance, the `date` declaration in `Invoice` will give rise to a field called `date` in the `Invoice` database table and a pair of methods `Date getDate(); void setDate(Date date);` in the `Invoice` class. `Attributes' specifying the indices required for each field and default display preferences are given in parentheses.
`(indexed)` |  | If a table is specified as being indexed by a particular field, the index will be generated automatically when the data structure definition is processed. FIXME: Possibly some more sophisticated mechanism for passing SQL index-type parameters will be needed?
`(unique)` |  | It's also possible to specify that every record in the table must have a different value for a particular field. `unique` implies `indexed`.
`(primary)` |  | One field in each table must be designated as a primary key. The system uses this as an OID (object identifier) to help it manage the cache. The `primary` field need not necessarily be called `id`. By implication, it is indexed and unique, and the system takes care of setting and reading its value: the programmer will hardly ever have to use it explicitly.
references |  | References (links) between objects---in RDB jargon, `one-to-one' relationships between records---are specified just like string or numeric fields, in the form `target-table name;` The target field of a reference is always the target table's primary key. For instance, the `issuer` declaration in `Invoice` will give rise to a field `issuer` in the `Invoice` table which contains the primary `id` number of a `Party` record, and to a pair of methods `Party getIssuer() void setIssuer(Party isser);` in the `Invoice` class which deal directly in objects representing the linked `Party`: the necessary dereferencing happens transparently.
owned lists |  | FIXME:I think this is history but there is a way of specifying how you want to maintain data integrity when a row is deleted. JimW Owned lists of objects, similar to Java `Vector`s and expressed in RDBs as `one-to-many' relationships between records, are specified in the form `target-table.link-field Subset name;` For instance, the `lines` declaration in `Invoice` will cause the system to check that `InvoiceLine` has an indexed field `invoice`, and give rise to a method `Subset getLines();` in the `Invoice` class, which returns an object behaving somewhat like a `Vector` (FIXME say more ...).
`(cachelimit =` ...`)` |  | A limit can be placed on the number of records from each table which will be held in the cache. If omitted, it defaults to some suitably small number.

#### Unboxed compound fields

Sometimes, it would be convenient to be able to embed sub-records inside a table row, rather than linking into a separate table. For instance, we might want to express a quantity of money in an arbitrary currency, by including a reference to the currency in question along with the numeric amount; logically, the two fields form a single unit of data, and could well be grouped into an object. At this stage, though, it's not clear that features for dealing cleanly with this situation would be sufficiently beneficial to offset the work required to implement them; furthermore, they would inevitably obfuscate the API to some extent, making it less Java-like, because in Java's memory model all compound structures are stored as independent `boxed' entities.

#### Inheritance

For some purposes, it might be nice to support inheritance between tables (as Postgres does). Getting the corresponding Java classes arranged in a hierarchy which mirrored that defined on the tables could probably be managed, albeit slightly untidily given the lack of multiple inheritance. This feature is not considered to be a priority for the moment.

#### Delivery medium

Programmers write the data structure definition using their favourite text editor, just like the write Java code. They must then run a processor over the file in order to generate the Java base class definitions for the persistent classes and the database validation/initialisation code. The processor is written in Java so that any programmer wishing to use Melati will be able to compile and run it straightforwardly. Programmers who use `make`-like utilities can arrange for the processor to be run automatically when the data structure definition file is changed; however, it is not anticipated that this will happen very often, so manual intervention will not be a major chore.

### Access control

#### The capabilities model

Deciding how permissions are expressed in the API means making tradeoffs between flexibility, administrative convenience and implementational efficiency. At the moment, JAL supports arbitrary access control lists for records, templates and controllers, expressed in terms of user groups; exceptions to the default policy (world-readable and world-writeable) are stored in the `userpermissions` table, and queried by means of a three-table join along with `userresourcetypes` and `userresourcetypes`. Although this API is very flexible, it undoubtedly adds some overhead which we might, on the general principle that scalability can only be achieved by constant discipline, seek to avoid even though it's clear that it's not a problem right now. (Since the size of the ACL table may well scale linearly with that of the overall data set, it is probably not sensible to attempt to cache it.) Furthermore, in order to implement any given access policy, it's necessary for an administrator or administrative process to set up an appropriate ACL.

For Melati, it is proposed that we move to the following model:

- Every class representing a database table supports a pair of methods

  > `void assertReadable(AccessToken token) throws AccessException;
  > void assertWriteable(AccessToken token) throws AccessException;`

  which throw some informative exception if `token` is not sufficient to permit reading/writing the record's fields.
- The system invokes the appropriate access-assertion method whenever a field of a persistent object is read or written to (via its `setFoo`/`getFoo` methods). This is how low-level checks are automatically enforced.
- If the fields

  > `Capability readCapability;
  > Capability writeCapability;`

  are defined for a table and are non-null in the record under consideration, the default (base-class) access-assertion methods check `token` against them explicitly. It's possible to define arbitrary permissions for an object, but only in terms of a single capability which is stored in the same table row as the record's actual data fields. An example of a capability might be `writeable by a trusted participant of the FooWeb project'. This scheme is similar to the supplementary group mechanism of the Unix filesystem, and (in fact) to Turbine's user/role/permission system.
- The programmer can override the access-assertion methods for a persistent class if she wants to implement a consistent policy (provided that the class is defined in the data structure definition). For instance, the following fragment from the example database would make invoices (though not their lines) readable by their issuer as well as by anyone with an explicit `readCapability`:

  >     public class Invoice extends InvoiceBase {
  >       public void assertReadable(AccessToken token) throws AccessException {
  >         if (token.getUser() != getIssuer() && token.getUser() != getReceiver())
  >           super.assertReadable(token);
  >       }
  >     }

- Users are assigned to groups, possibly depending on how `far' they have chosen to log themselves in, and capabilities can be assigned to groups or to groups of groups, etc. In a well-designed setup, the group-capability information is compact enough to be cached in its entirety.

We are not interested in supporting generic field-specific access control, but special rules can be supported programmatically by overriding a class's setter/getter methods. For example, the following fragment would prevent changes to an invoice's `taxDate` after the invoice had been `finalised' (as determined by a method `isFinalised` which is here left undefined); the date could still be force-changed using a separate method, but a special capability would be required.

>     public class Invoice extends InvoiceBase {
>       public void setTaxDate(Date date) {
>         if (isFinalised())
>           throw new BlahException("rhubarb");
>         else
>           super.setTaxDate(date);
>       }

>       public void setTaxDate_force(Date date) {
>         if (!Implicit.accessToken().hasCapability(forceInvoiceDetails))
>           throw new BlahException("rhubarb");
>         else
>           super.setTaxDate(date);
>       }
>     }

#### Early or late checks?

Another issue which has to be resolved is the question of when the low-level access control checks are performed. Two different models were considered:

- Partly static. At the beginning of a task involving an object, the programmer asks for a handle providing the level of access she needs. The handle is the object as far as she is concerned (except for `==` tests), but it doesn't offer any methods from the higher access levels. Once she has the handle, she can be sure at compile time that no accesses of its fields will fail for want of permission.
- Dynamic. All object handles support all possible methods, but they may throw an `access denied' exception if the user on behalf of whom the operation is being carried out does not have the appropriate clearance.

The partly static method has the advantage that it uses the type system, to some extent, to help the programmer identify early on what level of access she needs to an object, and documents semi-automatically whether variables and method parameters hold references through which an object can possibly have its state changed. It is, in fact, analogous to the use of the `const` keyword in C/C++; and this should set off alarm bells, because `const` is controversial and has well-known downsides.

Perhaps most seriously, it can confuse novice programmers, because once you start using it, you have to use it consistently: you cannot cleanly call a non-`const`-aware library routine using a `const`-annotated handle.

Furthermore, handles with guaranteed permission levels do not fit well with Melati's access model, in which objects (rows) may require different access capabilities or implement programmatic access policies, and yet we want links to other objects to be resolved transparently. A programmer may have `guaranteed' read access to `obj`, but no promise can be made that `obj.getFoo()` is a readable handle to the linked `foo` until permissions have been checked. So the compile-time guarantee that no access exceptions will be thrown is vitiated even in simple cases.

For these reasons, and for simplicity (providing unbreakably read-only handles is quite complicated), we go with explicitly dynamic access checks. Note that checks still happen at a low level: posting guards on all the entry points to a Melati-based application is not strictly necessary for security.

#### The `current user'

The other main design decision for the access control API is how the identity of the user on whose behalf operations are being performed will be carried around. The options considered were:

- Explicit. A token representing the user must be passed into every API call for inspecting persistent data---which would make field accesses look like

  > `String issuer = line.getInvoice(user).getIssuer(user).getName(user);`

  Of course, provision could be made for the user info to be omitted if the programmer were willing to make the assumption that a field was ``world-readable''. However, this mechanism still goes against the aim of near-transparent persistency.
- Object-implicit. Whenever an object is retrieved from the persistent store on behalf of a certain user, it contains her ID; requests to access fields via that object are implicitly made with her permissions, and linked objects by its accessors transitively carry her ID. The disadvantages of this method are that it will cause a multiplicity of `object handles' to be created, each carrying a different user ID, and that the programmer's code may behave in confusing ways if she stores object references in her inter-session data structures.
- Thread-implicit. As soon as Melati takes control of the handling of each incoming HTTP transaction, it determines the identity of the user (if any) and records it against the thread started by webmacro's `ResourceManager` to service the event. The persistent store can check the user's permissions whenever it needs to without the programmer ever having to mention them.

The thread-implicit technique seems to be the most convenient and transparent option for the programmer, given that the idea of a `current user' carrying implications for the capabilities of the running code is familiar from the process-ownership scheme implemented by all modern operating systems.

Implementation note. The ideal way of implementing a thread-implicit `effective user ID' would be to subclass `java.lang.Thread` so as to be able to associate the ID with each thread directly as a field; but this option isn't available without making a minor change to `org.webmacro.broker.ResourceManager`. Instead, it is proposed that the thread-user association be maintained via a hash table or (possibly ...) by manipulating the thread's name.

#### Overriding access controls

For some purposes, it will be necessary to allow users to perform, in a controlled manner, operations for which they would not usually have the necessary access permissions. For example, the production of relatively insensitive summary reports may involve scanning a number of individually secret records.

The example below sketches how anyone with read access to an invoice could be allowed to compute its total value even if they were not allowed to read its individual lines.

>     public class Invoice extends InvoiceBase {

>       ...

>       public long totalValue() {

>         // Fail if we don't have read access to `the invoice'.

>         assertReadable(Implicit.accessToken());

>         // If we do, force access to its constituent lines for this one operation.

>         long value = 0L;

>         Implicit.pushCapability(InvoiceLine.forceRead);

>         try {
>           for (Enumeration lines = getLines().elements();
>     	lines.hasMoreElements();)
>     	value += ((InvoiceLine)lines.nextElement()).getAmount()
>           }
>         }
>         finally {
>           // To avoid our having to remember to do this, the enhanced-capability
>           // operation could be wrapped up in a Runnable.

>           Implicit.popCapability();
>         }

>         return value;
>       }

>       ...
>     }

>     public class InvoiceLine extends InvoiceLineBase {

>       ...

>       // A capability used by Invoice.totalValue()
>       // It's kept package-private in order to reduce the chance of leakage
>       // leading to a more general access breach than intended.

>       static final SettableCapability forceRead;

>       ...

>       public void assertReadable(AccessToken token) {
>         if (!token.hasCapability(forceRead))
>           super.assertReadable(token);
>       }

>       ...
>     }

#### Summary

Under thread-implicit, dynamic, group-capability access control, a persistent object behaves very like a file: you can legally attempt any defined operation on it, but if the user in whose name you are running is not a member of a group with an appropriate capability, an exception will be thrown following an (almost) indefeasible low-level check. Bypassing record permissions in order to support a particular operation is like setting an effective user ID for a particular utility program.

#### Protecting resources other than records

JAL's security model currently relies on restricting access to Webmacro handlers and templates. There is no reason why Melati's capabilities model should not be used to support access control tests buried in the `HandlerProvider` and `TemplateProvider` supplied to Webmacro. But it's probably better just to have handlers examine the user's capabilities for themselves. The following fragment shows how a handler for a generic record-editing service might do this:

>     // Fetch the record specified in the form

>     String tableName = (String)context.getForm("table");
>     int recordNum = Integer.parseInt((String)context.getForm("id"));

>     Record record = database.table(tableName).record(recordNum);

>     try {
>       // Fail if we can't read it

>       record.assertReadable(Implicit.accessToken());

>       // Fine, return the editing template

>       ...
>     }
>     catch (AccessException e) {
>       // Take appropriate action, e.g. returning a login template
>       ...
>     }

NB in Melati, the worst that can happen if the checks are left too late is that the user gets an error message generated by the low-level persistent store after filling in and submitting a form.

### Transactions

One of the requirements for Melati is that it should support transactions (and that its data cache should remain consistent even when transactions are pending or get cancelled). Integrating transactions with the API under which database records appear as transparently persistent objects poses the same problems as did the notion of the `current user': there has to be some way for the persistent store to know which transaction a data access (NB read as well as write!) is meant to belong to; but to require the programmer to pass a `Connection` handle into every call would spoil the illusion and degrade the simplicity of the interface.

It is, however, anticipated that in nearly all cases, the pattern in which transactions are used will be very simple: for each incoming HTTP request, begin a new transaction; if an exception is thrown during processing, roll it back, but on successful completion, commit it. So it makes sense to adopt a model in which the `current transaction' is associated with the execution thread, just as it is proposed that the `current user' should be. The idea should be familiar from single-threaded SQL monitors like `psql`. If the transaction is set up---along with the user ID---before any of the programmer's code runs, and a trap is put in place to cancel it if an exception condition occurs, then the right thing will generally happen automatically without the programmer having to think about it.

Explicit checkpointing (committing) is also available, and if the programmer needs to perform some subtask in the context of a different transaction, she can do so with the following idiom:

>     Session otherSession = ...;
>     ...
>     Implicit.inSession(otherSession,
>     		   new Runnable {
>     		     public void run() {
>     		       // do the subtask
>     		     }
>     		   });
>     ...

It goes without saying that behind the implicit transaction mechanism, Melati will support `connection pooling'. Implementation note: perhaps Sun's new pooling utility will be suitable.

### Retrieval and modification

#### Identified records

A record identified by its primary key can be called up from the persistent store (cache or DBMS) by invoking a method on its table:

> `Invoice inv = database.invoiceTable().invoiceRecord(234);`

Implementation note. The underlying `SELECT` used to retrieve identified or linked records by primary key is a cached `PreparedStatement`.

#### Searching

It's possible to ask for a `SELECT`ion of objects from a table via its selection method. We may eventually want to support some minimally complicated way of constructing these queries without embedding literal SQL in the code; for instance:

>     Enumeration them = invoiceTable.selection(
>           Filter.like(Invoice.NUMBER, "123%"));

A sufficiently powerful `meta-language' of that kind should be able to support queries which automatically include the joins necessary to resolve references between objects. But there may well be little need for that feature.

The programmer can also run arbitrary `SELECT` queries on the database; the result will not be a stream of objects (so that e.g. any overriding of getter methods will be ignored) and will not be cached, but it ought to be possible to present it in a more friendly form than a `ResultSet`---perhaps an `Enumeration` of `Field` objects which can trivially be turned into appropriate markup in the template.

#### Partial retrieval

For the moment it is not proposed that we support partial retrieval of records, i.e. specifying which fields should be uploaded from the database now (if they aren't cached) and leaving others to be loaded on demand. This might save a little memory and IPC, and possibly disk accesses on the DBMS side if the records were very big, but it's probably not worth it.

#### Updating

Updates to records are supported transparently via the corresponding objects' setter methods. By default, the invocation of any single setter method will result in an immediate `UPDATE` command being issued to the DBMS (although the change will not, of course, be visible outside the current transaction). Since that behaviour is inefficient if one wants to change a number of fields at once, we may want to provide a way of batching updates into a single DBMS command.

At the simplest, this is method pair `record.cacheModifications()`, which causes modifications to an object to stay in the data cache only, and `.writeModifications()`, which causes cached and future changes to be written down immediately as usual. The problem is that you have to remember to turn write-down back on (and also the cache is slightly out of sync with the results you will get from `SELECT`s).

So we wrap those in a `record.apply` method, which you use as follows:

>     invoice.apply(new InvoiceUpdater {
>       public void update(Invoice invoice) {
>         invoice.setTaxDate(taxDate);
>         invoice.setNotes(notes);
>         ...
>       }
>     });

But the most common situation in which a multi-field update is required is when reading values in from a form, and that is handled automatically (and atomically); the `apply` idiom will almost always always be unnecessary.

### Cacheing

FIXME must support transactions and cacheing of whole subsets. Transactions are handled by copying an object's underlying array of fields into a session-private cache when it is modified. An easy, though possibly expensive, solution for subsets would be to copy the whole list of members into the session cache.

### Representing field types and display styles

The fields attached to persistent objects are associated with rich typing and display preference information, which is used for creating displays and input boxes for their values in whatever markup language the template is written in, and for generating javascript validation routines for those inputs.

#### The type/style hierarchy

Clearly there is a necessary distinction between abstract type/style information and the markup-specific way in which it is used (the latter being encapsulated in an object representing the markup language). Another possible cut is between types strictly so defined and display preferences, but it's not clear what would be gained by separating them into two, so it is proposed that the both should be encoded in a single hierarchy (now in org.melati.poem).

#### Values vs. types

Unlike in JAL, it is proposed that field values should not, in general, be stored and passed around with full type information attached, but instead as plain Java `String`s, `int`s and so on. If the programmer needs to know more about the values than is evident from their Java types---which she mostly will not---she has to call a different method:

>     String notes = invoice.getNotes();
>     TextType notesTypes = invoice.table().getNotesType();

The advantages claimed for this approach are a small gain in efficiency, since the values returned by getter methods can be slightly smaller and quicker to construct, and an improvement in transparency for the programmer: she can deal directly in familiar Java types.

However, we will probably also want to provide convenience methods for packaging a value and a type/style together in a form in which they can be used to generate markup concisely in templates.

### Defining markup languages/styles

One of the aims for Melati is to tidy up JAL's facility for generating HTML for form elements corresponding to record fields, with a view to making it easier to understand, and capable of extension to work with WML and XML, and, perhaps, non-SGML-derived languages such as plain text (for emails) or something suitable for input to a PDF generator.

FIXME: this is in fact probably NOT how we will do it; we've realised that calling up mini subtemplates for controls is a much better idea! Embedding HTML (or whatever) in the Java is just wrong, even if it's wrapped in some library.

#### Who does the rendering?

The main issue to be resolved in the design of the new system is: how much commonality of structure do we assume between the target languages?

- Smart `Type`s. We could assume that every markup language looks basically like HTML, and have each `MarkupLanguage` object provide an interface similar that offered by ECS to low-level elements such as `<INPUT>`s; the field `Type`s themselves would then be responsible for abstractly `rendering' any given value using the available operations.
- Smart `MarkupLanguage`s. Or, we could make each language responsible for knowing how to render every known kind of field. This would potentially give us more flexibility in generating representations in languages which did not fit the HTML model very well; on the other hand, it would mean that all the `MarkupLanguage` implementations would have to be upgraded every time a new `Type`---perhaps `Colour` or `ICQNumber`---was added (at least if we wanted it to appear in a cute way).

It is proposed that the we should go with the first option, for the following reasons:

- HTML was designed to be pretty generic with respect to the most familiar computer interfaces, so it makes a reasonable interface-rendering API even if the goal of expressing the logic of the document in an appearance-independent way falls down at the application level (which is why everyone uses HTML tags as appearance markup, why latex is so annoying, why we have decided to use templates, and why XML is going to be less cool than people think).
- We can probably use ECS directly (or at worst in a slightly hacked form) for the HTML `MarkupLanguage`!
- If we make the `MarkupLanguage` the primary entry point for the rendering routines, it still gets the chance to override the default ECS-style mechanism for specific types, and to offer nifty views of types it knows it can handle in a special way.

#### Validation

JAL's mechanism for inserting Javascript fragments which perform client-side validation of form fields works by

- including a Javascript header `validation.js` containing
  - a variable holding a list of validation rules to be applied to the page's fields
  - Javascript routines for adding rules of various kinds to the list
  - a `validate` routine for checking that the fields pass all the tests
- inserting a script fragment alongside each field which adds an appropriate validation test to the list
- assigning an invocation of `validate` to the `submit` button's `onClick` method

This mechanism can be adopted unchanged, along with all the existing Javascript code, by Melati if it is made part of the HTML `MarkupLanguage`. It is proposed that the script fragment simply be included along with the markup for each `<INPUT>` so that it does not have to be mentioned explicitly in the template; the inclusion of the trigger in the `submit` button should be made transparent in a similar way.

## Template authors

`MarkupLanguage`s will provide template authors with easy-to-use facilities for inserting markup which renders field values (which need, for instance, to be escaped in a manner appropriate to the target language) and input controls.

FIXME: this is in fact probably NOT how we will do it; we've realised that calling up mini subtemplates for controls is a much better idea! Embedding HTML (or whatever) in the Java is just wrong, even if it's wrapped in some library.

#### Displaying named fields

The following example shows how part of a template for displaying an invoice might look.

>     #set $ml = $jal2.HTMLMarkupLanguage

>     ...

>     <P>Invoice number: $ml.display($invoice.NumberField)<P>

>     <P>Tax date: $ml.display($invoice.TaxDateField)</P>

>     <P>Colour: $ml.displayColourSample($invoice.ColourField)</P>

>     <TABLE>
>     #foreach $line in $invoice.Lines {
>       <TR>
>         <TD>$ml.display($line.Product.CodeField)</TD>
>         <TD>$ml.display($line.Product.DescriptionField)</TD>
>         <TD>$ml.display($line.AmountField)</TD>
>       </TR>
>     }
>     </TABLE>

At the top of the template is a directive for obtaining an HTML renderer `$ml` which is then used explicitly to display each field. FIXME: It might be possible to make the markup language a (thread-) global setting like the current user and current transaction---need to check what is possible in webmacro's syntax. The labels `NumberField`, `TaxDateField`, ... are used in place of `Number`, `TaxDate`, ... to retrieve both value and type/style information simultaneously (see above).

Note the use of the `displayColourSample` method to force a field to be displayed in a particular form: it's entirely open to the template writer to use language-specific special rendering techniques, because, of course, she knows what language she is writing for.

Pulling the items out of the invoice is trivial: the template writer can simply invoke its `getLines` to obtain an enumerable container with the appropriate objects in it.

#### Generating forms for named fields

Forms for named fields are handled in a similar way (FIXME this is impressionistic at the moment); recall that validation snippets are included along with the markup for each input:

>     #set $ml = $jal2.HTMLMarkupLanguage

>     $ml.BodyInclusions  <!-- get the javascript header in -->

>     ...

>     <P>Invoice number: $ml.input($invoice.NumberField)<P>

>     <P>Tax date: $ml.input($invoice.TaxDateField)</P>

>     <INPUT TYPE=submit value=Update name=Update
>      $ml.SubmitButtonAttributes>

#### Generic fields

Templates for applications like the admin system are written in a similar style their JAL equivalents:

>     #set $ml = $jal2.HTMLMarkupLanguage

>     $ml.BodyInclusions  <!-- get the javascript header in -->

>     ...

>     <TABLE>
>     # foreach $field in $object {
>         <TR>
>           <TD>$ml.label($field)</TD>
>           <TD>$ml.input($field)</TD>
>         </TR>
>       }
>     </TABLE>

>     <INPUT TYPE=submit value=Update name=Update
>      $ml.SubmitButtonAttributes>

## Installers

#### Operations to be performed

There is a really hair-raising list of things that have to be done before a JAL application can be delivered. The following is a summary taken from the JAL Installation Guide:

- Install
  - Java. Relatively standard, but RedHat, the most popular Linux distribution in the English-speaking world, doesn't even ship it, let alone install it by default. Or do they now?
  - Apache. Standard; installed by default on all Linux servers.
  - JSDK servlet development kit. Standard; only needs to be put in the Java classpath.
  - JServ servlet runner. Relatively standard, but there are hoops to jump through to get RedHat 6's Apache installation to install it. Is it still like this?
  - Webmacro. Nonstandard, but only needs to be put in the Java classpath.
  - Postgres. Standard and shipped with RedHat (though it still needs nontrivial initialisation before you can begin to configure databases, and you have to put its Java drivers in the classpath yourself).
  - OROMatcher. Nonstandard, but only needs to be put in the Java classpath.
  - JAL itself with Paneris libraries and the actual application. Needs to be put in the Java classpath and Apache's static content area.
- Configure all the above. This involves editing half a dozen nontrivial configuration files and knowing what a servlet repository is.
- Ensure that Apache and Postgres get started at boot time (the RedHat RPMs do this for you).
- Set up the databases for the application.

Melati can carry out the very last step automatically by running `CREATE` `TABLE` and `CREATE` `INDEX` commands determined from the data structure definition---assuming that Postgres thinks the installer has database-creation rights (current JAL applications provide a `psql`-based script for this purpose). However, the other steps would be exceedingly difficult to automate in a way which would dovetail with an existing setup on a customer's machine: the only viable means of coexisting with their settings would be to use the API of a configuration tool like `linuxconf` (but even `linuxconf` doesn't know about e.g. `mod-jserv`). That leaves two possible solutions, which we could offer as alternatives:

- The customer installs and configures everything from scratch. In practice this will mean them paying an experienced Paneris insider to do it. I think the sheer variety of different packages involved, even more than the complexity of the process, will be a significant barrier to the adoption of Melati by the wider open source community. For a more optimistic view, here are TimJ's comments:

  > umm, noone is pretending it is straightforward, but i think it is within the capablities of all webmacro users. NB ISPs such as ednet (and others that host servlets) provide an environment with Linux, apache, Postgres, Java, JSDK, leaving the user just to messabout with classpaths.

- The customer drops a massive tarball, containing everything from Apache to Melati pre-configured to work together, on top of a more or less blank installation of a particular OS (e.g. the current RedHat). Such a drastic operation will not appeal to developers, but might be quite convenient for customers looking to put up a dedicated server for a Paneris site. We will mention this as an option and do it if there is demand.

#### Delivery medium

Most of the installation will have to be carried out from a command prompt on Linux; the best interface for NT/W2K will be decided when the port is made. However the creation of a Melati application database could be carried out by pressing a button on the web admin interface.

## Administrators

### Generic admin system

The generic admin system looks essentially identical to JAL's existing screens. New database fields and even tables can be added, and will be available for use in templates and generic report/data entry screens: the data structure definition is not exclusive.

Field display preferences set in the data structure definition---canonically, the default height of a `TEXTAREA`---can be adjusted freely by the administrator; the system will never `change them back', because the system only ever adds fields in the DSD which are missing from the running database. FIXME: TimJ points out that this could be confusing: ``I changed my DSD and regenerated, but my text area is still the same size''. It is confusing, and we need a warning message, but the only alternative is to remove preference information to a separate file, and that would detract from the appealing conciseness of the notation.

The administrator is not allowed to change the basic type of any field, e.g. from `INT` to `FLOAT` or from `VARCHAR(10)` to `VARCHAR(11)` (Postgres doesn't support this). She can delete a field (and add it again in a different form), or rename it, provided that it was not declared in the data structure definition; whenever such a change is made (which is assumed to be seldom), the data cache is cleared of records from the table in question, because otherwise the persistent store would have to cope with multiple versions of a table's shape.

#### Delivery medium

Administrators access Melati's services over a web interface. Can we use secure transport for sensitive purposes?

## Users

### Self-management of identity

Login and password management look essentially identical to JAL's existing screens.

#### Delivery medium

Users access Melati's services over a web interface. Can we use secure transport for sensitive purposes?

## Traces of typical sessions

The ways in which users can achieve the goals expected of them by navigating through the system are:

Complete, working examples to follow here eventually.

## Externalities

The external circumstances which are essential to the correct and reliable operation of the system are:

- backups, which are outside the scope of Melati
- FIXME: anything else?

## Risk analysis

The obvious ways in which this specification might turn out to be poor are:

- It might turn out that we need more flexiblity in the eventual `CREATE` `TABLE` statements than we get from the data structure definition language.
- The implicit transaction model might be inconvenient if a programmer wanted to use several transactions in parallel in some complex application.

The obvious ways in which the implementation of this specification might fail are:

- It may take a while for Melati to match the full range of features offered by JAL, and until it does, there's a risk that Paneris developers will go on using the latter rather than extending Melati appropriately.

## About this document

### Authors

William Chesters <williamc@paneris.org>

Most recent CVS $Author: timp $ @paneris.org

### Quality

The current quality level of this document is: Alpha. There are decisions yet to be made, sections to be filled out and some additions to come (including more examples). Some of the content would fit better in the Requirements Specification.

### Readership and purpose

- The customer should feel confident that they will get want they want, and that they know who will be able to use their system, how it will feel, who they need to train, how they will have to support it.
- The project leader should feel happy about taking responsibility for leading the internal design of the system.
- The developers should feel informed about the way the system as a whole fits together.
- Future maintainers should be able to understand the way the system as a whole fits together.

This document is also intended to give the wider open source community an insight into the motivation behind Melati, so that they can give us feedback pre-release and understand the finished product.

### History

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

Date | Event
--- | ---
(not yet) | Certified at release quality level by ...

The CVS log for this document is:
$Log: FunctionalSpecification.html,v $
Revision 1.1 2005/11/21 22:01:49 timp
Moved from site/doc
Revision 1.15 2003/03/04 22:01:47 jimw
Removed some broken links and a few misleading historical details.
Revision 1.14 2002/12/29 09:23:55 jimw
Removed doc from doc/examples
Revision 1.13 2000/10/26 05:53:46 timj
remove documentation of unique with
Revision 1.12 2000/07/27 18:39:45 timp
Make CVS links work
Revision 1.11 2000/02/29 09:53:02 williamc
Finish recovering from disaster; point out in the docs that you can 'add methods to table rows'
Revision 1.2 2000/02/04 18:28:34 williamc
Add QA stub; explain DSD-admin interactino a little better