mcconnell    2003/01/15 01:14:52

  Modified:    merlin   .cvsignore blocks.xml build.xml default.properties
                        kernel.xml merlin.properties
               merlin/src/java/org/apache/avalon/merlin/block Block.java
                        DefaultBlock.java
               merlin/src/java/org/apache/avalon/merlin/container
                        Container.java ContainerLoader.java
                        DefaultContainer.java DefaultContainer.xinfo
                        StateEvent.java
               merlin/src/java/org/apache/avalon/merlin/kernel
                        DefaultKernel.java KernelLoader.java
               merlin/src/test/config block.xml
               merlin/src/test/org/apache/avalon/playground
                        StandardComponent.java
  Removed:     merlin   external.xml
  Log:
  Rationalization of the containment strategy enabling simplicifation of the
  container interface and better seperation of container concerns (under Block)
  as distinct from runtime managemnt (uner Container).
  
  Revision  Changes    Path
  1.3       +1 -0      avalon-sandbox/merlin/.cvsignore
  
  Index: .cvsignore
  ===================================================================
  RCS file: /home/cvs/avalon-sandbox/merlin/.cvsignore,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- .cvsignore        3 Dec 2002 07:08:02 -0000       1.2
  +++ .cvsignore        15 Jan 2003 09:14:50 -0000      1.3
  @@ -7,3 +7,4 @@
   extensions
   distributions
   common
  +working
  \ No newline at end of file
  
  
  
  1.3       +14 -10    avalon-sandbox/merlin/blocks.xml
  
  Index: blocks.xml
  ===================================================================
  RCS file: /home/cvs/avalon-sandbox/merlin/blocks.xml,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- blocks.xml        28 Dec 2002 01:35:38 -0000      1.2
  +++ blocks.xml        15 Jan 2003 09:14:50 -0000      1.3
  @@ -3,22 +3,26 @@
   The blocks.xml file contains the declaration of the blocks to be loaded
   and assembled by the kernel.  Each block element declares a block name,
   a path to a single jar file, an engine configuration (which may 
  -include declaration of additional extension directories and a block 
  -classpath), anad tagged configuration fragments.
  +include declaration of additional extension directories a block 
  +classpath), and tagged configuration fragments.
   -->
   
   <blocks>
   
  -   <!--
  -   DEV NOTE: - Path statements need to declared as just the filename and 
  -   the kernel should be resonsible for resolving the full path.  The current
  -   inclusion of a directory is temporary because it is making assumptions 
  -   about the deployment context.
  -   -->
  +   <block name="james" src="src/test/config/james.xml" enabled="false" >
  +     <configuration target="dns">
  +        <servers>
  +          <server>212.198.0.66</server>
  +          <server>212.198.0.67</server>
  +          <server>194.51.32.65</server>
  +        </servers>
  +        <authoritative>false</authoritative>
  +      </configuration>
  +   </block>
   
  -   <block name="playground" 
path="../assembly/build/lib/avalon-assembly-demo-1.0.jar"/>
  +   <block name="playground" 
path="../assembly/build/lib/avalon-assembly-demo-1.0.jar" enabled="true"/>
   
  -   <block name="demo" path="../merlin/build/lib/avalon-merlin-demo-1.0.jar">
  +   <block name="demo" path="../merlin/build/lib/avalon-merlin-demo-1.0.jar" 
enabled="true">
        <configuration target="test">
          <configuration target="standard">
            <message>Client supplied message.</message>
  
  
  
  1.10      +6 -2      avalon-sandbox/merlin/build.xml
  
  Index: build.xml
  ===================================================================
  RCS file: /home/cvs/avalon-sandbox/merlin/build.xml,v
  retrieving revision 1.9
  retrieving revision 1.10
  diff -u -r1.9 -r1.10
  --- build.xml 7 Jan 2003 04:24:16 -0000       1.9
  +++ build.xml 15 Jan 2003 09:14:50 -0000      1.10
  @@ -28,6 +28,7 @@
       <pathelement location="${avalon-assembly.jar}"/>
       <pathelement location="${excalibur-logger.jar}"/>
       <pathelement location="${excalibur-configuration.jar}"/>
  +    <pathelement location="${excalibur-pool.jar}"/>
       <pathelement location="${excalibur-thread.jar}"/>
       <pathelement location="${excalibur-event.jar}"/>
       <pathelement location="${util.concurrent.jar}"/>
  @@ -204,17 +205,20 @@
        <mkdir dir="${common.dir}"/>
        <copy todir="${common.dir}" file="${avalon-framework.jar}"/>
        <copy todir="${common.dir}" file="${excalibur-i18n.jar}"/>
  -     <copy todir="${common.dir}" file="${excalibur-configuration.jar}"/>
        <copy todir="${common.dir}" file="${avalon-meta.jar}"/>
        <copy todir="${common.dir}" file="${logkit.jar}"/>
  +     <copy todir="${common.dir}" file="${excalibur-configuration.jar}"/>
   
        <mkdir dir="${lib.dir}"/>
        <copy todir="${lib.dir}" file="${build.lib}/${jar.name}"/>
  +     <copy todir="${lib.dir}" file="${excalibur-collections.jar}"/>
        <copy todir="${lib.dir}" file="${excalibur-extension.jar}"/>
        <copy todir="${lib.dir}" file="${excalibur-logger.jar}"/>
        <copy todir="${lib.dir}" file="${excalibur-event.jar}"/>
        <copy todir="${lib.dir}" file="${commons-collections.jar}"/>
        <copy todir="${lib.dir}" file="${util.concurrent.jar}"/>
  +     <copy todir="${lib.dir}" file="${excalibur-threadcontext.jar}"/>
  +     <copy todir="${lib.dir}" file="${excalibur-pool.jar}"/>
        <copy todir="${lib.dir}" file="${excalibur-thread.jar}"/>
        <copy todir="${lib.dir}" file="${avalon-lifecycle.jar}"/>
        <copy todir="${lib.dir}" file="${avalon-assembly.jar}"/>
  @@ -414,7 +418,7 @@
          debug="${build.debug}"
          optimize="${build.optimize}"
          deprecation="${build.deprecation}"
  -       target="1.2">
  +       target="1.3">
          <classpath refid="project.class.path" />
          <include name="**/playground/*.java"/>
       </javac>
  
  
  
  1.6       +19 -4     avalon-sandbox/merlin/default.properties
  
  Index: default.properties
  ===================================================================
  RCS file: /home/cvs/avalon-sandbox/merlin/default.properties,v
  retrieving revision 1.5
  retrieving revision 1.6
  diff -u -r1.5 -r1.6
  --- default.properties        6 Jan 2003 01:05:53 -0000       1.5
  +++ default.properties        15 Jan 2003 09:14:50 -0000      1.6
  @@ -8,7 +8,7 @@
   name=avalon-merlin
   Name=Merlin Service Management System
   dir-name=merlin
  -version=2.1
  +version=1.0
   package-version=2.1
   demo-version=1.0
   year=2002
  @@ -72,10 +72,25 @@
   
commons-collections.jar=${excalibur-event.home}/lib/commons-collections-20021002.jar
   
   # ----- Excalibur thread, version 1.0 or later -----
  +excalibur-collections.home=${excalibur.home}/collections
  +excalibur-collections.lib=${excalibur-collections.home}/build/lib
  
+excalibur-collections.jar=${excalibur-collections.lib}/excalibur-collections-1.0.jar
  +
  +# ----- Excalibur thread, version 1.0 or later -----
   excalibur-thread.home=${excalibur.home}/thread
   excalibur-thread.lib=${excalibur-thread.home}/build/lib
   excalibur-thread.jar=${excalibur-thread.lib}/excalibur-thread-1.0.jar
   
  +# ----- Excalibur threadcontext, version 1.0 or later -----
  +excalibur-threadcontext.home=${excalibur.home}/threadcontext
  +excalibur-threadcontext.lib=${excalibur-threadcontext.home}/build/lib
  
+excalibur-threadcontext.jar=${excalibur-threadcontext.lib}/excalibur-threadcontext-1.0.jar
  +
  +# ----- Excalibur pool -----
  +excalibur-pool.home=${excalibur.home}/pool
  +excalibur-pool.lib=${excalibur-pool.home}/build/lib
  +excalibur-pool.jar=${excalibur-pool.lib}/excalibur-pool-1.1.jar
  +
   # ----- Logkit -----
   logkit.home=${basedir}/../../jakarta-avalon-logkit
   logkit.lib=${logkit.home}/build/lib
  @@ -123,8 +138,8 @@
   dist.name = ${name}-${version}
   
   #  name of jar file
  -jar.name = ${name}-${version}.jar
  -bootstrap.jar = ${name}-bootstrap-${version}.jar
  +jar.name = ${name}-${package-version}.jar
  +bootstrap.jar = ${name}-bootstrap-${package-version}.jar
   
   #  property indicating directory where all distribution archives are placed
   dist.base = distributions
  @@ -135,7 +150,7 @@
   lib.dir = lib
   demo.name = demo
   demo.jar = ${name}-${demo.name}-${demo-version}.jar
  -sar.name = ${name}-${version}.sar
  +sar.name = ${name}-${package-version}.sar
   
   # misc.
   
  
  
  
  1.13      +11 -23    avalon-sandbox/merlin/kernel.xml
  
  Index: kernel.xml
  ===================================================================
  RCS file: /home/cvs/avalon-sandbox/merlin/kernel.xml,v
  retrieving revision 1.12
  retrieving revision 1.13
  diff -u -r1.12 -r1.13
  --- kernel.xml        9 Jan 2003 03:59:39 -0000       1.12
  +++ kernel.xml        15 Jan 2003 09:14:50 -0000      1.13
  @@ -1,37 +1,25 @@
   
   <kernel>
   
  -   <system host="localhost">
  -     <configuration path="configuration.xml"/>
  -   </system>
  +   <!-- 
  +   The kerenel can contain the following declarations:
  +   1. a system descriptor
  +   2. a logging descriptor
  +   3. a logging catagories descriptor that establishes logging priority
  +      for the kernel messages
  +   4. an engine descriptor
  +   -->
  +
  +   <system host="localhost"/>
   
      <logging target="default" priority="DEBUG">
         <category name="/sys/logger" priority="WARN"/>
  -      <!--
  -      <target name="default">
  -        <file location="kernel.log" />
  -      </target>
  -      -->
      </logging>
   
      <categories>
         <category name="/sys" priority="INFO"/>
      </categories>
   
  -   <!--
  -   Definition of the root engine classloader.
  -   -->
  -   <!--
  -   <engine>
  -     <library dir=".">
  -       <include name="some-additional-extension-dir"/>
  -     </library>
  -     <classpath>
  -       <fileset dir="some-directory">
  -         <include name="something.jar"/>
  -       </fileset>
  -     </classpath>
  -   </engine>
  -   -->
  +   <engine/>
   
   </kernel>
  
  
  
  1.2       +2 -2      avalon-sandbox/merlin/merlin.properties
  
  Index: merlin.properties
  ===================================================================
  RCS file: /home/cvs/avalon-sandbox/merlin/merlin.properties,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- merlin.properties 6 Jan 2003 01:05:53 -0000       1.1
  +++ merlin.properties 15 Jan 2003 09:14:50 -0000      1.2
  @@ -34,7 +34,7 @@
   # Filename of the blocks configuration.  The file will be resolved relative
   # to the Merlin home directory. The default value is [blocks.xml]
   #
  -#merlin.blocks.xml=blocks.xml
  +#merlin.blocks.xml=./blocks.xml
   
   # 
   # merlin.bootstrap.debug
  @@ -42,6 +42,6 @@
   # of a logger) will be sent to System.out.  If false, not bootstrap messages 
