Antti Koivunen wrote:
Hi there,
After following the recent discussion on defining a minimal set of core interfaces for A5 (which is nice), I tried to gather some of the ideas and further simplify the concept.
1. Context
Definition: the operational context of a specific component. There is no need for the component to modify its context (think EJB and JNDI env ctx). Management should happen elsewhere.
The lookups can be represented simply as strings (URN/URI syntax), which gives us the following interface:
public interface Context
{
Object lookup( String name ) throws AppropriateException;
}
Naturally, we also need to define a method for setting the context that a component can implement (see further below).
2. Logger, LogEnabled & Co.
I wouldn't include these in the core interfaces. Logger is just another component that could be acquired through the context. This might also help to reduce friction between different projects, as using Avalon wouldn't force them to use a specific logging interface.
The same applies to Configuration, Parameters, etc. (it would be of course possible to implement a base/utility class that takes care of the "standard" lookup operations).
3. Lifecycle
I think we should only include the lifecycle interfaces for which there exists a clear contract, i.e. the ones that make sense in the container-component relationship. This basically leaves us the following operations:
initialize(Context?) / dispose() (~ create() / destroy())
These make sense and should be included. The initialize method could
well take the context as an argument eliminating the need for an
additional interface (a separate setContext method would basically
say: here's your context, but don't use it before I call
initialize).
suspend() / resume() (~ stop() / start())
The necessity of these is subject to some debate. I suppose, the
component could have use for them, but the contract would have to be
clear (see below).
Now, to ensure performance and consistent client access, we should also have a 'service handle' interface (Resource in Merlin):
public interface Handle
{
Object access() throws AppropriateException;
void release( Object instance );
}
Experience with handler access and release has led me to include an argument containing the source of the access and release. This allows the handler to track usage, and more specifically, during demonnissioning the handler can take responsibility for the gracefull termination of all exposed instances. A context implementation along the lines your describing above plays into this as it is the primary origin of instance creation actions (ie. lookup (or get) results in resolution of a handler, access is invoked on the handler passing the context as the source, etc.). This also means that you need to expand you context interface to enable client to release components, which in turn triggers the flow back to the handler to release an object granted by the handler to the context.
This leads to a Context interface something along the lines of (note - lookup replaced by get and String argument replaced by Object to be A4 consitent):
public interface Context
{
Object get( Object key ) throws ContextException;
void release( Object object );
}
If we add some convinience operations to the above, we end up with something like:
public interface Context
{
boolean hasEntry( Object key );
Object get( Object key ) throws ContextException;
void release( Object object );
void release();
}
The convinience operations include hasEntry (because context entries can be optional and its simply nicer to do this that wrap things in a try catch block and it is consitent with A4 service manager semantics; and includes a release() operation which is simply an instruction to the context to release all objects that hve been claimed by the client).
This would also give clear semantics to suspend() and resume(). To summarize, here's a crude example:
public class MyComponent implements ...
{
void initialize( Context ctx ) throws AppropriateException
{
Logger logger = (Logger) ctx.lookup("...");
Configuration conf = (Configuration) ctx.lookup("...");
serviceHandle = (Handle) ctx.lookup("...");
// etc...
}
void doSomething() throws Exception
{
Service service = null;
try {
service = (Service) serviceHandle.access();
// do something
} finally {
if (service != null) {
serviceHandle.release( service );
}
}
}
}
I think that's about it. Your turn :)
I prefer the notion of seperating out logging, configuration, context and initialization as seperate and destinct stages of a deployment phase. I do think (based on Merlin 2.1 experience) that there is a lot of benefit to be gained from comverging context and service manager into a single interface - in fact all of the internals of Merlin use an extended A4 Context interface which is basically providing this (note: this is a reversal of my prior position on service context seperation). However, we don't need to let this difference of opinion stand in the way :-) .. lets just call call this the deployment phase (see below).
The question of statup/suspend/resume/stop as you suggested above is a valid target for discussion. In particular, the distinction between initialize and start seems to me to be artificial . The same can be said for stop/dispose. Removing these artificial stages leaves you with something like the following:
[INSTANCE] ------ deployment -----> [INITIALIZED]
Component is taken through the stages necessary
to establish it as an initialized and available
object capable of performing whatever its work
interface exposes.
[INITIALIZED] ------ suspension ----> [SUSPENDED]
The action of suspending an initialized object
enabling modification of non-final artificates
established during deployment
[INITIALIZED] <----- resumption ----- [SUSPENDED]
Returning a suspended component to its normal
initialized state.
[INSTANCE] <-- decommissioning ---- [INITIALIZED]
Stripping down and disposing of the component.
The next open question conerns the semantics that are applicable during the suspended state. If we assume that we are dealing with meta enabled objects, a container can use meta information to determine what actions should/can be applied. If we asume that any artificate provided by a container to a component during the deployment phase is tagged as final or transient, we are heading into a rather nice scenario where suspension represents a state where an non-final artifcats can be reapplied to the component. This could include any of the artificats such as the logging channel, configuration, parteters, or context entries.
In the following example of a simple context defintion, I'm declaring the the name entry is non-final. I.e. this means that the component, if suspended, can be recontextualized during which the value returned from the name entry may be different. The component need not check final entries (because they will be unchanged).
<context>
<context key="urn:avalon:name" final="false"/>
<context key="urn:avalon:home" final="true"/>
</context>
This is also the principal reason why I've switchinged from pro context/service seperation to pro unification. In effect, I (as component author) am maintaining control over contract and I'm getting the container to do more work for me - and significantly reducing the number of lines of code I'm dealing with.
BTW, it's been a while since my previous posting, but I'm glad to see everyone's been busy ;) I still have some catching up to do, but I hope to be able to help with A5 (and Cocoon) implementation.
In you post you mention the Merlin Resource interface (Merlin 2.0). This has been the subject of some refactoring, the result of which is the redefintion of the abstraction as *Appliance*. In addition - the internals related to component assembly, lifecycle and lifestyle management of Merlin 2 have been seperated out into the assembly package in avalon-sandbox and the aspects concerning "containement" have been moved to the avalon-sandbox/merlin package.
Also, you may want to take a look at the Locator interface and related implementation in avalon-sandbox/assembly/src/..../locator/*.java.
Cheers, Steve.
(: A ;)
-- Stephen J. McConnell mailto:[EMAIL PROTECTED] http://www.osm.net -- To unsubscribe, e-mail: <mailto:[EMAIL PROTECTED]> For additional commands, e-mail: <mailto:[EMAIL PROTECTED]>
