cocoon-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Stefano Mazzocchi <stef...@apache.org>
Subject Re: [RT][merlin][cocoon] blocks, auto-assembly, versioning
Date Thu, 17 Apr 2003 13:33:56 GMT
Happy to see my RT picked up.

on 4/16/03 11:48 PM Leo Simons wrote:

[snip]

> Random Comments on Stefano's RT
> ===============================
> Cocoon specific item: a sitemap. I don't know exactly what the sitemap 
> does within cocoon, but IIUC it basically ties avalon-style components 
> to various parts and tasks within a web application. It is sort of an 
> xml description of the process-based MVC architecture cocoon implies. 
> The whole concept of a sitemap is pretty much specific to a certain 
> style of user interface application, and I believe in the current cocoon 
> case pretty specific to web-based user interfaces. Not going to talk 
> about it further.

In super-short terms, a sitemap.xmap file is for cocoon what a build.xml
file is for ant.

> An interesting comment from Stefano is that the servlet spec implies 
> monolithic applications by design, since it stimulates seperation of 
> wars. This is quite interesting because phoenix seperates its sar files 
> (Server Application aRchive) more rigorously than the average servlet 
> container its wars, yet the applications built on top of it (that I 
> know) are rarely monolithic.

This is because the servlet API were *designed* to avoid inter-war
communication. Avalon was born *exactly* to remove that limitation, but
provide a secure and IoC-based environment.

NOTE: In case you were not around, look into the archives: much of the
Phoenix architecture was discussed between Peter, Berin, Fede and I
exactly around the concept of Blocks which has been in the Avalon
original concept since 1999.

Then, much of the original concepts were changed and block enteded up
being deprecated in Avalon. But I still consider it useful.

[snip]

> Instance sharing above and beyond library sharing
> -------------------------------------------------
> Stefano also points out you almost always have to install multiple 
> copies of jars: there is no way to install a single jar and use it 
> multiple times (java has no functionality for .Net shared assemblies, so 
> to speak). This is not strictly always true (most servlet engines 
> provide a /common/lib), but it is the most common case for webapps to 
> provide everything.

Wait, don't mislead my reasoning: I'm fully aware of the facilities such
as /common/lib or jre/lib/extension or even jre/lib/endorsed, but my
point is that in order for webapps to be *really* deployable, one must
install it and forget it. the container should do what it takes to
minimize the abuse of memory and space.

> What he doesn't explicitly state is that besides sharing of common jars, 
> you want to share common instances, or at least get your instances from 
> a common pool. This is basically what he dubs "component-oriented 
> deployment", IIUC:
> 
>   ---------------------------------------------------
>   |    Inside the running application appserver     |
>   ---------------------------------------------------
>   | ----------------------                          |
>   | | Processor Pool     |                          |
>   | |                    |<-----------------\       |
>   | |                    |                  |       |
>   | ----------------------                  |       |
>   |     ^           get [ProcessorInstance] |       |
>   |     | get [ProcessorInstance]           |       |
>   |     |                          ---------------  |
>   | ---------------                | Application |  |
>   | | Application |                ---------------  |
>   | ---------------                                 |
>   ---------------------------------------------------
> 
> in other words, there are various resources multiple applications might 
> share, just like in daily life you often have multiple web applications 
> talking to the same instance of a (say, mysql) database. In the above 
> diagram (don't you love ascii ;), the Processor Pool might be replaced 
> by the database (like hsqldb), and the ProcessorInstance might be 
> replaced by a DataSource instance. Depends on the granularity.
> 
> This kind of setup is not implemented in phoenix (it is left up to the 
> user to setup JNDI or something like that, and perform the get() against 
> something fetched from JNDI).

The above is something that cocoon will need like fresh air, expecially
in the new flowscript subsystem where javascript code will call the
avalon container and get an implementation of a particular service and
these services *must* be hot deployable.

> A container which does enable this (and very elegantly, using the proven 
> to be very useful altrmi), is EOB, 
> http://www.enterpriseobjectbroker.org/. They (Paul Hammant being a prime 
> mover) summarise it as "A bean server that uses .Net style remoting for 
> Java". EOB runs on top of phoenix, btw.

A potential flowscript is something like this

 var repositoryROLE = Packages.org.whatever.components.Repository.ROLE;

 function edit(page) {
     var repository = cocoon.componentManager.get(repositoryROLE);
     var page = repository.load(page);

     ... perform editing ...

     repository.save(page);
     ... send results ...
 }