will 
   # be displayed. Default value is false.
   #
  -#merlin.bootstrap.debug=false
  +merlin.bootstrap.debug=false
   
   
  
  
  
  1.8       +20 -5     
avalon-sandbox/merlin/src/java/org/apache/avalon/merlin/block/Block.java
  
  Index: Block.java
  ===================================================================
  RCS file: 
/home/cvs/avalon-sandbox/merlin/src/java/org/apache/avalon/merlin/block/Block.java,v
  retrieving revision 1.7
  retrieving revision 1.8
  diff -u -r1.7 -r1.8
  --- Block.java        9 Jan 2003 11:26:25 -0000       1.7
  +++ Block.java        15 Jan 2003 09:14:51 -0000      1.8
  @@ -67,25 +67,40 @@
       static final String AVALON_BLOCK_KEY = "Avalon-Block";
   
      /**
  +    * Deploy the block during which appliances managed by the block
  +    * will be established as executing components.
  +    *
  +    * @exception Exception if a deployment error occurs
  +    */
  +    void deploy() throws Exception;
  +
  +   /**
  +    * Decommission the block.
  +    *
  +    * @exception Exception if a deployment error occurs
  +    */
  +    void decommission() throws Exception;
  +
  +   /**
       * Startup the block and startup all subsidiary blocks.
       * @exception Exception if a startup error occurs
       */
  -    void startup() throws Exception;
  +    //void startup() throws Exception;
   
      /**
       * Suspend the block and all subsidiary blocks.
       */
  -    void suspend();
  +    //void suspend();
   
      /**
       * Resume the block and all subsidiary blocks.
       */
  -    void resume();
  +    //void resume();
   
      /**
       * Shutdown the block.
       * @exception Exception if a shutdown error occurs
       */
  -    void shutdown() throws Exception;
  +    //void shutdown() throws Exception;
   
   }
  
  
  
  1.13      +508 -141  
avalon-sandbox/merlin/src/java/org/apache/avalon/merlin/block/DefaultBlock.java
  
  Index: DefaultBlock.java
  ===================================================================
  RCS file: 
/home/cvs/avalon-sandbox/merlin/src/java/org/apache/avalon/merlin/block/DefaultBlock.java,v
  retrieving revision 1.12
  retrieving revision 1.13
  diff -u -r1.12 -r1.13
  --- DefaultBlock.java 9 Jan 2003 11:26:25 -0000       1.12
  +++ DefaultBlock.java 15 Jan 2003 09:14:51 -0000      1.13
  @@ -6,6 +6,7 @@
   import java.io.IOException;
   import java.net.URL;
   import java.util.List;
  +import java.util.Iterator;
   import java.util.ArrayList;
   import java.util.jar.Attributes;
   import java.util.jar.Manifest;
  @@ -17,6 +18,7 @@
   import org.apache.avalon.assembly.appliance.DefaultAppliance;
   import org.apache.avalon.assembly.appliance.ApplianceContext;
   import org.apache.avalon.assembly.appliance.ApplianceException;
  +import org.apache.avalon.assembly.appliance.DependencyGraph;
   import org.apache.avalon.assembly.engine.EngineClassLoader;
   import org.apache.avalon.assembly.locator.Locator;
   import org.apache.avalon.assembly.locator.Contextualizable;
  @@ -24,6 +26,7 @@
   import org.apache.avalon.assembly.lifestyle.LifestyleService;
   import org.apache.avalon.assembly.lifecycle.AssemblyService;
   import org.apache.avalon.assembly.lifecycle.AssemblyException;
  +import org.apache.avalon.assembly.util.ExceptionHelper;
   import org.apache.avalon.framework.logger.Logger;
   import org.apache.avalon.framework.logger.AbstractLogEnabled;
   import org.apache.avalon.framework.activity.Initializable;
  @@ -44,6 +47,10 @@
   import org.apache.avalon.meta.info.DependencyDescriptor;
   import org.apache.avalon.meta.model.builder.XMLProfileCreator;
   import org.apache.avalon.meta.model.Profile;
  +import org.apache.avalon.merlin.service.Registry;
  +import org.apache.avalon.merlin.kernel.DefaultKernel;
  +import org.apache.avalon.assembly.appliance.DefaultApplianceContext;
  +import org.apache.excalibur.configuration.ConfigurationUtil;
   
   /**
    * The default implementation of a Block.  The implementation provides 
  @@ -61,6 +68,10 @@
       public static final Attributes.Name BLOCK_PACKAGE = new Attributes.Name( 
"Block-Package" );
       public static final Attributes.Name OLD_BLOCK_NAME = new 
Attributes.Name( "Block-Name" );
   
  +    private static final int DISASSEMBLED = 1000;
  +    private static final int TERMINATED = 2000;
  +    private static final int DISPOSED = 3000;
  +
       public static String getPackageName( Manifest manifest )
       {
           Attributes attributes = manifest.getAttributes( 
Block.AVALON_BLOCK_KEY );
  @@ -93,6 +104,9 @@
       // state
       
//-------------------------------------------------------------------------------
   
  +   /**
  +    * The engine classloader.
  +    */
       EngineClassLoader m_engine;
   
      /**
  @@ -134,6 +148,74 @@
        */
       private BlockException m_error;
   
  +    /**
  +     * The apliance context.
  +     */
  +    private ApplianceContext m_applianceContext;
  +
  +   /**
  +    * The container meta info descriptor.
  +    */
  +    private ContainerDescriptor m_descriptor;
  +
  +   /**
  +    * The block configuration.
  +    */
  +    private Configuration m_config;
  +
  +   /**
  +    * The service registry assigned to the block.
  +    */
  +    private Registry m_registry;
  +
  +   /**
  +    * List of the appliance instances that the block is 
  +    * managing.
  +    */
  +    private List m_appliances = new ArrayList();
  +
  +   /**
  +    * List of the subsidiary blocks.
  +    */
  +    private List m_blocks = new ArrayList();
  +
  +   /**
  +    * Map of container objects keyed by block.
  +    */
  +    private Map m_containers = new Hashtable();
  +
  +   /**
  +    * Reference to the set of appliances to be terminated.  The set 
  +    * appliances is based on the shutdown graph resolved during the 
  +    * disassembly phase.
  +    */
  +    private Appliance[] m_shutdown;
  +
  +   /**
  +    * List of the commonents that have been established explicity by the 
  +    * block during deployment.
  +    */
  +    private Map m_components = new Hashtable();
  +
  +   /**
  +    * Flag holding the deoplyed state of the block.
  +    */ 
  +    private boolean m_deployed = false;
  +
  +   /**
  +    * Flag holding the decommissioned state of the block.
  +    */ 
  +    private boolean m_decommissioned = false;
  +
  +   /**
  +    * Flag holding the disassembled state of the block.
  +    */ 
  +    private boolean m_disassembled = false;
  +
  +   /**
  +    * Flag holding the terminated state of the block.
  +    */ 
  +    private boolean m_terminated = false;
   
       //=====================================================================
       // Contextualizable
  @@ -148,12 +230,23 @@
       {
           super.contextualize( context );
           m_engine = (EngineClassLoader) context.get( "urn:assembly:engine" );
  +        m_applianceContext = (ApplianceContext) context.get( 
"urn:assembly:appliance.context" );
  +        m_descriptor = (ContainerDescriptor) context.get( 
"urn:merlin:container.descriptor" );
  +        m_registry = (Registry) context.get( "urn:merlin:container.registry" 
);
  +        m_config = (Configuration) context.get( 
"urn:merlin:container.configuration" );
  +        m_blocks = (List) context.get( "urn:merlin:container.containers" );
       }
   
       //=====================================================================
       // Initializable
       //=====================================================================
   
  +   /**
  +    * Initialization of the blocks during which appliance instances managed 
by the blocks
  +    * will be established.
  +    *
  +    * @exception Exception if a block initialization error occurs
  +    */
       public void initialize() throws Exception
       {
           super.initialize();
  @@ -161,162 +254,237 @@
           {
               throw new IllegalStateException( "context" );
           }
  -        m_thread = new Thread( this, super.getPath() );
  -        m_thread.setContextClassLoader( m_engine );
  -        m_thread.start();
  -    }
  + 
  +        //
  +        // construct the appliance instances managed by this block
  +        //
  +
  +        Profile[] profiles = m_descriptor.getComponents();
  +        for( int i=0; i<profiles.length; i++ )
  +        {
  +            Profile profile = profiles[i];
  +            if( getLogger().isDebugEnabled() )
  +            {
  +                final String message = "profile: " + profile; 
  +                getLogger().debug( message );
  +            }
  +
  +            Configuration config = 
  +               DefaultKernel.getNamedConfiguration( m_config, 
profile.getName() );
  +
  +            DefaultApplianceContext context = 
  +               new DefaultApplianceContext( profile );
  +            context.setPartitionName( getPath() );
  +            context.setConfiguration( config );
  +            context.makeReadOnly();
  +
  +            Appliance appliance = m_engine.createAppliance( context, true );
  +            m_appliances.add( appliance );
  +            m_registry.bind( appliance );
  +        }
  +   }
   
       
//-------------------------------------------------------------------------------
  -    // Runnable
  +    // Appliance
       
