|
Jakarta main
Avalon main
About
Overview
Changes
API Docs
Patterns and Design
Patterns
Reuse Standards
Inversion of Control
Separation of Concerns
Security
The API
What is a Component?
What is a Composer?
The Component Lifecycle
Designing a Component
|
Avalon Component Developers Documentation
: The Component Lifecycle
|
Introduction |
A Component lives within something called a container. Avalon provides an
application that functions as a container for Applications (which are
Components) called Phoenix.
You can also create your own Components that function as a container.
The contract between a container and a contained Component is simple: the
container is required to take a Component through what is called its
lifecycle.
|
The Lifecycle |
The lifecycle of a Component specifies the methods that can be called on it,
and the order in which this may happen. Some methods can be called only once
in a specific Phase of a Component its lifecycle, others may
be called multiple times. These methods are called the lifecycle methods.
It is up to each container to indicate which lifecycle methods it will honor.
This should be clearly documented together with the description of the
container. Phoenix supports all of the lifecycle methods defined in the
Avalon Framework API.
|
The Lifecycle interfaces |
A Component exposes its lifecycle methods by implementing the lifecycle
interfaces. Each of these defines one or more methods that represent a
specific Phase in a Component's lifecycle. The defined interfaces are:
- Loggable
- Contextualizable
- Composable
- Configurable
- Parameterizable
- Initializable
- Executable
- Interruptable
- Recontextualizable
- Recomposable
- Reconfigurable
- Reparameterizable
- Stoppable
- Disposable
Note:Executable replaces the deprecated Startable/Stoppable duo.
Interruptable replaces the deprecated Suspendable/Resumable duo.
Note:java.lang.Runnable has also been in use as a lifecycle
interface. This is not recommended and is not supported by Avalon. Instead,
the run() method is the responsibility of the Component itself. If you wish
to use it, call it from within start() or another method.
|
Phase order |
The order in which the various lifecycle methods are called is very specific.
While none are required (it is possible to have a Component implementing
none of the lifecycle methods, although the use of that would be limited),
some can only be used when others are as well. This is best explained using
a few examples.
simple examples |
The lifecycle of a Component implementing only Configurable for
example will be:
- constructor
- configure
- finalize
The lifecycle of a Component implementing only Composer will be:
- constructor
- compose
- finalize
|
complete |
If a Component implements more than one interface the order of
the events (compose, configure etc.) follow a specific order. A Component
implementing all above interfaces (including Runnable) will follow this
specific path:
- constructor
- contextualize
- compose
- configure
- parameterize
- initialize
- start
- run
-
- suspend
- recontextualize
- recompose
- reconfigure
- reparameterize
- resume
- stop
- dispose
- finalize
|
Phases executed once |
These lifecycle methods are only called once in the entire life of a
Component:
- contextualize
- compose
- configure
- parameterize
- initialize
- dispose
|
Phases executed once or more |
These lifecycle methods are called at least once and possibly more, depending
on the container:
|
The Interruptable phase |
The methods suspend() and resume() are not guaranteed to be called at all,
even when implemented. They can be called more than once, but only after
one another and between start() (or run() when used) and stop(). The reason
they exist is so the container can notify the Component it
needs to come to temporary stop any operations. The container may need to
perform some synchronized operation on one of the Components used by this
Component, or it may wish to call any of the following methods, which can
also be called zero or more times, and only between a suspend() and a resume().
- recontextualize()
- recompose()
- reconfigure()
- reparameterize()
|
The Command Pattern |
The most advanced, most complicated and most flexible option is to use
the Command pattern by having your Component implement the Commandable
interface. This is experimental; you'll find the Commandable and its
related classes in the excalibur package.
It is recommended that if your Component implements Commandable, it should
not implement Executable or Interruptable. When you do choose to combine the
two, the order in which the different steps must happen is very specific:
// inside container...
// ...
myComponent.initialize();
myComponent.start();
Iterator commands = myComponent.getCommands();
runAll(commands);
myComponent.suspend();
myComponent.resume();
myComponent.suspend();
myComponent.resume();
myComponent.stop();
myComponent.dispose();
// ...
// on shutdown...
stopAll(commands);
commands = null;
myComponent = null;
System.gc(); // finalize() is called on myComponent, which allows it to perform some
// final operation on its Commands.
The advantage of using Commands is that you can have multiple processes running
outside your Component that can manipulate it. These will run until completion
even if you Component has already been disposed of.
You should note that the Command interface we use extends Runnable, which means
Commands can be (and usually are) run() using standard pooling utilities for
threads.
|
|
| by
Berin Loritsch, Peter Donald, Leo Simons |
|