We aim to be able to:

 1) deploy a new instance of a repositoryROLE into the system at runtime
 2) change the association of the above reference to the instance at
runtime.

This is because we want to:

 a) add/change functionality without restarting
 b) allow to try the new functionality without restarting
 c) allow to roll back to the previous version/implementation in case
problems arise with the new one without restarting

this is useful both in development and production.

[snip]

> Inheritance already available in java
> -------------------------------------
> Stefano's bullet point number three is inheritance, where a block 
> identified by a URL extends another block identified by some other URL. 
> This is both potentially complicated to implement, and already 
> implemented perfectly well with standard java inheritance. 

As all avaloners so far, you fail to see that CoP approaches can be
applied to things that are not, strictly speaking, code.

Let me give you an example: suppose you have two jars

 a.jar
  +- foo.xml
  +- bar.xml
  +- images
        +- logo.gif

 b.jar
  +- foo.xml
  +- bar.xml
  +- images
        +- logo.gif

you will note that the above two jars share one thing: the internal file
layout.

Now, suppose that you plug these jars into a system that expects this
file system layout. This is the *contract* between the component and the
system. This is a 'non code' interface.

The above is polymorphic: I can plug in different modules and, as long
as the file system layout and the file schemas are the same, everything
is fine.

So, you can say that both 'a.jar' and 'b.jar' *implement* the given
filesystem layout, which we can identify with a unique (and versioned) URI.

Now, let's apply inheritance:

 a.jar
  +- foo.xml
  +- bar.xml
  +- images
        +- logo.gif

 b.jar extends a.jar
  +- images
        +- logo.gif

where you can see how

 b.jar extends a.jar
  +- images
        +- logo.gif

is totally equivalent of having

  b.jar
  +- foo.xml
  +- bar.xml
  +- images
        +- logo.gif

where only 'logo.gif' has been modified.

But with this kind of inheritance, you have one *huge* feature: having
b.jar extend a.jar means that all changes to a.jar are *transparently*
reflected to everything that b.jar doesn't overwrite explicitly.

This is only an example on how the same concept of polymorphic
inheritance can be applied to many more things than simply code, in this
case a file system.

> Inheritance 
> has its use in COP, and I really don't understand why a different 
> mechanism is neccessary.

Because java inheritance just deals with code, we also need to apply the
same concepts to others things like xml files, images and all types of
resources that cocoon blocks will carry along.

[snip]

> Versioning
> ----------
> Stefano talks about what is basically versioning of implementation. 

no. I talk about both versioning of the roles and versioning of the
implementations. I think both are required.

> Of 
> course, you also want versioning of work interface. 

exactly.

> The level at which
> to implement versioning is the subject of debate. Java has the extension 
> mechanism for doing it at the jar level (the recent releases of the 
> excalibur components do this neatly for example, and merlin and phoenix 
> make use of that. I think netbeans uses this as well). There's also the 
> option to brute-force require a certain format for the name of the 
> provided jar (ie ${id}-${version}.jar). OSGi does bundle versioning in a 
> way similar to the extension mechanism IIRC.

The use of jar manifests is workable. as it is the solution of a
block.info file.

> Another option which has been tried (and discarded by some, ie Peter 
> Donald :D) is the association of a version with a work interface rather 
> than with the archive containing the work interface. .Net does 
> versioning of the archive (the assembly), and has a pretty extensive and 
> usable mechanism for it (basics at 
> http://msdn.microsoft.com/library/en-us/cpguide/html/cpconassemblyversioning.asp). 
> Most other stuff I know does this, too.

Supposing that a work interface can remain the same forever is utterly
utopistic. By providing revisions and the ability to have several
different instances in the same environment, we allow an easy and
smoother evolutionary path for both implementations and abstractions.

In order to scale and pass the test of reality, a CoP system must
implement effective versioning for everything that can be used as a
contract between two subsystems. This includes:

 1) the block implementation
 2) the block abstraction

So, personally, I don't see the single interface to be versioned, but
rather the URI that identifies the block that contains the interface.

So, when we do

 componentManager(Repository.ROLE)

ROLE doesn't need to be versioned since the classloader will know
*which* block implementation of *which* particular block abstraction it
has to go to to load that class and this happens transparently (the
control is totally inverted).