//-------------------------------------------------------------------------------
   
  -    /**
  -     * Starts the thread of execution for the block.  This operation is
  -     * invoked by the container constructor.
  -     */
  -    public void run()
  +   /**
  +    * Assemble the appliance.  The implementation extends the default 
  +    * appliance behavior by instantiating the container it is managing, 
  +    * and applying assembly to the container instance. This results in 
  +    * container creating appliance instances for the component is is 
  +    * managing together with assembly of its sub-containers.
  +    *
  +    * @exception AssemblyException if an error occurs during appliance 
assembly
  +    */
  +    public void assemble( DependencyGraph graph ) throws AssemblyException
       {
  -        if( !m_running )
  +        if( m_assembled )
           {
  -            m_running = true;
  +            return;
  +        }
  +
  +        if( getLogger().isDebugEnabled() )
  +        {
  +            getLogger().debug("block assembly: " + System.identityHashCode( 
graph ) );
           }
   
  +        //
  +        // add the dependecy graph to the context that will be used to 
establish
  +        // the container so that the container can handle orderly startup 
and 
  +        // shutdown of compoents
  +        //
  + 
  +        Map context = m_applianceContext.getDeploymentContext();
  +        context.put( "urn:merlin:container.dependency-graph", graph );
  +        context.put( "urn:merlin:container.listener", this );
  +
  +        //
  +        // assemble the components handled by the block
  +        //
  +
           try
           {
  +            assembleComponents( graph );
  +        }
  +        catch( AssemblyException e )
  +        {
  +            final String error = 
  +              "Assembly failure attributable to embedded appliance.";
  +            throw new AssemblyException( error, e );
  +        }
   
  -            //
  -            // while desired state of the hosted container is something
  -            // other than DISPOSED, check if the desired state is different
  -            // from the current state reported by the container, and if
  -            // so initiate a container state change
  -            //
  +        //
  +        // assemble the subsidiary blocks
  +        //
   
  -            while( m_action.intValue() < StateEvent.DISPOSED )
  +        Iterator iterator = m_blocks.iterator();
  +        while( iterator.hasNext() )
  +        {
  +            Block block = (Block) iterator.next();
  +
  +            if( getLogger().isDebugEnabled() )
               {
  -                synchronized( m_action )
  -                {
  -                    if( m_state != m_action.intValue() )
  -                    {
  -                        switch( m_action.intValue() )
  -                        {
  -                            case StateEvent.STARTED:
  -                                if( m_state == StateEvent.INITIALIZED )
  -                                {
  -                                    m_container.startup();
  -                                }
  -                                else if( m_state == StateEvent.SUSPENDED )
  -                                {
  -                                    m_container.resume();
  -                                }
  -                                break;
  -                            case StateEvent.SUSPENDED:
  -                                if( m_state == StateEvent.STARTED )
  -                                {
  -                                    m_container.suspend();
  -                                }
  -                                break;
  -                            case StateEvent.STOPPED:
  -                                if( ( m_state == StateEvent.STARTED )
  -                                    || ( m_state == StateEvent.SUSPENDED ) )
  -                                {
  -                                    m_container.shutdown();
  -                                }
  -                                break;
  -                        }
  -                    }
  -                }
  -                sleep();
  +                final String message =
  +                  "activating block: " + block; 
  +                getLogger().debug( message );
  +            }
  +
  +            try
  +            {
  +                block.assemble( new DependencyGraph( graph ) );
  +                Container container = (Container) block.resolve( this );
  +                m_containers.put( block, container );
               }
  -            if( m_container instanceof Disposable )
  +            catch( Throwable e )
               {
  -                ((Disposable)m_container).dispose();
  +                final String error =
  +                  "Could not establish a sub-container: " 
  +                  + block
  +                  + " in block: " + this;
  +                throw new AssemblyException( error, e );
               }
           }
  -        catch( Throwable e )
  +
  +        super.assemble( graph );
  +
  +        if( getLogger().isDebugEnabled() )
           {
  -            final String error = "Unexpected error during container 
execution.";
  -            m_error = new BlockException( error, e );
  -            terminate();
  +            Appliance[] startup = graph.getStartupGraph( );
  +            StringBuffer buffer = new StringBuffer( "startup sequence: " );
  +            for( int p=0; p<startup.length; p++ )
  +            {
  +               buffer.append( ", " + startup[p] );
  +            }
  +            getLogger().debug( buffer.toString() );
           }
       }
   
  -    
//-------------------------------------------------------------------------------
  -    // Appliance
  -    
//-------------------------------------------------------------------------------
  +   /**
  +    * Startup the components in this container.
  +    * @exception Exception if a startup error occurs
  +    */
  +    private void assembleComponents( DependencyGraph graph ) throws 
AssemblyException
  +    {
  +        Iterator iterator = m_appliances.iterator();
  +        while( iterator.hasNext() )
  +        {
  +            Appliance appliance = (Appliance) iterator.next();
  +            graph.add( appliance );
  +            appliance.assemble( graph );
  +        }
  +    }
   
      /**
  -    * Assemble the appliance.  The implementation extends the default 
  -    * appliance behavior by instantiating the container it is managing, 
  -    * and applying assembly to the container instance. This results in 
  -    * container creating appliance instances for the component is is 
  -    * managing together with assembly of its sub-containers.
  -    *
  -    * @exception AssemblyException if an error occurs during appliance 
assembly
  +    * Disassemble the block.
       */
  -    public void assemble() throws AssemblyException
  +    public void disassemble()
       {
  -        if( m_assembled )
  +        if( m_disassembled )
           {
               return;
           }
   
           if( getLogger().isDebugEnabled() )
           {
  -            getLogger().debug("block assembly" );
  +            getLogger().debug( "disassemble" );
           }
   
  -        super.assemble();
  -
  -        try
  +        if( !m_deployed )
           {
  -            m_assembled = true;
  -            m_container = (Container) super.access();
  -            m_container.addStateListener( this );
  -            m_container.assemble();
  +            throw new IllegalStateException( "deployment" );
           }
  -        catch( Throwable e )
  +
  +        synchronized( m_action )
           {
  -            m_assembled = false;
  -            final String error = "Unable to establish containment 
implemetation.";
  -            throw new AssemblyException( error, e );
  +            m_action = new Integer( StateEvent.STOPPED );
  +            while( ( m_state < StateEvent.STOPPED  ) && ( m_error == null ) )
  +            {
  +                sleep();
  +            }
  +
  +            if( m_error != null )
  +            {
  +                if( getLogger().isErrorEnabled() )
  +                {
  +                    final String msg = "Unexpected error during 
disassembly.";
  +                    String error = ExceptionHelper.packException( msg, 
m_error );
  +                    getLogger().error( error );
  +                    m_error = null;
  +                }
  +            }
           }
       }
   
      /**
  +    * Startup the components in this container.
  +    * @exception Exception if a startup error occurs
  +    */
  +    //private void disassembleComponents()
  +    //{
  +    //    Iterator iterator = m_appliances.iterator();
  +    //    while( iterator.hasNext() )
  +    //    {
  +    //        Appliance appliance = (Appliance) iterator.next();
  +    //        appliance.disassemble();
  +    //    }
  +    //}
  +
  +   /**
       * Terminate the block.  If a container has been established, the 
implemetation
       * will relase the container and continue with appliance termination.
       */
       public void terminate()
       {
  -        synchronized( this )
  +        if( m_terminated )
           {
  -            if( m_error == null )
  +            return;
  +        }
  +
  +        if( !m_deployed )
  +        {
  +            handleTermination();
  +        }
  +
  +        synchronized( m_action )
  +        {
  +            m_action = new Integer( TERMINATED );
  +            while( ( m_state < TERMINATED ) && ( m_error == null ) )
               {
  -                m_action = new Integer( StateEvent.DISPOSED );
  -                while( ( m_state < StateEvent.DISPOSED ) && ( m_error == 
null ) )
  -                {
  -                    sleep();
  -                }
  +                sleep();
               }
  -            else
  +
  +            if( m_error != null )
               {
                   if( getLogger().isErrorEnabled() )
                   {
  -                    getLogger().error( "terminating due to container error", 
m_error );
  -                }
  -                if( m_container instanceof Disposable )
  -                {
  -                    ((Disposable)m_container).dispose();
  +                    final String msg = "Unexpected error during 
termination.";
  +                    String error = ExceptionHelper.packException( msg, 
m_error );
  +                    getLogger().error( error );
  +                    m_error = null;
                   }
               }
           }
  -
  -        if( m_container != null )
  -        {
  -            release( m_container );
  -            m_container = null;
  -        }
  -        super.terminate();
       }
   
       
//-------------------------------------------------------------------------------
  @@ -324,91 +492,290 @@
       
//-------------------------------------------------------------------------------
   
      /**
  -    * Convinience operation to startup the components in the container.
  -    * @exception Exception if a container startup error occurs
  +    * Deploy the block during which appliances managed by the block
  +    * will be established as executing components.
  +    *
  +    * @exception Exception if a deployment error occurs
       */
  -    public void startup() throws Exception
  +    public void deploy() throws Exception
       {
  -        if( !m_assembled )
  +        if( getDependencyGraph() == null )
           {
  -            throw new IllegalStateException( "assembly" );
  +            final String error =
  +              "Cannot deploy block " + this + " before assembly.";
  +            throw new IllegalStateException( error );
           }
   
  -        synchronized( this )
  +        if( getLogger().isDebugEnabled() )
  +        {
  +            getLogger().debug( "deployment" );
  +        }
  +
  +        //
  +        // construct and start a thread in which this block will execute
  +        //
  +
  +        m_thread = new Thread( this, super.getPath() );
  +        m_thread.setContextClassLoader( m_engine );
  +        m_thread.start();
  +
  +        synchronized( m_action )
           {
               m_action = new Integer( StateEvent.STARTED );
               while( ( m_state < StateEvent.STARTED ) && ( m_error == null ) )
               {
                   sleep();
               }
  +
               if( m_error != null )
               {
  -                throw m_error;
  +                m_state = StateEvent.STOPPED;
  +                final String error = 
  +                  "Unexpected deployment error.";
  +                Exception exception = new BlockException( error, m_error );
  +                m_error = null;
  +                throw exception;
  +            }
  +        }
  +
  +        //
  +        // deploy the subsidiary blocks
  +        //
  +
  +        Iterator iterator = m_blocks.iterator();
  +        while( iterator.hasNext() )
  +        {
  +            Block block = (Block) iterator.next();
  +
  +            try
  +            {
  +                block.deploy();
  +                Container container = (Container) block.resolve( this );
  +                m_containers.put( block, container );
  +            }
  +            catch( Throwable e )
  +            {
  +                final String error =
  +                  "Subsidiary block deployment error in: " + block
  +                  + " in parent block: " + this;
  +                m_error = new BlockException( error, e );
  +                break;
               }
           }
  +        
  +        m_deployed = true;
       }
   
  -    /**
  -     * Request for the container to suspend all subsidiary containers
  -     * and all contained components.
  -     */
  -    public void suspend()
  +   /**
  +    * Decommission the block.
  +    *
  +    * @exception Exception if a deployment error occurs
  +    */
  +    public void decommission()
       {
  -        synchronized( this )
  +        if( !m_deployed )
  +        {
  +            throw new IllegalStateException( "deployment" );
  +        }
  +
  +        synchronized( m_action )
           {
  -            m_action = new Integer( StateEvent.SUSPENDED );
  -            while( ( m_state < StateEvent.SUSPENDED ) && ( m_error == null ) 
)
  +            m_action = new Integer( StateEvent.STOPPED );
  +            while( ( m_state < StateEvent.STOPPED ) && ( m_error == null ) )
               {
                   sleep();
               }
  +
  +            if( m_error != null )
  +            {
  +                if( getLogger().isErrorEnabled() )
  +                {
  +                    final String msg = "Unexpected error during 
decommissioning.";
  +                    String error = ExceptionHelper.packException( msg, 
m_error );
  +                    getLogger().error( error );
  +                }
  +                m_state = StateEvent.STOPPED;
  +            }
           }
       }
   
  +    
