On 13 Apr 2005, at 18:08, Vadim Gritsenko wrote:
Pier Fumagalli wrote:

I'm just saying that the concerns are separate: a block provides generators, transformers, serializers, ... to other blocks, but those are de-coupled from the real java components (if any) doing the job.

But *real* blocks, IIUC, *are* the only way to bring new (java) components into the system, because Cocoon core lacks all the optional components, and, at the minimum, consists only of environment, treeprocessor, and block manager.


So in extreme case xslt processor component itself is optional and provided by the xslt real block.

I think that we're mixing again the idea behind a Cocoon block and an Avalon block.


As far as I've understood Cocoon blocks (and I might be _ENTIRELY_ wrong here) Cocoon blocks do not expose (for example) an XSLT Java transformer, but expose a transformer converting a specified format into another.

Again, an example using Forrest.

The forrest block (ForrestBlock) requires two different blocks implementing the following interfaces:
- ForrestRepository: a block exposing a generator that given a uri path (/2.1/whatsnew) generate an XML document in the <!DOCTYPE book PUBLIC "-//APACHE//DTD Cocoon Documentation Book V1.0//EN" "book-cocoon-v10.dtd"> format
- ForrestSkin: a block exposing a serializer converting a document in the above mentioned format into something usable by a browser and exposing a mountable pipeline containing the resources (images, css, javascripts, ...) that the client will see...


The ForrestBlock might have a sitemap which might look something like this:

<map:sitemap>
  <map:components>

    <map:generators>
      <map:generator name="repository"
                     src="block:repository:/generators/repository"/>
    </map:generators>

    <map:serializers>
      <map:serializer name="renderer"
                      src="block:skin:/serializers/renderer"/>
    </map:serializers>

  </map:components>

<map:pipelines>
<map:match pattern="resources/**">
<map:mount src="block:skin:/pipelines/resources" uri-prefix="resources/"/>
</map:match>


    <map:match pattern="**">
      <map:generate type="repository" src="{1}"/>
      <map:serialize type="html"/>
    </map:match>
  </map:pipelines>
</map:sitemap>

Now, the "repository" implementation block might expose a virtual generator like this:

<map:block>
  <map:generators>
    <map:generator name="repository">
      <map:generate type="file" src="{1}"/>
    </map:generator>
  </map:generators>
</map:block>

but another implementation might specify the following:

<map:block>
<map:generators>
<map:generator name="repository">
<map:generate type="sql" src="select content from documents where id = '{1}'"/>
<map:transform type="xslt" src="sql2document.xslt"/>
</map:generator>
</map:generators>
</map:block>


In the same way, the "skin" implementation block

<map:block>
  <map:serializers>
    <map:serializer name="renderer">
      <map:transform type="xslt" src="document2html.xslt"/>
      <map:serialize type="html"/>
    </map:serializer>
  </map:serializers>

<map:pipelines>
<map:pipeline name="resources">
<map:match "**.jpg">
<map:read type="resource" mime-type="images/jpeg" src="resources/images/{1}.jpeg"/>
</map:match>
</map:pipeline>
</map:pipelines>
</map:block>


but again, another implementation might do different:

<map:block>
  <map:serializers>
    <map:serializer name="renderer">
      <map:transform type="stx" src="document2wap.stx"/>
      <map:serialize type="wap"/>
    </map:serializer>
  </map:serializers>

<map:pipelines>
<map:pipeline name="resources">
<map:match "**.gif">
<map:read type="image" mime-type="images/gif" src="resources/images/{1}.jpeg"
width="20" height="20" scale="yes"/>
</map:match>
</map:pipeline>
</map:pipelines>
</map:block>


So far, easily enough, we can see how the "ForrestBlock" interacts with the block interfaces it requires, and how those can be composed differently. Easy enough, so in the sitemap we want to use from cocoon:

<map:sitemap>
...
  <map:match pattern="wap/**">
    <map:mount block="ForrestBlock">
      <map:parameter name="repository" value="SQLForrestRepository"/>
      <map:parameter name="renderer"   value="WAPForrestRenderer"/>
    </map:mount>
  </map:match>
  <map:match pattern="html/**">
    <map:mount block="ForrestBlock">
      <map:parameter name="repository" value="SQLForrestRepository"/>
      <map:parameter name="renderer"   value="HTMLForrestRenderer"/>
    </map:mount>
  </map:match>
...
</map:sitemap>

Now, without considering the real java component which are doing the job (XSLT transformer, IMAGE reader, STX transformer, ...) the block implementation can be entirely developed using the technology (Avalon's ECM/Carsten's ECM+++) without caring too much about Java components themselves.

You can simply deploy several versions of the same interface block in the same container, and given that we're taking the problem of loading classes out of the picture, blocks can work as they're supposed to be without thinking much about the crummy Java machinery behind them.

Also, think about one thing: is a transformer exposed by a cocoon block a specific XSL or STX or (you name it) transformer, or is it a pseudo-component which per se knows how to translate the input to its output?

The java component "XSLT transformer" doesn't do anything "by itself", it becomes a "Cocoon transformer" (it transforms a specified document into another) only when the java XSLT component is associated with the XSLT.

But the same "Cocoon transformer" can be created by associating the STX "java component" with an equivalent STX stylesheet.

Now, there is also another concern that falls into this ballpark.

In my view, I think that our "ForrestBlock" block will only be allowed declare its requirements through interface blocks. This means that for a block to work properly, its requirements must be abstracted entirely from the specific implementations.

But a block implementation MIGHT (in my view) require a _very_specific_java_component_ to fulfill the contract it implements. For example, in the case of the "ForrestRepository" interface implementation, the generator exposed is abstracted entirely, but to implement this component I can require a SQLGenerator (Java component), a FileGenerator (Java component), a JcrGenerator (Java component), and so on and so forth.

So, in my view, either we define an interface cocoon block for each possible component (95% of those will only have ONE implementation), or we allow blocks to require specific JAva components to do their jobs, without relying on interfaces.

So, at the end of the day, the java componentization of how a generic generator (for example) exposed by a block is a completely separate, different, concern from the one implied in the blocks: I want a generator that given a URI produces a document of "book" doctype.

My 0.02 £

        Pier





Reply via email to