(This document is adapted from a message written by stefanomazzocchi and posted on the cocoon development mailing list)

Up to version 2.1.x, Cocoon is a framework implemented as an application.

A 'framework' is supposed to give services to entities included in it, while an application is supposed to be executed by a containing framework.

While the above might sound weird at first, this is a very common situation: an operating system is a framework implemented as an application run at boot time. At the same time, an application server is a framework implemented as an application. But even a browser is a framework implemented as an application.

So, there is no inherently bad design in this concept, *but* the framework must be implemented in such a way that it's inherently *easy* to deploy/install/plug-in/connect/attach/inject/link an internal application that must be executed by the framework.

Let me give you an example: I would like to be able to package my stuff that I wrote to be run *by* cocoon and deploy it on Cocoon, maybe even at runtime.

The parallel is easily made: servlets and WARs archives. The Servlet API introduced in a later release the concept of a WAR (Web ARchive) package that includes all the resources needed for the servlet/jsp-based web application to run, including libraries, resources, files and everything.

So, the parallel I want to draw is simple:

{{{ WAR (Web ARchive) -> tomcat (or other servlet container)

so, a WAR package is for tomcat what a COB will be for Cocoon.

In very short terms: a way for you to deploy your stuff on Cocoon without hassle (including special libraries, resources and what not).

Are we really cloning the servlet API?

Many purists from the J2EE world (even Apache people) believe that Cocoon is an attempt to rewrite the servlet API for XML. In a sense it's true: the servlet API wasn't designed for pipelines and the deployment descriptor wasn't designed for serious URI space mapping.

So, while the Servlet API introduces components (servlets and filters) that are based on streams of bytes/chars, Cocoon introduces components designed to be part of a pipeline (since 1997 I thought about a way to allow servlet chaining to be feasible, that is probably what triggered the idea of pipeline components for Cocoon).

Anyway, looking at this parallel, Cocoon really lacks a way to make its applications deployed easily within a 'naked' container that includes only the basic and default machinery.


We could stop here, we could clone the WAR concept inside Cocoon, allow you to deploy your stuff and you won't be missing anything.

But there are two things that the servlet API architects didn't consider (not even myself at that time since I was part of that group): polymorphism and inheritance.

Applying Avalon COP philosophy over again

If you ever worked with Avalon, you know the feeling: at first it doesn't make any sense at all. It's a mess of stupid and very abstract interfaces... but after a while, a pattern emerges and it sticks.

Once you start using COP (component oriented programming), it's very hard to go back (so much so that many abuse it and over-componentize their systems... even Cocoon itself suffers from this problem on some parts).

COP is based on IoC (Inversion of Control) and SoC (Separation of Concerns) and while the servlet API makes extensive use of the IoC metapattern, SoC doesn't play a clear and defined role (they tried to patch it with RequestDispatcher, which is the ugliest hack ever).

Anyway, if the servlet API, internally, show use of IoC and SoC, externally, from the WAR point of view, there is *absolutely* no notion of it: a WAR is a package that includes a single and isolated application.

Period. That's it. There are many mechanism that enforce the clear separation between different WARs. So, they implement monolithic web applications and this is *by design*.

Improvements

Improvement #1: component-oriented deployment

Let me give you a possible use-case scenario.

Let us suppose that we implement WAR-like package deployment on top of Cocoon and that your application requires both PDF serialization and SVG->PNG rasterization.

Then, you implement another cocoon web application and you still require PDF generation.

Unfortunatley, since WAR-like installation isolates the packages and their classloaders, you have to install the PDF serialization libraries twice.

Thus the idea of blocks as units of deployable service. Here is a picture:

{{{ +


+ +


+


+| |+


+ +


+|


+| |+


+ +


+|


+ +


+}}}

{{{ +


+ +


+


+ +


+


+ +


+


+ +


+}}}

The second case allows:

maintained by different groups independently, as long as the service contracts remain the same)

Improvement #2: polymorphic behavior

The above solution already improves on the WAR model, but we can do better than this. Another use-case scenario:

In the previous scenario, your web application required PDF serialization and, in fact, it mixes concerns if it depends *explicitly* on FOP since, later on, you might want to use another library/service that implements the same (for example iText or RenderX).

So, instead of depending on a particular *implementation* of a service behavior, if we make blocks depending on *behaviors* directly (considered as service contracts) we can implement polymorphic behavior of blocks.

Again, let's visualize it:

{{{ +


+ +


+


+ +


+


+ +


+


+ +


+}}}

{{{ +


+ +


+


+ | | +


+ |


+ | | +


+ |


+ +


+


+ +


+


+ +


+}}}

Here, the webapp1 requires "fo-pdf" serialization services but it does not care (nor should!) which implementation of this service is actually located into the system.

It is, in fact, the installer's concern to indicate what block that implements that behavior should be used in that system at that time.

Note that this allows several very intersting things:

  1. versioning: it is possible install several different versions of the same block and try them out (even at runtime) and roll-back if the version creates incompatibilities without having to change anything in the blocks, but only using the block manager (which is the part of cocoon responsible for deployment and configuration of blocks in the system).
  2. polymorphism: I can have different implementations of the same behavior and I can switch them simply by acting on the block manager, without having to touch a single configuration line in any block. The blocks are, in fact, sealed.

Improvement #3: block inheritance

The third step is to allow blocks to extends other blocks.

The idea is to be able to wrap a block with another one, creating an 'overloading' mechanism similar to the one used by OOP inheritance where methods are 'fall back' to the extended class if the extending class doesn't implement them.

Let us supposed we have the following block (very simple):

{{{block "A" implements "skin"

and let us suppose that we want to change the look and feel of that block. The first two stylesheets provide simply a way to adapt from more specific markup to the Document DTD. So, my block would need to change only the last two resources 'document2html.xslt' and 'logo.gif'.

The best solution is to allow my block to explicitly "extend" that block and inherits the resources that it doesn't contain.

{{{block "B" extends block "A"

but then block B still is considered implementing behavior "skin" because the rest is inherited.

This mainly:

BlockIntroduction (last edited 2009-09-20 23:43:09 by localhost)