//-------------------------------------------------------------------------------
  +    // Runnable
  +    
//-------------------------------------------------------------------------------
  +
       /**
  -     * Request for the container to resume all subsidiary containers
  -     * and all contained components.
  +     * Starts the thread of execution for the block.  This operation is
  +     * invoked by the container constructor.
        */
  -    public void resume()
  +    public void run()
       {
  -        if( m_state != StateEvent.SUSPENDED )
  +        if( !m_running )
           {
  -            throw new IllegalStateException( "not-suspended." );
  +            m_running = true;
           }
   
  -        synchronized( this )
  +        try
           {
  -            m_action = new Integer( StateEvent.STARTED );
  -            while( ( m_state == StateEvent.SUSPENDED ) && ( m_error == null 
) )
  +
  +            m_container = (Container) resolve( this );
  +
  +            //
  +            // while desired state of the hosted container is something
  +            // other than DISPOSED, check if the desired state is different
  +            // from the current state reported by the container, and if
  +            // so initiate a container state change
  +            //
  +
  +            while( m_action.intValue() < DISPOSED )
               {
  +                synchronized( m_action )
  +                {
  +                    if( m_state != m_action.intValue() )
  +                    {
  +                        switch( m_action.intValue() )
  +                        {
  +                            case StateEvent.STARTED:
  +                                if( m_state == StateEvent.INITIALIZED )
  +                                {
  +                                    m_container.startup();
  +                                }
  +                                else if( m_state == StateEvent.SUSPENDED )
  +                                {
  +                                    m_container.resume();
  +                                }
  +                                break;
  +                            case StateEvent.SUSPENDED:
  +                                if( m_state == StateEvent.STARTED )
  +                                {
  +                                    m_container.suspend();
  +                                }
  +                                break;
  +                            case StateEvent.STOPPED:
  +                                handleDecommissioning();
  +                                break;
  +                            case DISASSEMBLED:
  +                                handleDisassembly();
  +                                break;
  +                            case TERMINATED:
  +                                handleTermination();
  +                                break;
  +                        }
  +                    }
  +                }
                   sleep();
               }
  +
  +            getLogger().debug( "exit: " + m_state );
  +        }
  +        catch( Throwable e )
  +        {
  +            final String error = "Unexpected runtime error in block:" + this;
  +            m_error = new BlockException( error, e );
           }
       }
   
  -   /**
  -    * Convinience operation to shutdown the components in the container.
  -    * @exception Exception if a container shutdown error occurs
  -    */
  -    public void shutdown() throws Exception
  +    private void handleDecommissioning()
       {
  -        if( !m_assembled )
  -        {
  -            throw new IllegalStateException( "assembly" );
  -        }
  -        synchronized( this )
  +        if( m_container != null )
           {
  -            m_action = new Integer( StateEvent.STOPPED );
  -            while( ( m_state < StateEvent.STOPPED ) && ( m_error == null ) )
  +            if( ( m_state == StateEvent.STARTED )
  +              || ( m_state == StateEvent.SUSPENDED ) )
               {
  -                sleep();
  +                m_container.shutdown();
               }
  -            if( m_error != null )
  +        }
  +        else
  +        {
  +            m_state = StateEvent.STOPPED;
  +        }
  +        m_decommissioned = true;
  +    }
  +
  +    private void handleDisassembly()
  +    {
  +        if( !m_decommissioned )
  +        {
  +            handleDecommissioning();
  +        }
  +
  +        m_shutdown = getDependencyGraph().getShutdownGraph();
  +
  +        if( getLogger().isDebugEnabled() )
  +        {
  +            StringBuffer buffer = new StringBuffer( "dissassemble: " );
  +            for( int p=0; p<m_shutdown.length; p++ )
               {
  -                throw m_error;
  +               buffer.append( ", " + m_shutdown[p] );
               }
  +            getLogger().debug( buffer.toString() );
           }
  +
  +        for( int i=0; i<m_shutdown.length; i++ )
  +        {
  +            Appliance appliance = m_shutdown[i];
  +            appliance.disassemble();
  +        }
  +
  +        Iterator iterator = m_blocks.iterator();
  +        while( iterator.hasNext() )
  +        {
  +            Block block = (Block) iterator.next();
  +            block.disassemble();
  +        }
  +
  +        super.disassemble();
  +        m_disassembled = true;
  +        m_state = DISASSEMBLED;
       }
   
  +    private void handleTermination()
  +    {
  +        if( m_terminated )
  +        {
  +            // already terminated
  +            return;
  +        }
  +
  +        if( !m_disassembled )
  +        {
  +            handleDisassembly();
  +        }
  +
  +        if( getLogger().isDebugEnabled() )
  +        {
  +            getLogger().debug( "termination" );
  +        }
  +
  +        for( int i=0; i<m_shutdown.length; i++ )
  +        {
  +            Appliance appliance = m_shutdown[i];
  +            appliance.terminate();
  +        }
  +
  +        m_appliances = null;
  +
  +        Iterator iterator = m_blocks.iterator();
  +        while( iterator.hasNext() )
  +        {
  +            Block block = (Block) iterator.next();
  +            block.terminate();
  +        }
  +
  +        m_terminated = true;
  +        m_state = TERMINATED;
  +        super.terminate();
  +
  +        //
  +        // trigger termination of the thread
  +        //
  +
  +        m_action = new Integer( DISPOSED );
  +    }
  +
  +    
//-------------------------------------------------------------------------------
  +    // internal
  +    