> Implementing Versioning
> -----------------------
> My opinion is that it normally makes sense to provide a version for a 
> small group of components, not individual work interfaces, and that it 
> makes sense to package such a component into a seperately distributed 
> archive (jar). 

I agree.

> I also think it makes sense to use the java extension mechanism to do this.

Could well be. I haven't given much thoughts on the implementation details.

[snip implementation ideas]

> Compatible with cocoon blocks needs?

cocoon blocks extend avalon blocks. I'd be very happy to be able to
reuse as much as possible from anything that avalon will provide, but,
at least personally, I will not sacrifice the ability to do stuff like
block-level inheritance because this is simply too important for the
cocoon realm.

At the same time, knowing how much harm cocoon has done on avalon, I'm
ready to roll my own implementation if the cocoon block needs remind too
far from avalon's.

[snip]

> By reusing the jar MANIFEST.MF file and the 
> extension mechanism (extending on it a little to specify dependencies at 
> runtime), there is no need for a custom archive format like .sar or 
> ..cob. In fact, the entire concept of a "block" as distinct from "some 
> kind of aggregation of some components in a jar with a manifest file" is 
> simply not (formally or strictly) needed.

This is potentially true.

> I also removed the concept of a "behaviour URI" from cocoon blocks, as 
> behaviour is already specified by a work interface, and a work interface 
> is already identified by a role.

The behavior of a cocoon block is identified by:

 a) the dynamic resources it provides (described in the sitemap)
 b) the static resources it provides (described by their layout and
their schemas/binary formats)
 c) the avalon components it provides (described by their interfaces)

NOTE: there is no general consensus on the need of both a) and b) as
some would like to unify all resources as given by the sitemap only

A cocoon block behavior *must* have at least one of the above, but it
could well have all three!

I agree that, in case the block specifies only c), this falls back in
being a normal avalon block, but even in that case, it could contain
several different components and thus there is the need to identify the
behavior of *all of them together* and version that which can't be done
at the simple classname level.

This shows pretty evidently why I think that a cocoon block extens an
avalon block.

And it also shows why cocoon blocks has needs that avalon doesn't have
nor can provide with its current containers. (althought I would be only
happy to be proven wrong :-)

> Finally, I removed the concept of "block inheritance". It might make 
> sense in the cocoon context, but in general I can't see what it does 
> that java inheritance doesn't.

I hope I showed you why we need that.

> This thing still does support "optional COP", and is fully 
> backwards-compatible with any and all software I can think of. A 
> container which doesn't support auto-assembly simply ignores the extra 
> entries in the manifest, a metadata parser tool simply ignores the 
> @merlin.<blah> stuff. The idea is also to reuse all existing 
> infrastructure for this stuff.
> 
> Also note the attribute setup is completely optional. What it all boils 
>   down to is that having a few extra lines like
> 
> Manifest-Version: 1.0
> Created-By: Avalon-Merlin metadata parsing tool v1.0
> 
> Name: com/my/service
> Extension-Name: MyService
> Specification-Vendor: Apache Software Foundation
> Specification-Version: 1.3.22
> Implementation-Vendor: Apache Software Foundation
> Implementation-Version: 1.1
> Implementation-Vendor-Id: ASF
> 
> Merlin-Dependency-Name: com/my/pool/MyPool
> Merlin-Dependency-Version: 3.1
> Merlin-Dependency-Implementation-Location:
>     http://maven.my.com/mypool/jars/my-pool-3.1.jar
> Merlin-Dependency-Optional: true
> 
> Merlin-Dependency-Name: com/my/cli/MyCLITool
> Merlin-Dependency-Version: 1.0
> Merlin-Dependency-Implementation-Location:
>     http://www.my.com/dist/my/cli/my-clitool-1.0.jar
> Merlin-Dependency-Optional: false
> 
> in my-service-1.3.22.jar!/META-INF/MANIFEST.MF (something which is 
> doable by hand, or probably relatively easily generated from a slightly 
> modified maven POM using a few lines of jelly) allows automatic 
> resolution of dependencies, and addresses half of the cocoon blocks 
> requirements without needing additional semantics. The other half can be 
> addressed using the EOB approach.

I would be interested in knowing if my above points changes your POV on
the above (note: not implying anything, just curious).

Anyway, thanks for your RT on the matter.

-- 
Stefano.



Mime
View raw message