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]>