As we start our journey, we have to ask ourselves exactly what problems
are we trying to solve? How are we making it easier for our users?
The answers to these questions will help shape our view of the next
generation of Avalon.
As I step back and look at all the different Avalon lifecycle stages,
I have to wonder if we need such granularity? Like all component
architectures we have the concept of initialization, active use, and
destruction of components. We are very fine grained on initialization,
and have a respectable view of destruction. Lets take a look at the
full lifecycle of a component should it ask for everything:
Initialization
--------------
LogEnabled.enableLogging()
Contextualizable.contextualize()
Composable.compose()/Serviceable.service()
Configurable.configure()
Parameterizable.parameterize()
Initializeable.initialize()
Startable.start()
Live Action
-----------
Suspendable.suspend()
Recontextualizable.recontextualize()
Recomposable.recompose()/Reserviceable.reservice() ??
Reconfigurable.reconfigure()
Reparameterizable.reparameterize()
Suspendable.resume()
Destruction
-----------
Startable.stop()
Disposable.dispose()
That's alot of stuff. When you sit back and think about it, we can
merge all the stages that pass in information. We can think of it
as a super-context, simple JNDI, or whatever you want. The basic
gist is that all of those pieces are associated with the same concern:
getting information to the component.
If we look at it as a simplified JNDI, we can pass in one context
and the component will be able to pick and choose what it wants.
If the component is sandboxed, it will receive a SecurityException
if it tries to do bad things. But we can discuss that later.
We also have some interfaces defined that we don't have any contracts
set up for, namely the re* interfaces. We kept them for legacy
purposes, but we never really supported them. If the component is
passed the super-context object, then if it wants to know when it
has new information available all it has to do is implement a listener
interface. Let's take a look at a possibility for a newer and simpler
lifecycle:
Initialization
--------------
Serviceable.service() // we can discuss what it looks like later
Initializable.initialize()
Transition
----------
Startable.start() // introduce the semantics of claiming resources
// within this method (i.e. can be restarted
// later)
Active Use
----------
Suspendable.suspend() // No resources are reclaimed, but
ServiceListener.serviceUpdated() // processing is stopped
Suspendable.resume()
Transition
----------
Startable.stop() // introduce the semantics of reclaiming resources
// within this method (i.e. can be restarted
// later)
Destruction
-----------
Disposable.dispose() // remove all the remaining resources and prepare
// for destruction
There are two major differences. There is a new overall phase
(Transition), which means the component can claim or release any
runtime resources that it will need for processing. This brings clarity
to the difference between Initializable/Disposable and Startable.
The second difference is that the Re* interfaces are now handled by
a ServiceListener class. It will receive ServiceEvents if the container
has new configuration information available for it, or a different
set of services available.
It is also important to note that Initializable/Disposable can only be
called once (each), and Startable can be called any number of times.
Startable.start() brings the component from Transition to Active Use,
and Startable.stop() brings the component from Active Use to Transition.
Once the component has been disposed, can never be brought back to
life.
If a component does not implement Startable, it never sees the
Transition phase. It makes it really simple to understand what the
component is doing at any one time.
Getting back to the Serviceable interface, we need to realize that now
it is not just making other components available. It is also making
the configuration information available. Below is only one possibility:
interface ServiceManager
{
Configuration getConfiguration();
void writeConfiguration(Configuration config)
throws ServiceUnavailableException;
Object lookup( String urn ); // context and service combined
Session getSession();
}
interface Session
{
Object get( Object key );
void put( Object key, Object value );
}
If we decide to make the configuration accessible via the lookup()
mechanism, then we should have a bind() operation so that a component
can record changes to its configuration while it is running.
The session concept is something we can toy with later if we think
it would be a bad thing to place it here.
An alternative would be:
interface ServiceManager
{
Object lookup( String urn ) throws NoSuchValueException;
void bind( String urn, Object value )
throws AlreadyBoundException;
}
Any thoughts or inputs?
---------------------------------------------
Introducing NetZero Long Distance
1st month Free!
Sign up today at: www.netzerolongdistance.com
--
To unsubscribe, e-mail: <mailto:[EMAIL PROTECTED]>
For additional commands, e-mail: <mailto:[EMAIL PROTECTED]>