I have added a first, hopefully working, version of the sitemap aspect of real blocks to the trunk. No functionality to get components (not even VPCs) yet from the blocks.

Examples can be found in: http://svn.apache.org/viewcvs.cgi/cocoon/trunk/src/test/org/apache/cocoon/components/blocks/ the implementation is supposed to follow http://wiki.apache.org/cocoon/Blocks and the result of various mail list discussions (although I can have missed things).

Use
===

FS layout
---------

A block has the file system layout

[cocoon block] [DIR]
 |
 +-- COB-INF [DIR]
      +-- block.xml
      +-- classes [DIR]
      +-- lib [DIR]

according to http://wiki.apache.org/cocoon/BlocksFSLayout. Where block.xml is described in http://wiki.apache.org/cocoon/BlocksCob. [cocoon block] is like an ordinary Cocoon top level directory and typically contains a main sitemap, files and sub directories.

Configuration
-------------

block.xml describe where the main sitemap is and all component configurations are done from the main sitemap. Either directly in map:components or indirectly through an include http://svn.apache.org/repos/asf/cocoon/trunk/src/webapp/WEB-INF/cocoon.xconf. The code in COB-INF/[classes|lib] can be found throgh the local classloader http://marc.theaimsgroup.com/?l=xml-cocoon-dev&m=111032234204889&w=2.

The deployment configuration including URLs to the blocks is done in wiring.xml, http://wiki.apache.org/cocoon/BlocksWiring. Schemas for wiring.xml and block.xml can be found in http://svn.apache.org/viewcvs.cgi/cocoon/trunk/src/schema/. Currently no deployment tool is integrated so one have to write wiring.xml by hand. The super block of a block is identified by /wiring/block/connections/connection/@name='super', see http://svn.apache.org/viewcvs.cgi/cocoon/trunk/src/test/org/apache/cocoon/components/blocks/wiring.xml?view=markup for an example.

The wiring file is used by the BlocksManager to set up all the blocks. The BlocksManager is configured to point to the wiring.xml:

<component role="org.apache.cocoon.components.blocks.BlocksManager"
           class="org.apache.cocoon.components.blocks.BlocksManager"
           file="wiring.xml"/>

All access to blocks goes through the BlocksManager.

blocks: protocol
----------------

The blocks mount paths from deployment should in principle be used before the main sitemap in the (main) webapp is called. But at this point I didin't want to touch the core classes e.g. o.a.c.Cocoon or let any core components depend on the block infrastrucuture. Therefore I instead created a blocks: protocol that can be used in the main sitemap to connect to the blocks system:

  <map:match pattern="**">
    <map:read src="blocks:/{1}"/>
  </map:match>

block: protocol
---------------