//-------------------------------------------------------------------------------
  +
       /**
        * Method invoked when a container state changes.
        * @param event the state event
  @@ -417,7 +784,7 @@
       {
           if( getLogger().isDebugEnabled() )
           {
  -            getLogger().debug("state event: [" + event.getState() + "]" );
  +            getLogger().debug("state event: " + event );
           }
           m_state = event.getState();
       }
  
  
  
  1.6       +4 -3      
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.5
  retrieving revision 1.6
  diff -u -r1.5 -r1.6
  --- Container.java    9 Jan 2003 15:19:59 -0000       1.5
  +++ Container.java    15 Jan 2003 09:14:51 -0000      1.6
  @@ -57,6 +57,7 @@
   
   import org.apache.avalon.framework.Version;
   import org.apache.avalon.assembly.lifecycle.AssemblyException;
  +import org.apache.avalon.assembly.appliance.DependencyGraph;
   
   /**
    * <p>A container is node in a containment heirachy. It defines a scope 
  @@ -76,7 +77,7 @@
       * all subsidiary containers.
       * @exception Exception if a assembly error occurs
       */
  -    void assemble() throws AssemblyException;
  +    //void assemble( DependencyGraph graph ) throws AssemblyException;
   
      /**
       * Startup the components in this container and startup all subsidiary 
  @@ -101,7 +102,7 @@
       * Shutdown all subsidiary containers and all components in this 
container.
       * @exception Exception if a shutdown error occurs
       */
  -    void shutdown() throws Exception;
  +    void shutdown();
   
       /**
        * Adds a <code>StateListener</code> to the container.
  
  
  
  1.11      +26 -5     
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.10
  retrieving revision 1.11
  diff -u -r1.10 -r1.11
  --- ContainerLoader.java      9 Jan 2003 15:19:59 -0000       1.10
  +++ ContainerLoader.java      15 Jan 2003 09:14:51 -0000      1.11
  @@ -77,7 +77,6 @@
   import org.apache.avalon.framework.configuration.DefaultConfiguration;
   import org.apache.avalon.framework.context.Context;
   import org.apache.avalon.framework.context.DefaultContext;
  -//import org.apache.avalon.framework.context.Contextualizable;
   import org.apache.avalon.framework.context.ContextException;
   import org.apache.avalon.framework.logger.AbstractLogEnabled;
   import org.apache.avalon.framework.service.DefaultServiceManager;
  @@ -103,6 +102,7 @@
   import org.apache.avalon.assembly.engine.model.ClasspathDescriptor;
   import org.apache.avalon.assembly.util.ExceptionHelper;
   import org.apache.excalibur.configuration.ConfigurationUtil;
  +import org.apache.avalon.meta.model.builder.XMLProfileCreator;
   
   /**
    * An abstract utility class that provides support for the creation of 
subsidiary
  @@ -120,6 +120,7 @@
       //==============================================================
   
       protected static final XMLContainerCreator CREATOR = new 
XMLContainerCreator();
  +    private static final XMLProfileCreator BUILDER = new XMLProfileCreator();
   
       //==============================================================
       // ContainerLoader
  @@ -156,7 +157,10 @@
   
           try
           {
  -            return CREATOR.createContainerDescriptor( type, config );
  +            Profile profile = BUILDER.createProfile( type, config );
  +            boolean policy = getActivationPolicy( config );
  +            profile.setActivationPolicy( policy );
  +            return profile;
           }
           catch( Throwable e )
           {
  @@ -168,6 +172,22 @@
           }
       }
   
  +    private boolean getActivationPolicy( Configuration config )
  +    {
  +        final String value = config.getAttribute( "activation", null );
  +        if( value == null )
  +        {
  +            return false;
  +        }
  +        final String string = value.toLowerCase().trim();
  +        if( string.equals( "startup" ) )
  +        {
  +            return true;
  +        }
  +        return string.equals( "true" );
  +    }
  +
  +
       protected EngineClassLoader createChildEngine( 
         EngineClassLoader parent, File home, Configuration config, Logger 
logger ) 
         throws ContainerException, ConfigurationException
  @@ -188,7 +208,8 @@
           }
           catch( Throwable e )
           {
  -            final String error = "Bad library descriptor.";
  +            final String error = "Bad library descriptor in configuration: 
\n" 
  +              + ConfigurationUtil.list( config );
               throw new ContainerException( error, e );
           }
   
  @@ -216,7 +237,7 @@
               {
                   engine = new EngineClassLoader( parent );
               }
  -            engine.enableLogging( logger.getChildLogger( "engine" ) );
  +            engine.enableLogging( logger );
               DefaultLocator context = new DefaultLocator();
               context.put( "urn:assembly:home", home );
               context.put( "urn:assembly:engine.extensions", extensions );
  
  
  
  1.14      +129 -414  
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.13
  retrieving revision 1.14
  diff -u -r1.13 -r1.14
  --- DefaultContainer.java     9 Jan 2003 15:19:59 -0000       1.13
  +++ DefaultContainer.java     15 Jan 2003 09:14:51 -0000      1.14
  @@ -66,6 +66,7 @@
   import org.apache.avalon.assembly.appliance.ApplianceContext;
   import org.apache.avalon.assembly.appliance.DefaultApplianceContext;
   import org.apache.avalon.assembly.appliance.ApplianceException;
  +import org.apache.avalon.assembly.appliance.DependencyGraph;
   import org.apache.avalon.assembly.lifecycle.AssemblyException;
   import org.apache.avalon.framework.logger.AbstractLogEnabled;
   import org.apache.avalon.framework.configuration.Configuration;
  @@ -97,48 +98,14 @@
       // state
       //==============================================================
   
  -    private EngineClassLoader m_engine;
  +    private DependencyGraph m_graph;
   
       private ContainerDescriptor m_descriptor;
   
  -    private Registry m_registry;
  -
  -   /**
  -    * 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;
  -
  -   /**
  -    * Component configuration.
  -    */
  -    private Configuration m_targets;
  +    private Map m_components = new Hashtable();
   
      /**
       * State event listener list.
  @@ -151,6 +118,11 @@
        */
       private int m_state = StateEvent.UNKNOWN;
   
  +    /**
  +     * Flag holding the disposed state of the container.
  +     */
  +    private boolean m_disposed = false;
  +
       //==============================================================
       // Contextualizable
       //==============================================================
  @@ -161,142 +133,44 @@
       */
       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:avalon:partition.name" );
  -        m_registry = (Registry) context.get( "urn:merlin:container.registry" 
);
  -        m_targets = (Configuration) context.get( 
"urn:merlin:container.configuration" );
  +        m_graph = (DependencyGraph) context.get( 
"urn:merlin:container.dependency-graph" );
  +        addStateListener( (StateListener) context.get( 
"urn:merlin:container.listener" ) ); 
       }
   
       //==============================================================
       // Initializable
       //==============================================================
   
  -    public void initialize() throws Exception
  +   /**
  +    * Initialization of the container.  The implememtation uses the 
intilization
  +    * phase to verify correct setup including validation of logging channel 
assignment
  +    * and container context.
  +    * @exception IllegalStateException if the logging or context phases have 
not been
  +    *   applied 
  +    */
  +    public void initialize() throws IllegalStateException
       {
           if( getLogger() == null )
           {
  -            throw new IllegalStateException("logger");
  -        }
  -        if( m_engine == null )
  -        {
  -            throw new IllegalStateException("context");
  -        }
  -
  -        if( m_partition != null )
  -        {
  -            if( m_partition.endsWith("/") )
  -            {
  -                m_path = m_partition + m_descriptor.getName() + "/";
  -            }
  -            else
  -            {
  -                m_path = m_partition + "/" + m_descriptor.getName() + "/";
  -            }
  -        }
  -        else
  -        {
  -            m_path = m_descriptor.getName() + "/";
  -        }
  -
  -        Profile[] profiles = m_descriptor.getComponents();
  -        if( getLogger().isDebugEnabled() )
  -        {
  -            getLogger().debug( "initialization: " + m_path + " (" + 
profiles.length + ")" );
  +            throw new IllegalStateException("logging");
           }
   
  -        for( int i=0; i<profiles.length; i++ )
  +        if( m_graph == null )
           {
  -            Profile profile = profiles[i];
  -            if( getLogger().isDebugEnabled() )
  -            {
  -                final String message =
  -                  "appliance appliance: " + profile; 
  -                getLogger().debug( message );
  -            }
  -            DefaultApplianceContext context = new DefaultApplianceContext( 
profile );
  -            Configuration config = DefaultKernel.getNamedConfiguration( 
m_targets, profile.getName() );
  -            context.setPartitionName( m_path );
  -            context.setConfiguration( config );
  -            context.makeReadOnly();
  -            Appliance appliance = createAppliance( context, true );
  -            m_components.add( appliance );
  -            m_registry.bind( appliance );
  -        }
  -
  -        Iterator iterator = m_containers.iterator();
  -        while( iterator.hasNext() )
  -        {
  -            Appliance appliance = (Appliance) iterator.next();
  -
  -            if( getLogger().isDebugEnabled() )
  -            {
  -                final String message =
  -                  "activating container: " + appliance; 
  -                getLogger().debug( message );
  -            }
  -
  -            try
  -            {
  -                appliance.assemble();
  -                Container container = (Container) appliance.access();
  -                m_containerMap.put( appliance, container );
  -            }
  -            catch( Throwable e )
  -            {
  -                final String error =
  -                  "Could not establish a sub-container: " 
  -                     + appliance
  -                     + " in container: " + this;
  -                throw new ContainerException( error, e );
  -            }
  +            throw new IllegalStateException("context");
           }
  -    }
  -
  -   /**
  -    * 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 AssemblyException
  -    {
  -        if( m_state < StateEvent.INITIALIZED )
  -        {
  -            if( getLogger().isDebugEnabled() )
  -            {
  -                getLogger().debug( "assembly" );
  -            }
  -        
  -            assembleComponents();
  -            assembleContainers();
  +        //
  +        // issue an initialization event back to the block
  +        //
   
  -            m_state = StateEvent.INITIALIZED;
  -            fireStateChange( new StateEvent( this, m_descriptor.getName(), 
StateEvent.INITIALIZED ) );
  -        }
  +        m_state = StateEvent.INITIALIZED;
  +        fireStateChange( new StateEvent( this, m_descriptor.getName(), 
StateEvent.INITIALIZED ) );
       }
   
      /**
  -    * Startup the components in this container and startup all subsidiary 
  -    * containers.
  +    * Startup the components in this container.
       * @exception Exception if a startup error occurs
       */
       public void startup() throws Exception
  @@ -312,22 +186,23 @@
               return;
           }
   
  -        if( m_state > StateEvent.STARTED )
  +        if( m_state == StateEvent.STOPPED )
           {
  -            throw new IllegalStateException(
  -                "Container has already passed through start phase." );
  +            final String error = "Cannot restart a stopped container.";
  +            throw new IllegalStateException( error );
           }
   
  -        if( getLogger().isDebugEnabled() )
  +        try
           {
  -            getLogger().debug( "startup" );
  +            startupComponents();
  +            m_state = StateEvent.STARTED;
  +            fireStateChange( new StateEvent( this, m_descriptor.getName(), 
StateEvent.STARTED ) );
  +        }
  +        catch( Throwable e )
  +        {
  +            m_state = StateEvent.STOPPED;
  +            fireStateChange( new StateEvent( this, m_descriptor.getName(), 
StateEvent.STOPPED, e ) );
           }
  -
  -        startupComponents();
  -        startupContainers();
  -
  -        m_state = StateEvent.STARTED;
  -        fireStateChange( new StateEvent( this, m_descriptor.getName(), 
StateEvent.STARTED ) );
       }
   
       /**
  @@ -358,12 +233,17 @@
               getLogger().debug( "container suspension" );
           }
   
  -        suspendContainers();
  -        suspendComponents();
  -
  -        getLogger().debug( "container suspension complete" );
  -        m_state = StateEvent.SUSPENDED;
  -        fireStateChange( new StateEvent( this, m_descriptor.getName(), 
StateEvent.SUSPENDED ) );
  +        try
  +        {
  +            suspendComponents();
  +            m_state = StateEvent.SUSPENDED;
  +            fireStateChange( new StateEvent( this, m_descriptor.getName(), 
StateEvent.SUSPENDED ) );
  +        }
  +        catch( Throwable e )
  +        {
  +            m_state = StateEvent.STOPPED;
  +            fireStateChange( new StateEvent( this, m_descriptor.getName(), 
StateEvent.STOPPED, e ) );
  +        }
       }
   
       /**
  @@ -387,12 +267,17 @@
           // resume subsidiary containers
           //
   
  -        resumeComponents();
  -        resumeContainers();
  -
  -        getLogger().debug( "container resumption complete" );
  -        m_state = StateEvent.STARTED;
  -        fireStateChange( new StateEvent( this, m_descriptor.getName(), 
StateEvent.STARTED ) );
  +        try
  +        {
  +            resumeComponents();
  +            m_state = StateEvent.STARTED;
  +            fireStateChange( new StateEvent( this, m_descriptor.getName(), 
StateEvent.STARTED ) );
  +        }
  +        catch( Throwable e )
  +        {
  +            m_state = StateEvent.STOPPED;
  +            fireStateChange( new StateEvent( this, m_descriptor.getName(), 
StateEvent.STOPPED, e ) );
  +        }
       }
   
   
  @@ -400,7 +285,7 @@
       * Shutdown all subsidiary containers and all components in this 
container.
       * @exception Exception if a shutdown error occurs
       */
  -    public void shutdown() throws Exception
  +    public void shutdown()
       {
           if( m_state < StateEvent.STARTED )
           {
  @@ -427,11 +312,17 @@
           // the components in this container
           //
   
  -        shutdownContainers();
  -        shutdownComponents();
  -
  -        m_state = StateEvent.STOPPED;
  -        fireStateChange( new StateEvent( this, m_descriptor.getName(), 
StateEvent.STOPPED ) );
  +        try
  +        {
  +            shutdownComponents();
  +            m_state = StateEvent.STARTED;
  +            fireStateChange( new StateEvent( this, m_descriptor.getName(), 
StateEvent.STOPPED ) );
  +        }
  +        catch( Throwable e )
  +        {
  +            m_state = StateEvent.STOPPED;
  +            fireStateChange( new StateEvent( this, m_descriptor.getName(), 
StateEvent.STOPPED, e ) );
  +        }
       }
   
      /**
  @@ -439,7 +330,7 @@
       */
       public void dispose()
       {
  -        if( m_state == StateEvent.DISPOSED )
  +        if( m_disposed )
           {
               return;
           }
  @@ -449,58 +340,10 @@
               getLogger().debug( "disposal" );
           }
   
  -        disposeContainers();
  -        disposeComponents();
  -
  -        if( getLogger().isDebugEnabled() )
  -        {
  -            getLogger().debug( "cleanup" );
  -        }
  -
  -        m_state = StateEvent.DISPOSED;
  -        fireStateChange( new StateEvent( this, m_descriptor.getName(), 
StateEvent.DISPOSED, null ) );
  -
  -        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;
  -    }
  -
  -   /**
  -    * Startup the components in this container.
  -    * @exception Exception if a startup error occurs
  -    */
  -    private void assembleComponents() throws AssemblyException
  -    {
  -        Iterator iterator = m_components.iterator();
  -        while( iterator.hasNext() )
  -        {
  -            Appliance appliance = (Appliance) iterator.next();
  -            appliance.assemble();
  -        }
  -    }
  -
  -   /**
  -    * Invoke assembly on the nested containers in this container.
  -    * @exception Exception if an assembly error occurs
  -    */
  -    private void assembleContainers() throws AssemblyException
  -    {
  -        Iterator iterator = m_containers.iterator();
  -        while( iterator.hasNext() )
  -        {
  -            Appliance appliance = (Appliance) iterator.next();
  -            Container container = (Container) m_containerMap.get( appliance 
);
  -            container.assemble();
  -        }
  +        m_disposed = true;
       }
   
      /**
  @@ -509,56 +352,56 @@
       */
       private void startupComponents() throws Exception
       {
  -        Iterator iterator = m_components.iterator();
  -        while( iterator.hasNext() )
  -        {
  -            Appliance appliance = (Appliance) iterator.next();
  +        Appliance[] appliances = m_graph.getStartupGraph();
   
  -            if( getLogger().isDebugEnabled() )
  -            {
  -                final String message =
  -                  "activating component: [" + appliance.getName() + "]"; 
  -                getLogger().debug( message );
  -            }
  -
  -            try
  +        if( getLogger().isDebugEnabled() )
  +        {
  +            if( appliances.length > 0 )
               {
  -                Object object = appliance.access();
  -                m_componentMap.put( appliance, object );
  +                StringBuffer buffer = new StringBuffer( "startup: " );
  +                for( int p=0; p<appliances.length; p++ )
  +                {
  +                    if( p == 0 )
  +                    {
  +                        buffer.append( appliances[p] );
  +                    }
  +                    else
  +                    {
  +                        buffer.append( ", " + appliances[p] );
  +                    }
  +                }
  +                getLogger().debug( buffer.toString() );
               }
  -            catch( Throwable e )
  +            else
               {
  -                final String error =
  -                  "Could not establish a component: " 
  -                     + appliance.getName() 
  -                     + " in container: " + this;
  -                throw new ContainerException( error, e );
  +                getLogger().debug( "startup" );
               }
           }
  -    }
   
  -   /**
  -    * Startup the containers in this container.
  -    * @exception Exception if a startup error occurs
  -    */
  -    private void startupContainers() throws Exception
  -    {
  -        Iterator iterator = m_containers.iterator();
  -        while( iterator.hasNext() )
  +        for( int i=0; i<appliances.length; i++ )
           {
  -            Appliance appliance = (Appliance) iterator.next();
  -            Container container = (Container) m_containerMap.get( appliance 
);
  -            try
  -            {
  -                container.startup();
  -            }
  -            catch( Throwable e )
  +            Appliance appliance = appliances[i];
  +            if( appliance.getActivationPolicy() )
               {
  -                final String error =
  -                  "Could not start a subsidiary container: " 
  -                     + appliance.getName() 
  -                     + " in container: " + this;
  -                throw new ContainerException( error, e );
  +                if( getLogger().isDebugEnabled() )
  +                {
  +                    final String message =
  +                      "activating component: [" + appliance.getName() + "]"; 
  +                    getLogger().debug( message );
  +                }
  +                try
  +                {
  +                    Object object = appliance.resolve( this );
  +                    m_components.put( appliance, object );
  +                }
  +                catch( Throwable e )
  +                {
  +                    final String error =
  +                      "Could not establish a component: " 
  +                         + appliance.getName() 
  +                         + " in container: " + this;
  +                    throw new ContainerException( error, e );
  +                }
               }
           }
       }
  @@ -574,32 +417,6 @@
       }
   
      /**
  -    * Startup the containers in this container.
  -    * @exception Exception if a startup error occurs
  -    */
  -    private void suspendContainers()
  -    {
  -        Iterator iterator = m_containers.iterator();
  -        while( iterator.hasNext() )
  -        {
  -            Appliance appliance = (Appliance) iterator.next();
  -            Container container = (Container) m_containerMap.get( appliance 
);
  -            try
  -            {
  -                container.suspend();
  -            }
  -            catch( Throwable e )
  -            {
  -                final String error =
  -                  "Could not suspend a subsidiary container: " 
  -                     + appliance.getName() 
  -                     + " in container: " + this;
  -                throw new ContainerRuntimeException( error, e );
  -            }
  -        }
  -    }
  -
  -   /**
       * Startup the components in this container.
       * @exception Exception if a startup error occurs
       */
  @@ -610,42 +427,21 @@
       }
   
      /**
  -    * Startup the containers in this container.
  -    * @exception Exception if a startup error occurs
  -    */
  -    private void resumeContainers()
  -    {
  -        Iterator iterator = m_containers.iterator();
  -        while( iterator.hasNext() )
  -        {
  -            Appliance appliance = (Appliance) iterator.next();
  -            Container container = (Container) m_containerMap.get( appliance 
);
  -            try
  -            {
  -                container.resume();
  -            }
  -            catch( Throwable e )
  -            {
  -                final String error =
  -                  "Could not resume of a subsidiary container: " 
  -                     + appliance.getName() 
  -                     + " in container: " + this;
  -                throw new ContainerRuntimeException( error, e );
  -            }
  -        }
  -    }
  -
  -   /**
       * Shutdown all subsidiary containers and all components in this 
container.
       * @exception Exception if a shutdown error occurs
       */
       private void shutdownComponents() throws Exception
       {
  -        Iterator iterator = m_components.iterator();
  -        while( iterator.hasNext() )
  +        if( m_graph == null )
  +        {
  +            throw new IllegalStateException( "Container has not been 
contextualized: " + this );
  +        }
  +
  +        Appliance[] appliances = m_graph.getShutdownGraph();
  +        for( int i=0; i<appliances.length; i++ )
           {
  -            Appliance appliance = (Appliance) iterator.next();
  -            Object object = m_componentMap.get( appliance );
  +            Appliance appliance = appliances[i];
  +            Object object = m_components.get( appliance );
               if( object != null )
               {
                   if( object instanceof Startable )
  @@ -658,89 +454,7 @@
                       }
                       ((Startable)object).stop();
                   }
  -                else
  -                {
  -                    appliance.release( object );
  -                }
  -            }
  -        }
  -    }
  -
  -   /**
  -    * Shutdown the containers in this container.
  -    * @exception Exception if a startup error occurs
  -    */
  -    private 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();
  -            }
  -            catch( Throwable e )
  -            {
  -                final String error =
  -                  "Could not shutdown a subsidiary container: " 
  -                     + appliance.getName() 
  -                     + " in container: " + this;
  -                throw new ContainerException( error, e );
  -            }
  -        }
  -    }
  -
  -   /**
  -    * Release all of the components in this container.
  -    */
  -    private void disposeComponents()
  -    {
  -        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 =
  -                      "disposing of: " + 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
  -    */
  -    private void disposeContainers()
  -    {
  -        Iterator iterator = m_containers.iterator();
  -        while( iterator.hasNext() )
  -        {
  -            Appliance appliance = (Appliance) iterator.next();
  -            Container container = (Container) m_containerMap.get( appliance 
);
  -            try
  -            {
  -                m_containerMap.remove( appliance );
  -                appliance.release( container );
  -                appliance.terminate();
  -            }
  -            catch( Throwable e )
  -            {
  -                final String error =
  -                  "Could not shutdown a subsidiary container: " 
  -                     + appliance.getName();
  -                getLogger().warn( error, e );
  +                m_components.remove( appliance );
               }
           }
       }
  @@ -779,6 +493,7 @@
           {
               StateListener[] listeners =
                   (StateListener[])m_listeners.toArray( new StateListener[ 0 ] 
);
  +
               for( int i = 0; i < listeners.length; i++ )
               {
                   StateListener listener = listeners[ i ];
  @@ -790,7 +505,7 @@
                   {
                       m_listeners.remove( listener );
                       final String warning =
  -                        "State listener raised on error on notification. 
Removing listener: "
  +                        "State listener raised on error on notification - 
removing listener: "
                           + listener;
                       if( getLogger().isWarnEnabled() )
                       {
  
  
  
  1.7       +4 -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.6
  retrieving revision 1.7
  diff -u -r1.6 -r1.7
  --- DefaultContainer.xinfo    9 Jan 2003 15:19:59 -0000       1.6
  +++ DefaultContainer.xinfo    15 Jan 2003 09:14:51 -0000      1.7
  @@ -31,6 +31,10 @@
       <entry key="urn:avalon:partition.name"/>
       <entry key="urn:merlin:container.configuration"
         type="org.apache.avalon.framework.configuration.Configuration"/>
  +    <entry key="urn:merlin:container.listener"
  +      type="org.apache.avalon.merlin.container.StateListener"/>
  +    <entry key="urn:merlin:container.dependency-graph"
  +      type="org.apache.avalon.assembly.appliance.DependencyGraph"/>
     </context>
   
   </type>
  
  
  
  1.3       +32 -9     
avalon-sandbox/merlin/src/java/org/apache/avalon/merlin/container/StateEvent.java
  
  Index: StateEvent.java
  ===================================================================
  RCS file: 
/home/cvs/avalon-sandbox/merlin/src/java/org/apache/avalon/merlin/container/StateEvent.java,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- StateEvent.java   9 Jan 2003 15:19:59 -0000       1.2
  +++ StateEvent.java   15 Jan 2003 09:14:51 -0000      1.3
  @@ -99,12 +99,6 @@
        */
       public static final int STOPPED = 4;
   
  -    /**
  -     * Static state enumeration value indicating that a container and all
  -     * subsidiary containers have been disposed of.
  -     */
  -    public static final int DISPOSED = 5;
  -
   
       //============================================================
       // state
  @@ -135,7 +129,7 @@
        * @param source the source container
        * @param name the name of the soource container
        * @param state int value of (@link #INITIALIZED}, [EMAIL PROTECTED] 
#STARTED},
  -     *    [EMAIL PROTECTED] #SUSPENDED}, [EMAIL PROTECTED] #STOPPED} or 
[EMAIL PROTECTED] #DISPOSED}
  +     *    [EMAIL PROTECTED] #SUSPENDED}, or [EMAIL PROTECTED] #STOPPED}
        */
       public StateEvent( Object source, String name, int state )
       {
  @@ -148,7 +142,7 @@
        * @param source the source container
        * @param name the name of the soource container
        * @param state int value of (@link #INITIALIZED}, [EMAIL PROTECTED] 
#STARTED},
  -     *    [EMAIL PROTECTED] #STOPPED} or [EMAIL PROTECTED] #DISPOSED}
  +     *    [EMAIL PROTECTED] #SUSPENDED}, or [EMAIL PROTECTED] #STOPPED}
        * @param error an error condition triggering the state change
        */
       public StateEvent( Object source, String name, int state, Throwable 
error )
  @@ -191,6 +185,35 @@
       public Throwable getError()
       {
           return m_error;
  +    }
  +
  +   /**
  +    * Return a string representation of the event.
  +    */
  +    public String toString()
  +    {
  +        return "[" + getName() + ", " + getStateAsString() + "]";
  +    }
  +
  +    private String getStateAsString()
  +    {
  +        if( m_state == INITIALIZED )
  +        {
  +            return "INITIALIZED";
  +        }
  +        else if( m_state == STARTED )
  +        {
  +            return "STARTED";
  +        }
  +        else if( m_state == SUSPENDED )
  +        {
  +            return "SUSPENDED";
  +        }
  +        else if( m_state == STOPPED )
  +        {
  +            return "STOPPED";
  +        }
  +        return "UNKNOWN";
       }
   
   }
  
  
  
  1.26      +107 -60   
avalon-sandbox/merlin/src/java/org/apache/avalon/merlin/kernel/DefaultKernel.java
  
  Index: DefaultKernel.java
  ===================================================================
  RCS file: 
/home/cvs/avalon-sandbox/merlin/src/java/org/apache/avalon/merlin/kernel/DefaultKernel.java,v
  retrieving revision 1.25
  retrieving revision 1.26
  diff -u -r1.25 -r1.26
  --- DefaultKernel.java        9 Jan 2003 15:20:00 -0000       1.25
  +++ DefaultKernel.java        15 Jan 2003 09:14:51 -0000      1.26
  @@ -79,6 +79,7 @@
   import org.apache.avalon.assembly.appliance.Appliance;
   import org.apache.avalon.assembly.appliance.ApplianceContext;
   import org.apache.avalon.assembly.appliance.DefaultApplianceContext;
  +import org.apache.avalon.assembly.appliance.DependencyGraph;
   import org.apache.avalon.assembly.locator.Contextualizable;
   import org.apache.avalon.assembly.locator.Locator;
   import org.apache.avalon.assembly.locator.DefaultLocator;
  @@ -148,6 +149,7 @@
   
       protected static final String BLOCK_XML_ENTRY = "BLOCK-INF/block.xml";
   
  +
      /**
       * Return a configuration element relative to a target name.  The 
implementation 
       * will locate a configuration child in the supplied configuration with 
an element name
  @@ -223,6 +225,8 @@
   
       private DefaultRegistry m_registry;
   
  +    private final DependencyGraph m_graph = new DependencyGraph();
  +
       //==============================================================
       // Contextualizable
       //==============================================================
  @@ -407,7 +411,7 @@
               Block block = blocks[i];
               try
               {
  -                block.assemble();
  +                block.assemble( new DependencyGraph( m_graph ) );
               }
               catch( Throwable e )
               {
  @@ -463,7 +467,7 @@
           while( iterator.hasNext() )
           {
               Block block = (Block) iterator.next();
  -            block.startup();
  +            block.deploy();
           }
       }
   
  @@ -478,7 +482,7 @@
           {
               if( getLogger().isInfoEnabled() )
               {
  -                getLogger().info( "commencing shutdown phase" );
  +                getLogger().info( "decommissioning" );
               }
           }
   
  @@ -486,7 +490,7 @@
           while( iterator.hasNext() )
           {
               Block block = (Block) iterator.next();
  -            block.shutdown();
  +            block.decommission();
           }
       }
   
  @@ -503,7 +507,7 @@
           {
               if( getLogger().isInfoEnabled() )
               {
  -                getLogger().info( "commencing disposal phase" );
  +                getLogger().info( "termination" );
               }
           }
   
  @@ -514,7 +518,7 @@
               block.terminate();
           }
   
  -        if( getLogger() != null ) 
  +        if( getLogger() != null )
           {
               if( getLogger().isInfoEnabled() )
               {
  @@ -561,16 +565,21 @@
           for( int i=0; i<configs.length; i++ )
           {
               Configuration config = configs[i];
  -            try
  -            {
  -                Block block = loadPhysicalBlock( config, system );
  -                blocks.add( block );
  -            }
  -            catch( Throwable e )
  +            String name = config.getAttribute( "name", null );
  +            boolean enabled = config.getAttributeAsBoolean( "enabled", true 
);
  +            if( enabled )
               {
  -                final String error = 
  -                  "Error during block deployment for block: " + i;
  -                throw new BlockException( error, e );
  +                try
  +                {
  +                    Block block = loadPhysicalBlock( config, system );
  +                    blocks.add( block );
  +                }
  +                catch( Throwable e )
  +                {
  +                    final String error = 
  +                      "Error during block deployment for block: " + (i+1) + 
" [" + name + "]";
  +                    throw new BlockException( error, e );
  +                }
               }
           }
           return (Block[]) blocks.toArray( new Block[0] );
  @@ -578,13 +587,19 @@
   
      /**
       * Load a single block defintion.  The defintion is a configuration
  -    * element named "block" that contains a name and a jar file location.
  -    * The block name is defined by the block name attribute and the location
  -    * of the jar file if defined by the value of the "path" attribute. The 
  -    * implementation loads a block defintion for the supplied jar file 
  -    * and uses this to establish a subsidiary classloader and appliance 
  -    * to handle the implicit implementation container.  The block returned
  -    * from this method is the implicit appliance handling the root container.
  +    * element named "block" that either:
  +    * <ul>
  +    * <li>a reference to a block configuration file</li>
  +    * <li>a reference to a package black in the form of a jar file</li>
  +    * </ul>
  +    * 
  +    * The block name is defined by the block name attribute declared under 
the 
  +    * block element in the blocks.xml configuration.  In the case of the 
  +    * configuration based block defintion, the configuration is derived from 
a 
  +    * and explicit file reference.  In the case of a packaged block, the 
  +    * configuration is resolved from a packaged xmml file name 
  +    * /BLOCK-INFO/block.xml with a jar file.
  +    * 
       *
       * @param config the block declaration
       * @param system the system context
  @@ -604,43 +619,68 @@
           // in the block.xml file
           //
   
  +        URL url = null;
  +        Configuration base;
           String name = config.getAttribute( "name" );
  -        String path = config.getAttribute("path");
           Logger logger = getLogger().getChildLogger( name );
  -        logger.debug( "[" + path + "] as [" + name + "]");
  +        if( config.getAttribute( "path", null ) != null )
  +        {
   
  -        //
  -        // load the jar file referenced by the block declaration and get its 
  -        // manifest
  -        //
  +            //
  +            // It is a packaged block within a jar file.
  +            //
   
  -        URL url = new File( m_home, path ).getCanonicalFile().toURL();
  -        JarFile jar = getJarFile( url );
  -        Manifest manifest = jar.getManifest();
  -        if( !DefaultBlock.isBlock( manifest ) )
  -        {
  -            final String warning = 
  -              "Manifest does not declare a block within the resource: " + 
url;
  -            throw new IllegalArgumentException( warning );
  -        }
  +            String path = config.getAttribute("path");
  +            if( getLogger().isDebugEnabled() )
  +            {
  +                logger.debug( "[" + path + "] as [" + name + "]");
  +            }
   
  -        String packageName = DefaultBlock.getPackageName( manifest );
  -        if( packageName == null )
  -        {
  -            final String error = "Missing package declaration in block: " + 
url;
  -            throw new IllegalArgumentException( error );
  +            //
  +            // load the jar file referenced by the block declaration and get 
its 
  +            // manifest
  +            //
  +
  +            url = new File( m_home, path ).getCanonicalFile().toURL();
  +            JarFile jar = getJarFile( url );
  +
  +            //
  +            // get the blocks packaged configuration and use that to 
establish 
  +            // the engine to be supplied to the block
  +            //
  +
  +            base = getBlockConfiguration( jar );
           }
  +        else
  +        {
  +            // 
  +            // The block configuration is declared in an external file.
  +            //
   
  -        //
  -        // get the blocks packaged configuration and use that to establish 
  -        // the engine to be supplied to the block
  -        //
  +            String src = config.getAttribute( "src", null );
  +            if( src == null )
  +            {
  +                final String error = 
  +                  "Block does not contain a 'src' or 'path' attribute: \n"
  +                  + ConfigurationUtil.list( config );
  +                throw new BlockException( error );
  +            }
  +
  +            File file = new File( m_home, src );
  +            DefaultConfigurationBuilder builder = new 
DefaultConfigurationBuilder();
  +            InputStream is = new FileInputStream( file );
  +            if( is == null )
  +            {
  +                throw new BlockException(
  +                    "Could not load the configuration resource \"" + file  + 
"\"" );
  +            }
  +            base = builder.build( is );
  +        }
   
  -        Configuration base = getBlockConfiguration( jar );
  -        Configuration containment = 
  +        Configuration implementation = 
             getImplementationConfiguration( base.getChild( "implementation" ) 
);
   
  -        Configuration engineConfig = containment.getChild( "engine" );
  +        Configuration engineConfig = implementation.getChild( "engine" );
           EngineClassLoader engine = createChildEngine( m_engine, m_home, 
engineConfig, url, logger );
   
           //
  @@ -649,9 +689,10 @@
           //
   
           String partition = name + Container.PATH_SEPERATOR;
  -        ContainerDescriptor descriptor = createContainerDescriptor( name, 
engine, containment );
  +        ContainerDescriptor descriptor = createContainerDescriptor( name, 
engine, implementation );
           Registry registry = m_registry.createChild( name );
  -        List list = createChildContainers( engine, registry, partition, 
containment, config, logger );
  +
  +        List list = createChildBlocks( engine, registry, partition, 
implementation, config, logger );
   
           //
           // create the appliance context for the container
  @@ -687,7 +728,7 @@
       }
   
      /**
  -    * Creation of a set of child container relative to a set of parent 
parameters.
  +    * Creation of a set of child blocks relative to a set of parent 
parameters.
       * 
       * @param engine the parent classloader
       * @param registry the parent registry
  @@ -696,7 +737,7 @@
       * @param logger the logger from which child loggers shall be created
       * @return a list of appliance instances each representing a container 
container
       */
  -    private List createChildContainers( 
  +    private List createChildBlocks( 
         EngineClassLoader engine, Registry registry, String partition,
         Configuration config, Configuration custom, Logger logger )
         throws BlockException
  @@ -720,7 +761,7 @@
               catch( ConfigurationException ce )
               {
                   final String error = 
  -                  "Cannot create a subsidiary container due to missing 
container name in configuration:\n"
  +                  "Cannot create a subsidiary container due to missing name 
attribute:\n"
                     + ConfigurationUtil.list( child );
                   throw new BlockException( error );
               }
  @@ -773,7 +814,7 @@
       * Create a single containment block.
       *
       * @param engine the containers classloader
  -    * @param registry the compoent registry to apply to the container
  +    * @param registry the component registry to apply to the container
       * @param partition the partition to assigne to the container
       * @param name the appliance name
       * @param config the configuration of the container
  @@ -787,7 +828,7 @@
         throws BlockException
       {
           String subPartition = partition + name + Container.PATH_SEPERATOR;
  -        List list = createChildContainers( engine, registry, subPartition, 
config, custom, logger );
  +        List list = createChildBlocks( engine, registry, subPartition, 
config, custom, logger );
   
           ContainerDescriptor descriptor;
           try
  @@ -842,10 +883,16 @@
           map.put("urn:merlin:container.configuration", target );
   
           DefaultApplianceContext context = new DefaultApplianceContext( 
descriptor );
  +        context.put("urn:merlin:container.descriptor", descriptor ); 
  +        context.put("urn:merlin:container.registry", registry );
  +        context.put("urn:merlin:container.configuration", target );
  +        context.put("urn:merlin:container.containers", containers );
  +
           context.setName( name );
           context.setDeploymentContext( map );
           context.setPartitionName( partition );
           context.setApplianceClassname( DefaultBlock.class.getName() );
  +        context.makeReadOnly();
   
           //
           // create the containement appliance
  @@ -853,8 +900,8 @@
   
           try
           {
  -            context.makeReadOnly();
  -            return (Block) engine.createAppliance( context, false );
  +            getLogger().debug( "creating block with context: " + context );
  +            return (Block) engine.createAppliance( context, false, false );
           }
           catch( Throwable e )
           {
  @@ -935,7 +982,7 @@
           try
           {
               EngineClassLoader engine = new EngineClassLoader( m_bootstrap );
  -            engine.enableLogging( getLogger().getChildLogger( "engine" ) );
  +            engine.enableLogging( getLogger() );
               Locator system = getSystemContext();
               DefaultLocator context = new DefaultLocator( system );
               context.put( "urn:assembly:engine.bootstrap", "true" );
  
  
  
  1.3       +5 -2      
avalon-sandbox/merlin/src/java/org/apache/avalon/merlin/kernel/KernelLoader.java
  
  Index: KernelLoader.java
  ===================================================================
  RCS file: 
/home/cvs/avalon-sandbox/merlin/src/java/org/apache/avalon/merlin/kernel/KernelLoader.java,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- KernelLoader.java 9 Jan 2003 15:20:00 -0000       1.2
  +++ KernelLoader.java 15 Jan 2003 09:14:51 -0000      1.3
  @@ -28,10 +28,10 @@
   import org.apache.avalon.framework.configuration.DefaultConfigurationBuilder;
   import org.apache.avalon.framework.context.Context;
   import org.apache.avalon.framework.context.DefaultContext;
  -//import org.apache.avalon.framework.context.Contextualizable;
   import org.apache.avalon.framework.context.ContextException;
   import org.apache.avalon.merlin.block.Block;
   import org.apache.avalon.merlin.block.DefaultBlock;
  +import org.apache.avalon.merlin.block.BlockException;
   import org.apache.avalon.merlin.kernel.Kernel;
   import org.apache.avalon.merlin.kernel.DefaultKernel;
   import org.apache.avalon.merlin.kernel.KernelException;
  @@ -121,7 +121,10 @@
           catch( KernelException e )
           {
               // its already been logged
  -            System.err.println( e.toString() );
  +        }
  +        catch( BlockException e )
  +        {
  +            // its already been logged
           }
           catch( Throwable e )
           {
  
  
  
  1.14      +3 -18     avalon-sandbox/merlin/src/test/config/block.xml
  
  Index: block.xml
  ===================================================================
  RCS file: /home/cvs/avalon-sandbox/merlin/src/test/config/block.xml,v
  retrieving revision 1.13
  retrieving revision 1.14
  diff -u -r1.13 -r1.14
  --- block.xml 8 Jan 2003 23:21:52 -0000       1.13
  +++ block.xml 15 Jan 2003 09:14:52 -0000      1.14
  @@ -13,24 +13,9 @@
      </services>
   
      <!--
  -   Block implementation.  The implementation element may contain component
  -   and container entities. The block implementation statement is equivalent
  -   to a root container who's name is implied by the name of the block.
  +   Block implementation.  The following declaration demonstrates a 
  +   reference to an externally packaged implemetation descriptor.
      -->
  -   <implementation src="external.xml">
  -
  -     <!-- use external file or embedded defintion -->
  -     <!-- a container can contain a classpath declaration -->
  -     <!-- a container can contain nested appliance declarations -->
  -     <!-- a container can contain nested containers -->
  -     <!-- if the container used the "src" attribute the following content is 
ignored -->
  -     <!--
  -     <container name="test">
  -       <appliance name="standard" 
class="org.apache.avalon.playground.StandardComponent" activation="startup">
  -         <context class="org.apache.avalon.playground.StandardContextImp"/>
  -       </appliance>
  -     </container>
  -     -->
  -   </implementation>
  +   <implementation src="src/test/config/external.xml" />
   
   </block>
  
  
  
  1.6       +56 -1     
avalon-sandbox/merlin/src/test/org/apache/avalon/playground/StandardComponent.java
  
  Index: StandardComponent.java
  ===================================================================
  RCS file: 
/home/cvs/avalon-sandbox/merlin/src/test/org/apache/avalon/playground/StandardComponent.java,v
  retrieving revision 1.5
  retrieving revision 1.6
  diff -u -r1.5 -r1.6
  --- StandardComponent.java    6 Jan 2003 01:05:53 -0000       1.5
  +++ StandardComponent.java    15 Jan 2003 09:14:52 -0000      1.6
  @@ -56,6 +56,9 @@
   package org.apache.avalon.playground;
   
   import java.io.File;
  +import java.net.URL;
  +import java.net.URLClassLoader;
  +
   import org.apache.avalon.framework.activity.Disposable;
   import org.apache.avalon.framework.activity.Initializable;
   import org.apache.avalon.framework.activity.Startable;
  @@ -63,6 +66,8 @@
   import org.apache.avalon.framework.configuration.Configuration;
   import org.apache.avalon.framework.logger.AbstractLogEnabled;
   
  +//import org.apache.avalon.excalibur.thread.impl.DefaultThreadPool;
  +
   /**
    * This is a minimal demonstration component that implements the
    * <code>BasicService</code> interface and has no dependencies.
  @@ -117,8 +122,9 @@
       /**
        * Initialization of the component type by its container.
        */
  -    public void initialize()
  +    public void initialize() throws Exception
       {
  +        //doThreadTest();
           m_message = 
             "\n  home: " + m_home
             + "\n  work: " + m_work
  @@ -167,5 +173,54 @@
           getLogger().info( m_config.getChild("message").getValue("") );
           getLogger().info( "listing context\n" + m_message + "\n");
       }
  +    
   
  +    /**
  +     * Do a test related to the thread library.
  +     */
  +/*
  +    public void doTreadTest() throws Exception
  +    {
  +        try
  +        {
  +            getLogger().error( "START" );
  +            DefaultThreadPool pool = new DefaultThreadPool( "test", 12 );
  +        }
  +        catch( Throwable e )
  +        {
  +            ClassLoader loader = 
Thread.currentThread().getContextClassLoader();
  +            try
  +            {
  +                loader.loadClass( DefaultThreadPool.class.getName() );
  +            }
  +            catch( Throwable ex )
  +            {
  +                getLogger().error( "CONTEXT: " + ex.toString() );
  +            }
  +
  +            if( loader instanceof URLClassLoader )
  +            {
  +                listURLs( (URLClassLoader) loader );
  +            }
  +            getLogger().error( "THROWABLE: " + e );
  +            getLogger().error( "LOADER:" + loader );
  +            throw new Exception( "zutt", e );
  +        }
  +    }
  +    private void listURLs( URLClassLoader loader )
  +    {
  +        if( loader != null )
  +        {
  +            URL[] urls = loader.getURLs();
  +            for( int i=0; i<urls.length; i++ )
  +            {
  +                getLogger().debug( "URL: " + urls[i] );
  +            }
  +            if( loader.getParent() instanceof URLClassLoader )
  +            {
  +                listURLs( (URLClassLoader) loader.getParent() );
  +            }
  +        }
  +    }
  +*/
   }
  
  
  

--
To unsubscribe, e-mail:   <mailto:[EMAIL PROTECTED]>
For additional commands, e-mail: <mailto:[EMAIL PROTECTED]>

Reply via email to