>    ShutdownRequestingContext src =
>     (ShutdownRequestingContext)
> context.get(ShutdownRequestingContext.class);
>
>    DirectoryContext dc =
>      (DirectoryContext) context.get(DirectoryContext.class);
>
>    MailForwardingContext mfc =
>      (MailForwardingContext) context.get(MailForwardingContext.class);
>
> if all you know about are the "atomic" interfaces, as well as support:
>
>    JAMESComponentContext jcc =
>      (JAMESComponentContext) context.get(JAMESComponentContext.class);
>
> if you know about the "molecular" interface.  Note that client code is
> completely isolated from whether the relationship between the context
> implementation and the interface implementation is IS-A or HAS-A.

Noel,

your approach works, but there are still a mass of casts being done
(one per get()), and the last operation (the one with JAMESComponentContext)
still requires some tricks with proxies. Furthermore, while you do
hide the IS-A/HAS-A specifics of the context, there are other ways of
doing this, and I think your approach is a clumsy way of doing it,
as it forces the user to deal with a myriad of atomic interfaces.

Issues:

JAMESCOMPONENTCONTEXT STILL REQUIRES PROXIES
--------------------------------------------

I'm assuming here that

    interface JAMESComponentContext extends
        MailForwardingContext,
        ShutdownRequestingContext,
        DirectoryContext {}

I'm also assuming that the container writer is aware of the existence of
MailForwardingContext, ShutdownRequestingContext and DirectoryContext
(as well as some other context interfaces, say, ClassLoaderContext),
but that the container writer is not aware of the existence of
JAMESComponentContext.

So if we look in the container's code, it'll look like this:

  class ContextImpl implements Context,
        MailForwardingContext,
        ShutdownRequestingContext,
        DirectoryContext,
        ClassLoaderContext { (implementation) }

Now, how can you return a JAMESComponentContext? This class didn't exist
when the container was compiled, and while the ContextImpl class implements
all methods of JAMESComponentContext, you can not cast it to a
JAMESComponentContext.

In short, when I call get(JAMESComponentContext.class), how do you
provide it? You should be able to, because you do provide all operations
in the interface.




RESTATEMENT OF MY POSITION
--------------------------
(In the spirit of "if I keep repeating it, it will be true".)

The Context can be seen as a set of operations or services
that the container provides to the component. These services
may be simple getters:

  File getHomeDirectory ();

or performance information:

  long getSystemUptime ();
  long getSystemIdleTicks ();

or ways for the component to request actions of the container:

  void requestShutdown ();

We have bunched related operations into interfaces. For example,
the requestShutdown operation is in the RequestShutdownable interface
(following the Avalon practice of appending "-able" to just about
everything here).

Now, the container will provide a set of operations, call that set P
(for Provided). The component will require a set of operations, call
that set R (for Required).

Obviously, if R isn't a subset of P, we're toast. The container
can't sprout new code, after all. (And to forestall the "ok so we
make it pluggable" solution: If you can make it pluggable, it isn't
part of the Context, it is then a peer service.)

OK, so the problem now is:

 1. How does the component specify R?
 2. How does the container provide R?

My solution is:

 1. The component writer creates an interface that extends those
    atomic interfaces (RequestShutdownable etc.) whose operations
    it requires. Call this interface ComponentContext.

    The component then declares that as its desired context
    interface.

    This guarantees the following:

      +  The context object passed in to the contextualize
         method can be casted to ComponentContext.


 2. The container needs to do two things: First, verify that
    it can indeed provide all the operations. Second, provide
    them via the required interface.

    The container must have some implementation of a Context.
    Each operation is basically defined by a method signature.
    Thus, it should be trivial to confirm that R is a subset of
    P,  or abort if it isn't.

    The container can now create a dynamic proxy object that
    implements the required context interface. Method calls
    through the ComponentContext interface are routed as
    needed to the methods of the context implementation.

/LS


--
To unsubscribe, e-mail:   <mailto:[EMAIL PROTECTED]>
For additional commands, e-mail: <mailto:[EMAIL PROTECTED]>

Reply via email to