cocoon-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "Berin Loritsch" <>
Subject [Design] ContainerManager is under fire--let's find the best resolution
Date Thu, 06 Jun 2002 14:55:44 GMT
If anyone is subscribed to the JAMES list, please include them on the
conversation.  This is an important issue that requires the attention
of everyone involved.  The next generation of the ComponentManager will
be simplified from the current implementation, which will force some
projects to change the way they design their systems and interfaces.

Therefore, I suggest we come together on how we lookup and use our
components.  Currently there are three trains of thought: one inspired
by the ECM (monolithic), one inspired by Phoenix(only lookup), and one
inspired by Fortress(in the middle).

The first order of business is that we need to be clear on our

* Component -- a managed resource that is resolved at runtime (late
* Container -- a resource manager that resolves component instances
* Lookup Mechanism -- the interface that the client uses to lookup
* Client -- the code that uses components

I would love to give an illustration, but its copyrighted...

Anyway, here we go:

No other way to say it than its bad.  By merging all the concerns into
entity, we are tempted to do to add new methods to the lookup mechanism.
One example that was probably (in retrospect) ill advised was the
method on the CM.  At the time both Giacomo and I argued that the only
a container would have the knowledge that a client is done with a
is to explicitly say so.  Having seen what has happened in Cocoon's
of component types and interfaces, I can see there are better ways of
things.  The section at the end will identify exactly what I mean.

We have all been indoctrinated at how good this is.  We know because we
use it.
Avalon components are much less painful to develop than EJBs, and a
large part
of that is because EJB design uses a monolithic mindset and Avalon uses
A container is a container.  A lookup mechanism is a lookup mechanism.
is nothing more that needs to be said about that other than what is
separate should be separate in code.

I started on Fortress with the mindset of correcting the most heinous
committed by the ECM.  A Container is a Container, and a lookup
mechanism is
a lookup mechanism.  However, in an attempt to maintain as much
with the ECM as possible it inherited a couple of the shortcommings.
correcting those wrongs would require changing the way we write

The origional ComponentManager Interface

interface ComponentManager
    Component lookup( String role ) throws ComponentException;

That was it.  Nothing more.  The whole problem started with the need for
components, or components resolved by a hint.  As a ressult we invented
ComponentSelector (actually in Cocoon there was a
"NamedCOmponentManager" that
resolved "NamedComponents").  The Avalon team did correctly deduce that
was no real need for NamedComponents.  The name, or hint is a function
the container assigns to a component--not something inherent in the

Then cocoon needed a mechanism for pooled components.  However there was
way to return a component instance to the container.  Peter tried to
tell us
that it can be done, and that it should not be done at the CM level.  In
retrospect, I am sorry we prevailed.  As a result, we have the

interface ComponentManager
    Component lookup( String role ) throws ComponentException;
    boolean hasComponent( String role );
    void release( Component comp );


interface ComponentSelector
    Component lookup( Object hint ) throws ComponentException;
    boolean hasComponent( Object hint );
    void release();


In an attempt to remove the ComponentSelector abstraction,  I came up
something that would be a high performance CM interface.  It used a
or Prototype object to resolve the request for a component ahead of
As a result, we could safely remove the requirement for the
At first I thought it would be a step forward, and I pitched it to the
Avalon list.  When I got some opposition from Peter and Leo, I pitched
it to
Stefano to see if he could recommend anything.

Surprisingly enough, Stefano's reply was simply

"Ok, just one (maybe stupid) question: what's wrong in something like

interface ComponentManager {
     Component getComponent(String role);
     Component getComponent(String role, Object hint);

with a further clarification of

"I currently disklike the abuse of (non-runtime) exceptions that Avalon
to indicate things that are not found. A try/catch requires the JVM to
the state of the execution (sort-of an internal
continuation) and this is a very expensive process.

"The code above is much more performant and friendly in that respect,
even if
I still don't understand the need for those 'request' stubs."

Which raises two very good points.  How should we handle the CM
and do we need exceptions?

As a result, I would like to go back to grass roots, with a couple

Here is the interface for the CM:

interface ComponentManager
    Object lookup(String role);
    Object lookup(String role, Object hint);
    boolean exists(String role);
    boolean exists(String role, Object hint);

If you notice, there are four distinct differences from the current

1) We return Object instead of Component.  This merges the lessons
learned from
   the ServiceManager discussions about accessing legacy components that
are not
   able to emplement the Component interface.

2) We remove all *declared* exceptions.  If there is something wrong, it
is more
   appropriate to throw a RuntimeException.

