Architecture overview

This page briefly describes the main components of the JCopist core module.

Core components

The template manager

The template manager is responsible for the storage of the document templates used by the server. It is invoked when a new template is added, or when another component needs to use an existing template.

There is currently only one available implementation, which stores the unzipped content of the templates on the file system. However, new template managers can be developed by implementing the net.sf.jcopist.templates.ITemplateManager interface (for instance, templates could be stored in a relational database).

Builders and the builder manager

A builder merges a template with the dynamic data supplied by a client, in order to produce an OpenDocument.

More precisely, the builder requests the template's data from the template manager, copies it in a temporary directory, runs FreeMarker on some of the files, and re-zips the directory's content.

Builders are obtained through the builder manager , which manages an internal pool of builders.

Converters, OpenOffice instances and the converter manager

A converter converts the OpenDocument created by the builder to the format requested by the user.

This is where OpenOffice.org comes into play, as we need a running instance to perform the conversion. Therefore, there is a one-one relationship between converters and OpenOffice.org instances : a converter launches an soffice.bin process when it is created, and monitors this process throughout its lifetime (try killing an soffice.bin process while JCopist is running, it will be re-spawned).

Converters are obtained through the converter manager , which manages two internal pools of converters: one for synchronous jobs, and one for asynchronous jobs. The reason to have to separate pools is to avoid contention between the two types of jobs.

Senders and the sender manager

A sender is used to send the generated document to its final destination (senders are only used in asynchronous mode). The client specifies which senders to use and how to configure them by adding transport instances to the submitted job.

Senders are obtained through the sender manager . As senders do not maintain an internal state, they need not be pooled. Therefore, the sender manager dynamically instantiates the sender(s) corresponding to the transport(s) requested by the client.

How jobs are processed

Whether in synchronous or asynchronous mode, the way to process a job is the same. It is implemented in the net.sf.jcopist.process.impl.DocumentManager class that dipatch jobs to the needed module :

  • submit new Job to the JCopist server
  • Job transformed in ManagedDocument with specific workflow roadmap (assume that is classical Job process : buid, convert then send)
  • submit the managed document to the builder process, request a builder from the builder manager.
    • merge the data and the template with the builder.
    • return the builder to the builder manager.
    • return the managed document to the DocumentManager
  • submit the managed document to the converter process, request a converter from the converter manager.
    • convert to the final format with the converter.
    • return the converter to the converter manager.
    • return the managed document to the DocumentManager
  • submit the managed document to the sender process
    • for each transport specified in the job :
      • instantiate the corresponding sender.
      • call the sender's send method.

Synchronous (realtime) mode

There is not much more in the synchronous service than what's described above. Once the final document is generated, it is directly returned to the client. The synchronnous jobs are handled by net.sf.jcopist.service.impl.RealtimeServiceHelper .

Asynchronous (batch) mode

The asynchronous mode uses a few more components, as submitted jobs need to be queued.

An embedded HSQL database is used to store waiting and failed Jobs. The net.sf.jcopist.process.impl.DocumentManager is used to queue the jobs. It uses an internal pool of threads to process the jobs from the queue; these threads dispatch jobs in the required server modules ( builder, converter, sender).

Note that, in order to provide fault-tolerance, each job is stored in the database when it enters the queue ; the persisted job is deleted only when it has been entirely processed or if the database has been re-initialized. Therefore, if the server crashes, all pending jobs can be recovered.