Ross Gardler wrote:
This is a Random Thought. The ideas contained within are not fully
developed and are bound to have lots of holes. The idea is to promote
healthy discussion, so please, everyone, dive in and discuss.

In order to better support my position in this RT I've been experimenting with alternative implementations.

I now have a working (although very hacky) version of a new Forrest Core. It is *very* basic right now so don't get too excited, I'm only trying to feed the flames of this discussion. The deployed webapp version is 960kb, this includes the test code and sample documents. Add the size of Xalan and Xerces for the CLI version.

Clearly this will grow as we add some of the missing features (see below). Spring, ehcache and an RE processor are probably the largest additional dependencies we need in core and they weighs in at a few hundred Kb each (I think).

In other words, it looks like I can deliver in just a few megabytes.

What is does have:
------------------

- XHTML2 as internal format

- Locationmap support

- plugin architecture

- XSLT transformations

- CLI interface (very basic no link following)

- Webapp interface

- File and HTTP readers


What it doesn't have:
---------------------

- Container managed components

- pattern matching in the Locationmap or in the output plugin selection

- handling of aggregated documents - they work on the input side, but I'm still considering how best to handle them on the output side.

- external config files (i.e. the locationmap and available plugins are currently hard coded data structures)

- image (and other binary files) handling

- cacheing

- optimisation (i.e. no SAX stream between the individual components)

- adequate demos (a couple of Hello World input plugins and Gavs XHTML2 sample document only)

- loads of stuff I haven't thought of yet


Design
------

It's really simple (honest), the processing goes like this:

request URI (to controller)
  -> source documents(s)  (from readers)
    -> internal document(s)  (from input plugins)
      -> output document        (from output plugins)

The main componets are:

Controller
----------
This is the interface point between the application (CLI, webapp, or JUnit tests so far). To use it you do somethin like:

requestURI = new URI(TestController.TEST_REQUEST_URI);
Controller controller = new Controller();
AbstractOutputDocument doc = controller.getOutputDocument(requestURI);
out.println(doc.getContentAsString());

LocationMap
-----------
A simple lookup table mapping the requestURI to the required source document(s) - it supports optional files and aggregation.

A locationmap is built as follows (remember this should be read from a config file):

URI requestURI = new URI(TestController.TEST_REQUEST_URI);
location = new Location(requestURI, this.getClass().getResource(
        TestController.SOURCE_DOCUMENT_XHTML2_COMPLETE), true);
locationMap.put(requestURI, location);
location = new Location(requestURI, this.getClass().getResource(
        TestController.SOURCE_DOCUMENT_XHTML2_SIMPLE), true);
locationMap.put(requestURI, location);

Then you get the locations(s) with:

List<Location> locations = locationMap.get(requestURI);


ReaderFactory
-------------
Given the URL of a source document this factory returns the correct reader for the document. For example "http://foo.com"; will return an HTTPReader whilst "file://bar" will return a file reader.

Reader
-------
Reads a source document and infers the type of document it is (XML, image etc. although only XML is supported right now). This returns a typed document class representing the document by using a DocumentFactory.

DocumentFactory
---------------
This is perhaps the most complicated part of the system. It is roughly equivalent to the source resolver, that is, it infers the type of document we are working with. Once it knows the type of document it can provide a typed document object.

If we have a mime-type that gives us enough information it will use that (i.e. an OOo document). If not it will try looking ahead into the contents of the file until it has enough info. For example:

while ((numRead = reader.read(buf)) != -1 && mimeType == null) {
  String readData = String.valueOf(buf, 0, numRead);
  fileData.append(readData);
  buf = new char[1024];
  if (fileData.toString().contains("<?xml")) {
        String type = getXMLDocumentType(fileData.toString());
        doc = new XMLSourceDocument(fileData.toString(), reader);
  }
}

InputPluginFactory
------------------
Given a typed source document this factory provides an InputPlugin to convert from the source document to an internal XHTML2 document.

OutputPluginFactory
-------------------
Given one or more internal documents and a request URI this factory provides an OutputPlugin for producing the final document as requested.

What Next?
==========

- make the locationmap load from an XML file

- use a component manager and configure plugins from the containers config files (rather than building the config in code)

- handle aggregation on the output side (I'd like to discuss how to handle this if anyone is interested in helping out, but we must be aware that this is still an RT and we are only exploring ideas not committing the community to anything)

- create a documentation/test site

- build a number of input and output plugins for testing, such as:
        - OOo Input
        - RDBMS Input
        - PDF Output
        - RTF Output

- experiment with cocoon integration as a plugin (I *really* like this idea it seems to cover most of the drawbacks Tim has identified in my ideas, although I'd like to hear what Tim thinks about this)

- decide if we should continue experimenting along this line.

Ross