3) We add an additional lookup and hasComponent method (role, hint

4) We remove the release() method altogether.

Now, I forsee few raised flags with the first three changes.  They
simplify our
lives, and help make truly performant code.  The role/hint combo takes
its cue
from a common construct in Java, used in JSSE, i18n resolution, and many
factories.  Basically there is a default implementation, and the hint is
to let the "factory" choose a different implementation than the default
if need
be.  It also lets us get rid of the ComponentSelector.

In this case, it is a hint to the Container that I not only want a
I want one that handles TLS connections.  That way, we can look it up in
one call,
with no string concatenations:

ConnectionManager conn =
   (ConnectionManager) manager.lookup( ConnectionManager.ROLE, "TLS" );

There is little confustion, and if the hint is not supplied, the CM
returns the
default implemenatation.  It also lets us resolve bundles using a

XMLBundle bundle = (XMLBundle) manager.lookup( XMLBundle.ROLE,
Locale.getInstance("US") );

Or something like that...

What will require some convincing--esp. to the Cocoon crew is the
removal of
the release() method.  To that end, read the last section.

                   -o0  What needs to change 0o-

In order for a container to manage component instances using pools or
policies, we need to change the way we think about our components.
Consider the
DataSourceComponent as a prototype.  With the DataSourceComponent, the
code does not care how the Connection object came into existance.  It
does not
care that it has been used 100 times before.  All it cares about is that
Connection is ready to be used now.  The DataSourceComponent does not
have a
release method, but yet it manages to pool the Connection instances.

The secret is the proxy layer.  The proxy layer is a wrapper around the
object, that intercepts calls to the Connection's "close" method.  As a
instead of truly closing the connection, it merely returns the
Connection to
the pool.  The proxy also adds a method to check if the connection is
still alive.

So the proxy is one way of ensuring we have a component.  It is also a
way of
returning a component automatically after a certain timeout has elapsed.
If the
component is needed again, the proxy is able to pull a new instance from
pool to perform the task.  However, such a use does have consequences to
the design
of your components (i.e. a component can't store state information if it
automatically be returned to a pool after a timeout).

One of the nice things about a proxy style component is that we can also
a type of garbage collection behind the scenes.  Consider Cocoon.
Cocoon has
a hierarchy with the Cocoon object as the root container, and each
sitemap is
a container in and of itself.  Each container in the hierarchy knows
when a
request has been fulfilled--one way or another.  As a result, the
container can
clean up all the components automatically without consulting the child
if they are done with the handles yet or not.

Cocoon's pipeline components like the generators, serializers, et. al.
would either
need to be designed so that they are automatically returned to the
when they are done being used, or they would need to be changed so that
the Generator
returns an XMLSource, the Serializer returns a ContentHandler, and the
returns an object that mixes the two.  Once the pipeline has hit the
SAX event, it can clean up after itself!

In order to make it easier for the component developers, we need to have
dynamic proxy generator (that would also help with DataSourceComponet
It would wrap the interface to enable garbage collection of components.
All a
client is responsible for is to request the component.

Anyway I am open to comments now.


"They that give up essential liberty to obtain a little temporary safety
 deserve neither liberty nor safety."
                - Benjamin Franklin

To unsubscribe, e-mail:
For additional commands, email:

View raw message