mcconnell 2002/12/16 20:46:05
Modified: merlin/src/java/org/apache/avalon/merlin/container
Container.java ContainerLoader.java
DefaultContainer.java DefaultContainer.xinfo
Log:
Completed container based startup and shutdown of contained components.
Revision Changes Path
1.2 +22 -1
avalon-sandbox/merlin/src/java/org/apache/avalon/merlin/container/Container.java
Index: Container.java
===================================================================
RCS file:
/home/cvs/avalon-sandbox/merlin/src/java/org/apache/avalon/merlin/container/Container.java,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- Container.java 12 Dec 2002 00:34:49 -0000 1.1
+++ Container.java 17 Dec 2002 04:46:04 -0000 1.2
@@ -70,4 +70,25 @@
{
public static final String KEY = Container.class.getName();
public static final Version VERSION = Version.getVersion( "1.0" );
+
+ /**
+ * Assemble all of the componets in this container and invoke assembly on
+ * all subsidiary containers.
+ * @exception Exception if a assembly error occurs
+ */
+ void assemble() throws Exception;
+
+ /**
+ * Startup the components in this container and startup all subsidiary
+ * containers.
+ * @exception Exception if a startup error occurs
+ */
+ void startup() throws Exception;
+
+ /**
+ * Shutdown all subsidiary containers and all components in this container.
+ * @exception Exception if a shutdown error occurs
+ */
+ void shutdown() throws Exception;
+
}
1.3 +64 -16
avalon-sandbox/merlin/src/java/org/apache/avalon/merlin/container/ContainerLoader.java
Index: ContainerLoader.java
===================================================================
RCS file:
/home/cvs/avalon-sandbox/merlin/src/java/org/apache/avalon/merlin/container/ContainerLoader.java,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -r1.2 -r1.3
--- ContainerLoader.java 16 Dec 2002 01:09:47 -0000 1.2
+++ ContainerLoader.java 17 Dec 2002 04:46:04 -0000 1.3
@@ -55,6 +55,8 @@
import java.io.FileInputStream;
import java.io.InputStream;
import java.net.URL;
+import java.util.Map;
+import java.util.Hashtable;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.jar.JarFile;
@@ -95,6 +97,7 @@
import org.apache.avalon.assembly.engine.model.LibraryDescriptor;
import org.apache.avalon.assembly.engine.model.ClasspathDescriptor;
import org.apache.avalon.assembly.util.ExceptionHelper;
+import org.apache.excalibur.configuration.ConfigurationUtil;
/**
* An abstract utility class that provides support for
@@ -127,7 +130,7 @@
EngineClassLoader engine, String name, File home, Configuration config,
Logger logger )
throws Exception
{
- return createContainer( engine, name, home, config, logger, false );
+ return createContainer( engine, name, home, config, logger, null );
}
/**
@@ -138,12 +141,13 @@
* will be resolved
* @param config the container configuration
* @param logger the logging channel to assign to the container
+ * @param partition if null, this is a root container of a block in which case
+ * the block's engine, logging channel, and name are applied to the container
*/
protected Appliance createContainer(
- EngineClassLoader engine, String name, File home, Configuration config,
Logger logger, boolean flag )
+ EngineClassLoader engine, String name, File home, Configuration config,
Logger logger, String partition )
throws Exception
{
-
String classname = config.getAttribute( "class",
DefaultContainer.class.getName() );
Type type = engine.getRepository().getTypeManager().getType( classname );
ContainerDescriptor descriptor = CREATOR.createContainerDescriptor( type,
config, name );
@@ -152,46 +156,90 @@
for( int i=0; i<components.length; i++ )
{
Profile profile = createProfile( name, engine, components[i] );
+ engine.getRepository().getProfileManager().addProfile( profile );
descriptor.addComponent( profile );
- Appliance appliance = engine.createAppliance(
- new ApplianceContext( profile ), true );
}
+ ArrayList list = new ArrayList();
Configuration[] containers = config.getChildren( "container" );
for( int i=0; i<containers.length; i++ )
{
- Configuration childConfig = containers[i];
-
//
// create a classloader that will be supplied to the
// container (including resolution of the container level classpath
- // and extension path additions)
+ // and extension path additions), logger, and container name
//
+ Configuration childConfig = containers[i];
Configuration engineConfig = childConfig.getChild( "engine" );
String childName;
Logger childLogger;
EngineClassLoader childEngine;
- if( flag )
+ String childPartition;
+
+ if( partition == null )
{
childName = name;
childLogger = logger;
childEngine = engine;
+ childPartition = name;
}
else
{
childName = childConfig.getAttribute( "name", "untitled" );
childLogger = logger.getChildLogger( childName );
childEngine = childEngine = createChildEngine( engine, home,
childConfig, childLogger );
+ childPartition = partition + "/" + name;
}
- Appliance container = createContainer( childEngine, childName, home,
childConfig, childLogger );
- ContainerDescriptor containerDescriptor = (ContainerDescriptor)
container.getProfile();
- descriptor.addContainer( containerDescriptor );
- Appliance appliance = engine.createAppliance(
- new ApplianceContext( containerDescriptor ), true );
+ //
+ // recursively call this method to create the subsidiary containers
+ //
+
+ Appliance container =
+ createContainer(
+ childEngine, childName, home, childConfig, childLogger,
childPartition );
+ list.add( container );
+ }
+
+ //
+ // create the appliance context for the container
+ //
+
+ Map map = new Hashtable();
+ map.put("urn:assembly:engine.classloader", engine );
+ map.put("urn:merlin:container.containers", list );
+ map.put("urn:merlin:container.descriptor", descriptor );
+ if( partition != null )
+ {
+ map.put("urn:merlin:container.partition", partition );
+ }
+ else
+ {
+ map.put("urn:merlin:container.partition", "" );
+ }
+ ApplianceContext context = new ApplianceContext( descriptor );
+ context.setDeploymentContext( map );
+
+ if( partition != null )
+ {
+ context.setPartitionName( partition );
+ }
+
+ //
+ // create the containement appliance
+ //
+
+ try
+ {
+ return engine.createAppliance( context, false );
+ }
+ catch( Throwable e )
+ {
+ final String error =
+ "Unable to create containment appliance: " + name;
+ throw new ContainerException( error, e );
}
- return engine.createAppliance( new ApplianceContext( descriptor ), false );
}
protected Profile createProfile( String name, EngineClassLoader engine,
Configuration config )
1.2 +342 -4
avalon-sandbox/merlin/src/java/org/apache/avalon/merlin/container/DefaultContainer.java
Index: DefaultContainer.java
===================================================================
RCS file:
/home/cvs/avalon-sandbox/merlin/src/java/org/apache/avalon/merlin/container/DefaultContainer.java,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- DefaultContainer.java 12 Dec 2002 00:34:49 -0000 1.1
+++ DefaultContainer.java 17 Dec 2002 04:46:04 -0000 1.2
@@ -55,12 +55,24 @@
package org.apache.avalon.merlin.container;
+import java.util.List;
+import java.util.Iterator;
+import java.util.ArrayList;
+import java.util.Map;
+import java.util.Hashtable;
+
+import org.apache.avalon.assembly.engine.EngineClassLoader;
+import org.apache.avalon.assembly.appliance.Appliance;
+import org.apache.avalon.assembly.appliance.ApplianceContext;
+import org.apache.avalon.assembly.appliance.ApplianceException;
import org.apache.avalon.framework.logger.AbstractLogEnabled;
import org.apache.avalon.framework.context.Context;
import org.apache.avalon.framework.context.Contextualizable;
import org.apache.avalon.framework.context.ContextException;
+import org.apache.avalon.framework.activity.Disposable;
import org.apache.avalon.framework.activity.Initializable;
-import org.apache.avalon.assembly.engine.EngineClassLoader;
+import org.apache.avalon.merlin.container.ContainerDescriptor;
+import org.apache.avalon.meta.model.Profile;
/**
* <p>A container is node in a containment heirachy. It defines a scope
@@ -71,7 +83,8 @@
* @author <a href="mailto:[EMAIL PROTECTED]">Stephen McConnell</a>
* @version $Revision$ $Date$
*/
-public class DefaultContainer extends AbstractLogEnabled implements Container,
Contextualizable, Initializable
+public class DefaultContainer extends AbstractLogEnabled
+ implements Container, Contextualizable, Initializable, Disposable
{
//==============================================================
// state
@@ -79,6 +92,40 @@
private EngineClassLoader m_engine;
+ private ContainerDescriptor m_descriptor;
+
+ /**
+ * List of the appliance instances that the container is
+ * holding. Each appliance instance is a contained component.
+ */
+ private List m_components = new ArrayList();
+
+ /**
+ * List of the containment appliance instances that the container is
+ * holding. Each appliance instance is a subsidiary container.
+ */
+ private List m_containers;
+
+ /**
+ * Map of container objects keyed by containment appliance.
+ */
+ private Map m_containerMap = new Hashtable();
+
+ /**
+ * Map of components keyed by appliance.
+ */
+ private Map m_componentMap = new Hashtable();
+
+ /**
+ * Container partition name.
+ */
+ private String m_partition;
+
+ /**
+ * Container path name.
+ */
+ private String m_path;
+
//==============================================================
// Contextualizable
//==============================================================
@@ -92,6 +139,9 @@
public void contextualize( Context context ) throws ContextException
{
m_engine = (EngineClassLoader) context.get(
"urn:assembly:engine.classloader" );
+ m_containers = (List) context.get( "urn:merlin:container.containers" );
+ m_descriptor = (ContainerDescriptor) context.get(
"urn:merlin:container.descriptor" );
+ m_partition = (String) context.get( "urn:merlin:container.partition" );
}
//==============================================================
@@ -100,7 +150,295 @@
public void initialize() throws Exception
{
- getLogger().debug( "initialization" );
+ if( getLogger() == null )
+ {
+ throw new IllegalStateException("logger");
+ }
+ if( m_engine == null )
+ {
+ throw new IllegalStateException("context");
+ }
+
+ if( m_partition != null )
+ {
+ m_path = m_partition + "/" + m_descriptor.getName();
+ }
+ else
+ {
+ m_path = "/" + m_descriptor.getName();
+ }
+
+ if( getLogger().isDebugEnabled() )
+ {
+ getLogger().debug( "initialization: " + m_path );
+ }
+
+ Profile[] profiles = m_descriptor.getComponents();
+ for( int i=0; i<profiles.length; i++ )
+ {
+ Profile profile = profiles[i];
+ getLogger().debug( "creating appliance: " + profile );
+ ApplianceContext context = new ApplianceContext( profile );
+ context.setPartitionName( m_path );
+ Appliance appliance = createAppliance( context, true );
+ m_components.add( appliance );
+ }
+
+ Iterator iterator = m_containers.iterator();
+ while( iterator.hasNext() )
+ {
+ Appliance appliance = (Appliance) iterator.next();
+
+ if( getLogger().isDebugEnabled() )
+ {
+ final String message =
+ "activating container: [" + appliance.getProfile().getName() +
"]";
+ getLogger().debug( message );
+ }
+
+ try
+ {
+ Container container = (Container) appliance.access();
+ m_containerMap.put( appliance, container );
+ }
+ catch( Throwable e )
+ {
+ final String error =
+ "Could not establish a sub-container: "
+ + appliance.getProfile().getName()
+ + " in container: " + this;
+ throw new ContainerException( error, e );
+ }
+ }
+ }
+
+ /**
+ * Interception point in the component deployment process where specilization of
+ * this class can modify the criteria supplied under the appliance context. The
+ * default implementation invokes appliance creation on the service management
+ * engine and returns the non-assembled appliance result.
+ *
+ * @param context the appliance context
+ * @param shared boolean value indicating if the appliance is to be shared
+ * (i.e. available to other components as a depedency solution condidate)
+ * @return the new appliance
+ * @exception ApplianceException if an appliance creation error occurs
+ */
+ protected Appliance createAppliance( ApplianceContext context, boolean shared )
+ throws ApplianceException
+ {
+ return m_engine.createAppliance( context, shared );
+ }
+
+ /**
+ * Assemble all of the componets in this container and invoke assembly on
+ * all subsidiary containers.
+ * @exception Exception if a assembly error occurs
+ */
+ public void assemble() throws Exception
+ {
+ if( getLogger().isDebugEnabled() )
+ {
+ getLogger().debug( "assembly" );
+ }
+ assembleComponents();
+ assembleContainers();
+ }
+
+ /**
+ * Startup the components in this container.
+ * @exception Exception if a startup error occurs
+ */
+ protected void assembleComponents() throws Exception
+ {
+ Iterator iterator = m_components.iterator();
+ while( iterator.hasNext() )
+ {
+ Appliance appliance = (Appliance) iterator.next();
+ m_engine.assemble( appliance );
+ }
}
+ /**
+ * Invoke assembly on the nested containers in this container.
+ * @exception Exception if an assembly error occurs
+ */
+ protected void assembleContainers() throws Exception
+ {
+ Iterator iterator = m_containers.iterator();
+ while( iterator.hasNext() )
+ {
+ Appliance appliance = (Appliance) iterator.next();
+ Container container = (Container) m_containerMap.get( appliance );
+ container.assemble();
+ }
+ }
+
+ /**
+ * Startup the components in this container and startup all subsidiary
+ * containers.
+ * @exception Exception if a startup error occurs
+ */
+ public void startup() throws Exception
+ {
+ if( getLogger().isDebugEnabled() )
+ {
+ getLogger().debug( "startup" );
+ }
+ startupComponents();
+ startupContainers();
+ }
+
+ /**
+ * Startup the components in this container.
+ * @exception Exception if a startup error occurs
+ */
+ protected void startupComponents() throws Exception
+ {
+ Iterator iterator = m_components.iterator();
+ while( iterator.hasNext() )
+ {
+ Appliance appliance = (Appliance) iterator.next();
+
+ if( getLogger().isDebugEnabled() )
+ {
+ final String message =
+ "activating component: [" + appliance.getProfile().getName() +
"]";
+ getLogger().debug( message );
+ }
+
+ try
+ {
+ Object object = appliance.access();
+ m_componentMap.put( appliance, object );
+ }
+ catch( Throwable e )
+ {
+ final String error =
+ "Could not establish a component: "
+ + appliance.getProfile().getName()
+ + " in container: " + this;
+ throw new ContainerException( error, e );
+ }
+ }
+ }
+
+ /**
+ * Startup the containers in this container.
+ * @exception Exception if a startup error occurs
+ */
+ protected void startupContainers() throws Exception
+ {
+ Iterator iterator = m_containers.iterator();
+ while( iterator.hasNext() )
+ {
+ Appliance appliance = (Appliance) iterator.next();
+ Container container = (Container) m_containerMap.get( appliance );
+ try
+ {
+ container.startup();
+ }
+ catch( Throwable e )
+ {
+ final String error =
+ "Could not start a subsidiary container: "
+ + appliance.getProfile().getName()
+ + " in container: " + this;
+ throw new ContainerException( error, e );
+ }
+ }
+ }
+
+ /**
+ * Shutdown all subsidiary containers and all components in this container.
+ * @exception Exception if a shutdown error occurs
+ */
+ public void shutdown() throws Exception
+ {
+ if( getLogger().isDebugEnabled() )
+ {
+ getLogger().debug( "shutdown" );
+ }
+ shutdownContainers();
+ shutdownComponents();
+ }
+
+ /**
+ * Shutdown all subsidiary containers and all components in this container.
+ * @exception Exception if a shutdown error occurs
+ */
+ protected void shutdownComponents() throws Exception
+ {
+ Iterator iterator = m_components.iterator();
+ while( iterator.hasNext() )
+ {
+ Appliance appliance = (Appliance) iterator.next();
+ Object object = m_componentMap.get( appliance );
+ if( object != null )
+ {
+ if( getLogger().isDebugEnabled() )
+ {
+ final String message =
+ "stopping: " + appliance;
+ getLogger().debug( message );
+ }
+
+ m_componentMap.remove( appliance );
+ appliance.release( object );
+ appliance.terminate();
+ }
+ }
+ }
+
+ /**
+ * Shutdown the containers in this container.
+ * @exception Exception if a startup error occurs
+ */
+ protected void shutdownContainers() throws Exception
+ {
+ Iterator iterator = m_containers.iterator();
+ while( iterator.hasNext() )
+ {
+ Appliance appliance = (Appliance) iterator.next();
+ Container container = (Container) m_containerMap.get( appliance );
+ try
+ {
+ container.shutdown();
+ m_containerMap.remove( appliance );
+ appliance.release( container );
+ appliance.terminate();
+ }
+ catch( Throwable e )
+ {
+ final String error =
+ "Could not shutdown a subsidiary container: "
+ + appliance.getProfile().getName()
+ + " in container: " + this;
+ throw new ContainerException( error, e );
+ }
+ }
+ }
+
+ /**
+ * Disposal of the container.
+ */
+ public void dispose()
+ {
+ if( getLogger().isDebugEnabled() )
+ {
+ getLogger().debug( "disposal" );
+ }
+ m_engine = null;
+ m_descriptor = null;
+ m_componentMap.clear();
+ m_components.clear();
+ m_componentMap = null;
+ m_components = null;
+ m_containerMap.clear();
+ m_containers.clear();
+ m_containerMap = null;
+ m_containers = null;
+ m_partition = null;
+ m_path = null;
+ }
}
1.2 +5 -0
avalon-sandbox/merlin/src/java/org/apache/avalon/merlin/container/DefaultContainer.xinfo
Index: DefaultContainer.xinfo
===================================================================
RCS file:
/home/cvs/avalon-sandbox/merlin/src/java/org/apache/avalon/merlin/container/DefaultContainer.xinfo,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- DefaultContainer.xinfo 12 Dec 2002 00:34:49 -0000 1.1
+++ DefaultContainer.xinfo 17 Dec 2002 04:46:04 -0000 1.2
@@ -23,6 +23,11 @@
<context>
<entry key="urn:assembly:engine.classloader"
type="org.apache.avalon.assembly.engine.EngineClassLoader"/>
+ <entry key="urn:merlin:container.containers"
+ type="java.util.List"/>
+ <entry key="urn:merlin:container.descriptor"
+ type="org.apache.avalon.merlin.container.ContainerDescriptor"/>
+ <entry key="urn:merlin:container.partition"/>
</context>
</type>
--
To unsubscribe, e-mail: <mailto:[EMAIL PROTECTED]>
For additional commands, e-mail: <mailto:[EMAIL PROTECTED]>