The block: protocol, (http://wiki.apache.org/cocoon/BlocksDefinition and http://wiki.apache.org/cocoon/BlocksDefinition) the blocks version of the cocoon: protocol,

  block:/test

will call the pipeline with URI test in the root sitemap of the current block.

  block:./test

will call the pipeline with URI test in the current sitemap of the current block. In both cases block inheritance and polymorphism are respected (take a look at http://svn.apache.org/viewcvs.cgi/cocoon/trunk/src/test/org/apache/cocoon/components/blocks/test3/ for examples). The reason for not using "://" and ":/" for absolute and relative addressing as for the cocoon: protocol is that it doesn't follow the http://www.ietf.org/rfc/rfc3986.txt, see http://www.betaversion.org/~pier/wiki/display/pier/Cocoon+and+URIs for Pier's rant about it.

  block:foo:/test

will call the pipeline with URI /test in the block. The extended block can be explicitly called by,

  block:super:/test

block-property: module
----------------------

A block can have a number of properties that can be given default values in block.xml and deployment values in wiring.xml (see examples in test3/). The value of a property in the current block can be accessed with an input-module,

  {block-property:foo}

There is no access to properties in other blocks. The blocks properties can be used for things like db URLs and should IMO be block private.

block-path: module
------------------

A block URI block:foo:/bar where the foo block is mounted at /test can be "absoultized" to /test/bar by using the block-path input module,

  {block-path:foo:/bar}

see example in http://svn.apache.org/viewcvs.cgi/cocoon/trunk/src/test/org/apache/cocoon/components/blocks/test1/sub/. This module can be used together with the LinkRewriterTransformer http://cocoon.apache.org/2.1/apidocs/org/apache/cocoon/transformation/LinkRewriterTransformer.html from Forrest fame to creta the block link rewriting behaviour described in the end of http://wiki.apache.org/cocoon/BlocksDefinition.


Implementation
==============

BlocksManager
-------------

o.a.c.components.blocks.BlocksManager is the "root" class of the blocks frame work (it is a singleton). It reads the wiring.xml and configure and creates all the blocks. It implements o.a.c.Process and take care of requests to mounted blocks. The policy for mounted blocks is that the most specific mountpath is used if several blocks mount points matches the URI. I.e. for the request /foo/bar/blaha where block A: is mounted at /foo and B: at /foo/bar, the request will go to block B:. The current algorithm isn't that efficient.

All access between blocks are done through the BlocksManager and it also takes part in absolutizing block: URIs.

The BlocksManager takes care of the same things as o.a.c.Cocoon, but in the block context. The current implementation doesn't contain all the sofistication of o.a.c.Cocoon yet. A later question is if we should merge Cocoon and BlocksManager or if we should make it configurable whether it is the main sitemap (through Cocoon) or the wiring.xml (through BlocksManager), that is the "root" or keep it as is.

BlockManager
------------

The BlockManagers is created and configured by the BlocksManager and represents a block. All the blocks communiciation with the rest of the system is shielded by its BlockManager (well as there isn't any classloader isolation yet the shielding is limited), which in turn talks with the other blocks through BlocksManager. The BlockManager has an own ServiceManager that gets some minimal parent manager that is configured by resource://org/apache/cocoon/components/blocks/core-components.xconf". As mentioned above the local service manager can be extended with a sitemap defined class path, it would be nice to do this implicitly for COB-INF/[classes|lib].

The BlockManager also reads the block.xml and start a tree processor based on the local sitemap. It implements Processor.

It contains and manages the block properties and take care of some part of the block URI resolution.

At a later point I think that we should refactor the BlockManager so that there can be several implementations. In this way (given classloader shielding) one could maybe run several versions of Cocoon in the same "blocks container".

Block
-----

o.a.c.components.blocks.Block is an interface that the BlockManager implements and that is supposed to be used when the BlockManagrer is used by other components. It need some more thinking.

BlockEnvironmentHelper
----------------------

o.a.c.environment.internal.BlockEnvironmentHelper extendes the EnvironmentHelper with the static method Block getCurrentBlock(). The BlocksManager takes care about always puting the currently executing Block at the top of the Processor stack so that it an be found with getCurrentBlock. Take a look at

boolean BlocksManager.process(String blockId, Environment environment, boolean superCall)

This is the, somewhat subtle, main mechanism for polymorphism. Each time a new block is entered through the block: or blocks: protocol, it is done through the process methods of the BlocksManager. When a new block is entered it is pushed at the processor stack. But when a block delegates to its super block, the super block is not pushed. This means that all block:/ and block:./lookups in the super block (and its super blocks in turn) will be done through the block manager of the called block. To make this work for relative block lookup, block:./ it is not done by calling the current TreeProcessor as in the cocoon: protocol, that would break polymirohism for relative URIs. Instead the relative URIs are first "absolutized" and the used through the current block manager.

I made it an own class only to keep EnvironmentHelper indenpendent of the blocks framework. At a later point they should probably be merged. <OT>Or even better be replaced by a official execution stack with current manager, context, logger, block, processor, object model and sitemap params. With such a thing we could get rid of the use of Servicable, Context, Logger and some other stuff and use about any container internaly</OT>

BlocksSource
------------

o.a.c.components.source.impl.BlocksSource, implements the blocks: protocol. Delegates to mounted blocks through the BlocksManager, should be made caching and probably XMLizable.

BlockSource
-----------

o.a.c.components.source.impl.BlockSource, implements the block: protocol. Uses the current block from the BlockEnvironmentHelper and delegates the URI parsing and processing to the BlockManager. Should also be made caching and XMLizable.

BlockPropertyModule
-------------------

o.a.c.components.modules.input.BlockPropertyModule, implements the block-property module. It is rather straight forward and delegates the work to the current block manager. What lacks is a POJO friendly getProperties() method in the BlockManager, and a clear idea about which default values and deployment values that should take precedence in the case of block extension, take a look at the property handling part of BlockManager.initialize().

BlockPathModule
---------------

o.a.c.components.modules.input.BlockPathModule, implements the block-path module. It is rather straight forward and delegates the work to the current block manager.


State
=====

It is obviosly not tested that much yet. The interfaces and implementation needs community involvement.

                  --- o0o ---

WDYT?

/Daniel

Reply via email to