mcconnell 2002/08/24 04:47:30
Modified: container build.xml default.properties
Added: container/src/xdocs attributes.xml extension.xml index.xml
list.xml menu.xml
Log:
xdocs for container package
Revision Changes Path
1.5 +5 -47 jakarta-avalon-excalibur/container/build.xml
Index: build.xml
===================================================================
RCS file: /home/cvs/jakarta-avalon-excalibur/container/build.xml,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -r1.4 -r1.5
--- build.xml 20 Aug 2002 23:52:18 -0000 1.4
+++ build.xml 24 Aug 2002 11:47:30 -0000 1.5
@@ -133,10 +133,10 @@
<!-- Creates all the Javadocs -->
<target name="javadocs" depends="compile" description="Generates the
javadocs" unless="skip.javadocs">
- <mkdir dir="${dist.javadocs}"/>
+ <mkdir dir="${build.javadocs}"/>
<javadoc packagenames="org.apache.*"
sourcepath="${java.dir}"
- destdir="${dist.javadocs}">
+ destdir="${build.javadocs}">
<classpath refid="project.class.path" />
<doclet name="com.sun.tools.doclets.standard.Standard">
<param name="-author"/>
@@ -287,65 +287,23 @@
<target name="dist.lite"
depends="dist-jar, test, javadocs"
description="Generates a minimal distribution (jar + javadocs)">
-
<copy file="../LICENSE.txt" todir="${dist.dir}"/>
<copy file="../KEYS" todir="${dist.dir}"/>
-
</target>
- <target name="anakia-avail">
- <available classname="org.apache.velocity.anakia.AnakiaTask"
- property="AnakiaTask.present">
- <classpath refid="tools.class.path"/>
- </available>
- </target>
-
- <target name="anakia-check" depends="anakia-avail"
unless="AnakiaTask.present">
- <echo>
- AnakiaTask is not present! Please check to make sure that
- velocity.jar is in your classpath. The easiest way to build
- the documentation is to checkout jakarta-site CVS and specify
- jakarta-site.dir property.
- </echo>
- </target>
-
- <target name="docs" depends="anakia-check" description="Generate
documentation and website">
- <taskdef name="anakia"
- classname="org.apache.velocity.anakia.AnakiaTask">
- <classpath refid="tools.class.path"/>
- </taskdef>
+ <target name="docs" depends="javadocs, xdocs" description="generates all
the Avalon documentation"/>
- <anakia basedir="${xdocs.dir}"
- destdir="${docs.dir}"
- style="docs.vsl"
- projectfile="stylesheets/project.xml"
- includes="**/*.xml"
- excludes="stylesheets/**"
-
velocitypropertiesfile="../site/src/stylesheets/velocity.properties"
- />
-
- <copy todir="${docs.dir}" filtering="off">
- <fileset dir="../site/src" includes="css/*.css" />
- <fileset dir="${xdocs.dir}">
- <include name="**/images/**"/>
- <include name="**/*.gif"/>
- <include name="**/*.jpg"/>
- <include name="**/*.png"/>
- <include name="**/*.css"/>
- <include name="**/*.js"/>
- </fileset>
- </copy>
+ <target name="xdocs" description="generates the xdocs-based
documentation">
+ <ant antfile="${basedir}/../cocoonbuild.xml"/>
</target>
<target name="site" depends="javadocs, docs" description=" Places Docs
ready for hosting on website">
-
<mkdir dir="../site/dist/docs/${dir-name}"/>
<copy todir="../site/dist/docs/${dir-name}">
<fileset dir="${docs.dir}">
<include name="**"/>
</fileset>
</copy>
-
</target>
<!-- Cleans up build and distribution directories -->
1.2 +2 -0 jakarta-avalon-excalibur/container/default.properties
Index: default.properties
===================================================================
RCS file: /home/cvs/jakarta-avalon-excalibur/container/default.properties,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- default.properties 20 Aug 2002 15:57:55 -0000 1.1
+++ default.properties 24 Aug 2002 11:47:30 -0000 1.2
@@ -39,6 +39,8 @@
build.classes = ${build.dir}/classes
build.tests = ${build.dir}/tests
build.reports = ${build.dir}/reports
+build.docs = ${build.dir}/docs
+build.javadocs = ${build.docs}/api
# Set the properties for source directories
src.dir = src
1.1
jakarta-avalon-excalibur/container/src/xdocs/attributes.xml
Index: attributes.xml
===================================================================
<?xml version="1.0"?>
<document>
<header>
<title>Attributes</title>
<authors>
<person name="Stephen McConnell" email="[EMAIL PROTECTED]"/>
</authors>
</header>
<body>
<s1 title="Overview">
<p>Within Avalon there are a number of different containers with
varying level of
consitency with respect to the naming of context keys and more recently
the subject
of meta-info attribute names and related semantics. The purpose of
this project
is to establish a common reference point for Avalon-wide container
norm. </p>
<p>This information should be considered as a proposal only.</p>
</s1>
<s1 title="Context Keys">
<p>The following context keys and associated values are considered to
be
applicable to all containers.</p>
<table>
<tr>
<td><p>Key</p></td>
<td><p>Type</p></td>
<td><p>Description</p></td>
</tr>
<tr>
<td>
<p><strong>avalon:home</strong></p>
</td>
<td>
<p><code>java.io.File</code></p>
</td>
<td>
<p>Declaration of a base working directory. A container is
responsible
for ensuring that the file referenced by the value refers to an
existing
directory.</p>
</td>
</tr>
</table>
</s1>
<s1 title="Type Attributes">
<p>The following attributes may be declared within the scope of the
component info block of the meta-info model.</p>
<table>
<tr>
<td><p>Key</p></td>
<td><p>Description</p></td>
</tr>
<tr>
<td>
<p><strong>avalon:lifestyle</strong></p>
</td>
<td>
<p>Declaration of the lifestyle handler to be applied by a
container
to a instance of the componet type. The mechanisms used to
construct and
and deploy and componet and the association of a lifestyle
handler are
container dependent. Containers providing support for the
following four
lifestyles include Fortress and Merlin.</p>
<p>
<table>
<tr>
<td>singleton</td>
<td>A single instance of the componet type will be shared
by all consumers.</td>
</tr>
<tr>
<td>thread</td>
<td>A new instance of the componet will be created
relative to each distinct thread.</td>
</tr>
<tr>
<td>pool</td>
<td>A container shall maintain a pool of componets.</td>
</tr>
<tr>
<td>transient</td>
<td>New instance of the component are created on a per
request basis.</td>
</tr>
</table>
</p>
</td>
</tr>
</table>
</s1>
</body>
<footer>
<legal>
Copyright (c) @year@ The Jakarta Apache Project All rights reserved.
$Revision: 1.1 $ $Date: 2002/08/24 11:47:30 $
</legal>
</footer>
</document>
1.1
jakarta-avalon-excalibur/container/src/xdocs/extension.xml
Index: extension.xml
===================================================================
<?xml version="1.0"?>
<document>
<header>
<title>Lifecycle Extensions</title>
<authors>
<person name="Marcus Crafter" email="[EMAIL PROTECTED]"/>
</authors>
</header>
<body>
<s1 title="What are lifecycle extensions ?">
<p>
Lifecycle extensions are additional stages a component can traverse
through during
it's lifetime. Lifecycle extensions allow a container to provide extra
functionality
to components in addition to the standard stages defined by Avalon
Framework.
</p>
<p>
Avalon Framework defines a set of standard interfaces often termed as
Lifecycle
stages that can be used by a container to determine the components
requirements
during deployment and subsequent decommissioning.
</p>
<p>
These interfaces allows the developer to separate the various concerns
involved when
writing a component. Often termed SoC and IoC (Separation of Concerns and
Inversion of
Control), these concepts represent one of the primary advantages of using
Avalon.
</p>
<p>
Sometimes it's useful to extend this development paradigm from the
framework level
into the application domain, to create customized lifecycle extensions
that are called
upon in addition to the standard set defined by the Avalon Framework.
</p>
<p>
Such custom lifecycle stages can further enable domain specific logic
across many,
perhaps even unrelated components, can reduce code duplication, and
allows the developer
to reuse the same development and thinking paradigm as the standard
lifecycle stages.
</p>
<p>
For example, you might want to pass a specialized SecurityManager to some
of your
components before they are initialized, or have their internal state
persistently cached
during system shutdown and restored at during startup. You might want to
pass user
dependent decryption keys to your component, or give components the
opportunity to
recycle themselves before being disposed or returned to a pooled
component handler.
</p>
<p>
The possibilities and number of extensions are only limited by the
requirements of your
particular application domain.
</p>
<p>
This document describes how to add new lifecycle extensions using
<strong>Fortress</strong>
and <strong>Merlin</strong> containers.
This document assumes a knowledge of what an Avalon lifecycle is, and a
basic understanding
of the standard lifecycle interfaces Avalon Framework defines. References
in this document to
Service and ServiceManager can also be freely interpreted as Component
and ComponentManager
by the reader.
</p>
<p>
<note>As at the time of writing, Fortress and Merlin is the only Avalon
container that
supports lifecycle extensions, which means components that use this
feature will not work
with the other Avalon containers (ExcaliburComponentManager, Phoenix,
Tweety, etc)</note>
</p>
<p>
Support for lifecycle extensions in the other Avalon containers is
technically possible but
has not yet been discussed. Please check with the Avalon developer
mailing list if you use
one of these containers and would like to use lifecycle extensions.
</p>
</s1>
<s1 title="How do I extend a Component's lifecycle ?">
<p>
Extending a Component's lifecycle is straightforward. An overview of the
process
follows:
</p>
<ol>
<li>Define the new component interface</li>
<p>
Create the new interface defining the operations that should be called
upon components
that implement this interface. Using the previously mentioned examples,
this would be
your <code>SecurityManageable</code>, <code>Cacheable</code>,
<code>Decryptable</code>,
<code>Recycleable</code> interfaces.
</p>
<li>Define an extension object that calls upon the methods defined in
the new interface,
during one or more of the pre-defined phases of component's
lifecycle</li>
<p>
Create a class that implements the <code>Creator</code> and/or
<code>Accessor</code>
interfaces and implemets the interaction with target components
supplied under the
create, destroy, access and relase operations.
</p>
<li>Register your extension object - this depedends on the container you
are using. In
Merlin you need to include the <extensions> tag in the component
.xinfo file and
Merlin will automatically recognize it. In Fortress you register the
extension object
with a <code>LifecycleExtensionManager</code></li>
<li>Implement the new component interface on your component</li>
<p>
Add the new <code>implements</code> clause to your Component, or
Component implementation,
and write any methods defined in the implemented interface.
</p>
<p>
Proceed as normal. Checking for extensions is done implicitly within
both Fortress and
Merlin. Once lifecycle extensions are registered they will be activated
during the 4
phases defined later in this document.
</p>
</ol>
</s1>
<s1 title="When can a Component's lifecycle be extended ?">
<p>
The life of any component can be broken down to the following phases:
</p>
<ol>
<li>Creation</li>
<p>
When the component is instantiated.
</p>
<li>Access</li>
<p>
When the component is accessed via a ServiceManager/Selector
(<code>lookup()/select()</code>).
</p>
<li>Release</li>
<p>
When the component is released via a ServiceManager/Selector
(<code>release()</code>).
</p>
<li>Destruction</li>
<p>
When the component is decommissioned, ready for garbage collection.
</p>
</ol>
<p>
<note>A component will go through it's Creation and Destruction phase
only once. Since
extension classes can implement different handling strategies (Poolable,
ThreadSafe,
etc), the access and release phases of a component can be applied
multiple times.</note>
</p>
<p>
Lifecycle extensions can be added to any of the above defined phases.
This allows
you to control the interception point your particular extension will be
applied under.
</p>
<p>
For example, thread or user dependent extensions would be added at the
access and release
levels (ie. when the component is retrieved and returned to the
ServiceManager) as they
depend on runtime data not available until they are actually used.
</p>
<p>
More static, or global extensions would be added at the creation or
destruction level, since
they do not depend on any external data that change during runtime, nor
are they particular
to any one context of use.
</p>
</s1>
<s1 title="Lifestyle Extension Interfaces">
<p>
A container manages extensions using an extension handler. Handlers
may implement
the <code>Creator</code> and/or <code>Accessor</code> interfaces. A
creator extension
will be activated during the create and destroy stages of a component
lifecycle. A
accessor extension will be activated during the access and release
stages.
</p>
<s2 title="The Creator Interface">
<p>The <code>Creator</code> interface describes the create and destroy
stages that occur between a component and a container
during service management. Lifecycle extensions supporting create
and destroy stages must implement this interface.</p>
<source>
package org.apache.excalibur.container.lifecycle;
import org.apache.avalon.framework.context.Context;
public interface Creator
{
/**
* Create stage handler.
*
* @param object the object that is being created
* @param context the context instance required by the create handler
* implementation
* @exception Exception if an error occurs
*/
void create( Object object, Context context )
throws Exception;
/**
* Destroy stage handler.
*
* @param object the object that is being destroyed
* @param context the context instance required by the handler
* implementation
*/
void destroy( Object object, Context context );
}
</source>
</s2>
<s2 title="Accessor Interface">
<p>
The <code>Accessor</code> interface describes the access and release
stages that occur between a service or component manager and a container
during service deployment. Lifecycle extensions supporting access
and release stages must implement this interface.
</p>
<source>
package org.apache.excalibur.container.lifecycle;
import org.apache.avalon.framework.context.Context;
public interface Accessor
{
/**
* Access stage handler.
*
* @param object the object that is being accessed
* @param context the context instance required by the access handler
* implementation
* @exception Exception if an error occurs
*/
void access( Object object, Context context )
throws Exception;
/**
* Release stage handler.
*
* @param object the object that is being released
* @param context the context instance required by the release handler
* implementation
*/
void release( Object object, Context context );
}
</source>
</s2>
</s1>
<s1 title="Fortress Example">
<p>
Let's look at a simple example. The following is also available as a
working sample
in Fortress' examples directory.
</p>
<p>
Our example implements a Lifecycle extension for passing a
<code>SecurityManager</code> to
Components. We'll call it the <code>SecurityManageable</code> interface.
</p>
<s2 title="Define the component extension interface">
<p>
First we define the new Component extension interface.
</p>
<source>
/**
* Simple custom lifecycle extension interface for supplying a component
* with a security manager.
*/
public interface SecurityManageable
{
/**
* Pass a SecurityManager object to the component
*
* @param manager a SecurityManager value
*/
void secure( SecurityManager manager )
throws SecurityException;
}
</source>
</s2>
<s2 title="Create the lifecycle extensions class">
<p>
Next we define the actual extension implementation which invokes the
<code>secure()</code>
method. We extend from <code>AbstractLifecycleExtension</code> since we
only want
<code>secure()</code> to be invoked upon each access (ie. lookup()) to
the component, and
don't need to implement the other 3 LifecycleExtension methods (create,
release, and
destroy).
</p>
<source>
/**
* Some custom extensions for this container's components.
*/
public class Extensions
extends AbstractLifecycleExtension
{
/**
* Access, called when the given component is being
* accessed (ie. via lookup() or select()).
*
* @param component a Component instance
* @param context a Context instance
* @exception Exception if an error occurs
*/
public void access( Object component, Context context )
throws Exception
{
if ( component instanceof SecurityManageable )
{
// pass in a simple security manager, a real system might want
to pass
// in specialized/custom security managers
( ( SecurityManageable ) component ).secure( new
SecurityManager() );
}
}
}
</source>
<p>
<note>An extension class may run components through any given number of
extensions, and are not limited to just one.</note>
</p>
</s2>
<s2 title="Register the lifecycle extensions class">
<p>
We then inform our container about the extension. This could be done in
several different
ways, for simplicity we'll extend <code>initialize()</code> and add it to
the
<code>LifecycleExtensionManager</code> there.
</p>
<p>
(an alternative might be to initialize a LifecycleExtensionManager before
creating the
container and pass it in via the
<code>ContextBuilder.setExtensionManager()</code> method,
or to create a LifecycleExtensionManager subclass that includes the
extension preset)
</p>
<source>
/**
* Simple container that includes custom lifecycle extensions.
*/
public final class ExtendedContainer
extends AbstractContainer
{
public void initialize()
throws Exception
{
super.initialize();
m_extManager.addExtension( new Extensions() );
}
}
</source>
</s2>
<s2 title="Use the new component interface">
<p>
To use the new SecurityManageable lifecycle extension, we simply implement
SecurityManageable just as we do with any other Avalon lifecycle
interfaces
(assuming a predefined Component interface
<code>ExtendedComponent</code>).
</p>
<source>
/**
* ExtendedComponentImpl, demonstrating the use of a custom
* lifecycle stage SecurityManageable. This code does
* a simple access check for several files on the file system and logs
* the results accordingly.
*/
public class ExtendedComponentImpl
extends AbstractLogEnabled
implements ExtendedComponent, SecurityManageable
{
/**
* Pass a SecurityManager object to the component
*
* @param manager a SecurityManager value
*/
public void secure( final SecurityManager manager )
throws SecurityException
{
getLogger().info( "Received SecurityManager instance: " + manager
);
final String[] files = { "/tmp", "/vmlinuz", "/usr/lib/libc.a" };
for ( int i = 0; i < files.length; ++i )
{
try
{
manager.checkRead( files[ i ] );
getLogger().info( "Thread can read " + files[ i ] );
}
catch ( SecurityException e )
{
getLogger().info( "Thread can not read " + files[ i ] );
}
}
}
}
</source>
</s2>
</s1>
<s1 title="Merlin Example">
<s2 title="Create your lifestyle stage interface">
<p>
The following interface is your domain specific lifecycle stage interface.
It is the interface that an extension handler will use to interact with your
component during deployment and decommissioning.
</p>
<source>
public interface Exploitable
{
/**
* Operation invoked by an exploitation manager.
* @param message a message to be displayed
*/
void exploit( String message );
}
</source>
</s2>
<s2 title="Create the lifestyle extension handler">
<p>
An extension handler is the implementation class that will be activated by
the Merlin container to handle domain specific tasks during the deployment and
decommissioning phases. The extension can implement etier or both of the
Creator and Accessor interfaces depeding on the particular extension
requirements. IN this example we are defining a simple creation stage handler
that supplies a message to an instance of Exploitable.
</p>
<source>
public class ExploitationManager implements Creator
{
/**
* Operation invoked by a container to request creation
* stage extension interception.
* @param object a component to manager
* @param context the context
*/
public void create( Object object, Context context )
{
if( object instanceof Exploitable )
{
((Expoitable)object).exploit( "hello" );
}
}
/**
* Operation invoked by a container to request destroy
* stage extension interception.
* @param object a component to manager
* @param context the context
*/
public void destroy( Object object, Context context )
{
}
}
</source>
<p>
To complete the defintion of you extension handler you need to prepare the
meta-info that will be used by Merlin to identify the extension and the stage
interface is supports. The following <type/> declaration includes an
<extensions/> tag that contains a <reference/> element that
includes the reference to the Explitable lifecycle stage interface. This is the
key that Merlin uses to associate a handler with a component. If you extension
class requires any specific context values, they should be declared in a
context element within the extension element.
</p>
<source>
<type>
<component>
<name>my-extension-handler</name>
</component>
<extensions>
<extension>
<name>exploitation</name>
<reference type="Exploitable" version="1.0"/>
</extension>
</extensions>
</type>
</source>
</s2>
<s2 title="Create a component implementing the stage interface">
<source>
public class MyComponent extends AbstractLogEnabled implements Exploitable
{
/**
* Operation invoked by an exploitation manager.
* @param message a message to be displayed
*/
public void exploit( String message )
{
getLogger().info( message );
}
}
</source>
<p>
To complete the defintion of your component you need to prepare the meta-info
that will be used by Merlin to identify the stage interface is requires a
handler for. The following <type/> declaration includes an
<stage/> tag that contains a <reference/> element that includes the
reference to the Exploitable lifecycle stage interface. This is the key that
Merlin uses to associate the component with a handler capable of handling the
Exploitable interface.
</p>
<source>
<type>
<component>
<name>my-component</name>
</component>
<stages>
<stage>
<name>exploit-me</name>
<reference type="Exploitable" version="1.0"/>
</stage>
</stages>
</type>
</source>
</s2>
<s2 title="Register you component and the extension">
<p>To complete the process you need to declare your handler and component in
a jar manifest file. The following entries show the declaration of the
component and the extension handler.</p>
<source>
Manifest-Version: 1.0
Created-By: Ant 1.5
Name: MyComponent.class
Avalon: Type
Name: ExploitationManager.class
Avalon: Type
</source>
</s2>
<s2 title="Execute the example">
<p>To execute the example you simply need to include a reference to you
component within a Merlin container declaration. The following XML source
declares a Merlin kernel, container, and component. You don't need to include
the handler because Merlin can sort that out itself based on the information
supplied in the meta-info declarations.</p>
<source>
<kernel>
<container name="my-container>
<classpath>
<fileset dir="lib">
<include name="my-domo.jar"/>
</fileset>
</classpath>
<component name="demo" class="MyComponent" activation="startup"/>
<container>
</kernel>
</source>
</s2>
</s1>
<s1 title="Need more information ?">
<p>
If you have any particular questions, comments, etc, please send an email
to the Avalon
developer mailing <link
href="mailto:[email protected]">list</link>.
</p>
</s1>
</body>
<footer>
<legal>
Copyright (c) @year@ The Jakarta Apache Project All rights reserved.
$Revision: 1.1 $ $Date: 2002/08/24 11:47:30 $
</legal>
</footer>
</document>
1.4 +27 -16 jakarta-avalon-excalibur/container/src/xdocs/index.xml
1.1 jakarta-avalon-excalibur/container/src/xdocs/list.xml
Index: list.xml
===================================================================
<?xml version="1.0"?>
<document>
<header>
<title>Mailing List</title>
<authors>
<person name="Stephen McConnell" email="[EMAIL PROTECTED]"/>
</authors>
</header>
<body>
<s1 title="Mailing Lists">
<p>
The Excalibur Container project is part of the Apache Avalon Project. The <a
href="http://jakarta.apache.org/site/mail2.html#Avalon">Avalon User list</a> is
available for general questions and queries relating to Avalon initiatives.
</p>
</s1>
</body>
<footer>
<legal>
Copyright (c) @year@ The Jakarta Apache Project All rights reserved.
$Revision: 1.1 $ $Date: 2002/08/24 11:47:30 $
</legal>
</footer>
</document>
1.1 jakarta-avalon-excalibur/container/src/xdocs/menu.xml
Index: menu.xml
===================================================================
<project name="Excalibur Container"
href="http://jakarta.apache.org/avalon/excalibur/container">
<title>Excalibur Container</title>
<body>
<menu name="Essentials">
<item name="Overview" href="index.html"/>
</menu>
<menu name="Facilities">
<item name="Extensions" href="extension.html"/>
<item name="Attributes" href="attributes.html"/>
</menu>
<menu name="Links">
<item name="Fortress"
href="http://jakarta.apache.org/avalon/excalibur/fortress/"/>
<item name="Merlin" href="http://jakarta.apache.org/avalon/merlin"/>
<item name="Mailing List" href="list.html"/>
</menu>
<menu name="Reference">
<item name="Container APIs" href="api/"/>
</menu>
</body>
</project>
--
To unsubscribe, e-mail: <mailto:[EMAIL PROTECTED]>
For additional commands, e-mail: <mailto:[EMAIL PROTECTED]>