You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@avalon.apache.org by mc...@apache.org on 2002/08/04 08:43:20 UTC

cvs commit: jakarta-avalon-excalibur/assembly/src/java/org/apache/excalibur/meta/info ReferenceDescriptor.java

mcconnell    2002/08/03 23:43:20

  Modified:    assembly README.TXT kernel.bat
               assembly/demo/src/java/org/apache/excalibur/playground
                        EmbeddedDemo.java
               assembly/src/java/org/apache/excalibur/merlin
                        DefaultController.java Main.java
               assembly/src/java/org/apache/excalibur/merlin/assembly
                        ContainerManager.java DefaultSelector.java
                        TypeManager.java TypeRegistry.java
               assembly/src/java/org/apache/excalibur/merlin/container
                        Container.java DefaultContainer.java
                        DefaultContainer.xinfo
               assembly/src/java/org/apache/excalibur/merlin/container/doc-files
                        Container.gif DefaultContainer.gif
               assembly/src/java/org/apache/excalibur/merlin/kernel
                        DefaultKernel.java Kernel.java
               assembly/src/java/org/apache/excalibur/meta/info
                        ReferenceDescriptor.java
  Added:       assembly/src/java/org/apache/excalibur/merlin/container
                        ContainerEvent.java ContainerListener.java
                        StateEvent.java StateListener.java
  Log:
  Addition of independent threads for containers, container event model (subsidiary container addition/removal and container state change), and programatic creation of an embedded kernel and installation of profiles into a container dynamically.
  
  Revision  Changes    Path
  1.12      +9 -11     jakarta-avalon-excalibur/assembly/README.TXT
  
  Index: README.TXT
  ===================================================================
  RCS file: /home/cvs/jakarta-avalon-excalibur/assembly/README.TXT,v
  retrieving revision 1.11
  retrieving revision 1.12
  diff -u -r1.11 -r1.12
  --- README.TXT	14 Jul 2002 00:57:38 -0000	1.11
  +++ README.TXT	4 Aug 2002 06:43:19 -0000	1.12
  @@ -12,6 +12,14 @@
   Status
   ------
   
  +04-AUG-2002 
  +Independent threads for containers.
  +Container event model (subsidiary container addition/removal and container state change)
  +Programatic creation of an embedded kernel and installation of profiles into a container.
  +Component profile enabling/disabling.
  +Activation policy support for lazy or startup based launch.
  +Pluggable lifecycle extension support.
  +
   14-JUL-2002
   Completion of the javadoc for the meta data model for the kernel, container and component profile directives.
   
  @@ -35,27 +43,17 @@
   
   Short-term:
   
  -1. Add ability to programatically add new containers and components to the model.
  -2. Add ability to enable/disable components/containers.
  -3. Addition of pooled support under a service manager variant as per Merlin 1 is pending.
  -4. Context creation is based on the current ContextFactory class.  This needs to be updated in accordance with the specifications for context and context value creation directives.  Also, the registry needs to be updated to provide support for the import of container based context values (refer spec).
  -5. Management of defaults using the CascadingConfiguration need to be included.  The original Merlin approach was to include the default configuration information inside the .xinfo file.  The approach taken here will be to separate default information into a <classname>.xconfig for default information and a <classname>.xprofile containing default deployment descriptors.  
  +1. Addition of pooled support under a service manager variant as per Merlin 1 is pending.
   
   Medium-Term:
   
   1. Introduction of component factories will be required as a complement to the <component/> directive - e.g <factory/>.
   
  -2. An instantial scheduling policy will be introduced to enable the explicit declaration of lazy or immediate activation.  Immediate activation will support requirements for server style components that wil be launched on startup of the kernel.  Lazy activation policy will delay the activation of a service until a client application issues a lookup request.
  -
  -3. Additional support will be added for for compoents that are not declared in jar manifest.  In addition, it would be desirable that references to component that do not have a accompanying .xinfo file should be usable as simple service components using class introspection (i.e. creation of a type descriptor dynamically).
  -
   4. Upgrading of error handling against classic fail scenarios (class not in classpath, manifest errors, informative configuration errors).
   
   5. Gentle degrade of service deployment profile on error - if a component cannot be deployed, disable the activation of all of the dependent service but continue on with deployment of the remaining services (currently the situation is somewhat of a domino failure effect - if a supplier service fails, a dependent will fail because the supplier failed - this situation can be avoided by disabling depenedent services in fail conditions).
   
   6. Inclusion of explicit directives concerning assembly should be included although quite complex dependecy maps are readily managable using strait-forward logic based assembly of suppliers and consumers.
  -
  -7. Container based supply of services and context is pending.  Currently services are resolvable within the same container and any parent container.  It would be desirable to provide support for the exporting of a service from one container into another.
   
   Stephen McConnell
   mcconnell@apache.org
  
  
  
  1.6       +1 -1      jakarta-avalon-excalibur/assembly/kernel.bat
  
  Index: kernel.bat
  ===================================================================
  RCS file: /home/cvs/jakarta-avalon-excalibur/assembly/kernel.bat,v
  retrieving revision 1.5
  retrieving revision 1.6
  diff -u -r1.5 -r1.6
  --- kernel.bat	29 Jul 2002 06:14:28 -0000	1.5
  +++ kernel.bat	4 Aug 2002 06:43:19 -0000	1.6
  @@ -1 +1 @@
  -java -Djava.ext.dirs=.\extensions -jar .\extensions\merlin.jar src\etc\kernel.xml
  +merlin src\etc\kernel.xml
  
  
  
  1.4       +29 -5     jakarta-avalon-excalibur/assembly/demo/src/java/org/apache/excalibur/playground/EmbeddedDemo.java
  
  Index: EmbeddedDemo.java
  ===================================================================
  RCS file: /home/cvs/jakarta-avalon-excalibur/assembly/demo/src/java/org/apache/excalibur/playground/EmbeddedDemo.java,v
  retrieving revision 1.3
  retrieving revision 1.4
  diff -u -r1.3 -r1.4
  --- EmbeddedDemo.java	3 Aug 2002 10:52:45 -0000	1.3
  +++ EmbeddedDemo.java	4 Aug 2002 06:43:19 -0000	1.4
  @@ -20,8 +20,11 @@
   import org.apache.excalibur.merlin.container.Container;
   import org.apache.excalibur.merlin.model.ContainerDescriptor;
   import org.apache.excalibur.merlin.model.ClasspathDescriptor;
  +import org.apache.excalibur.merlin.model.Profile;
   import org.apache.excalibur.merlin.assembly.ContainerManager;
   import org.apache.excalibur.meta.info.Type;
  +import org.apache.excalibur.meta.info.DependencyDescriptor;
  +import org.apache.excalibur.meta.info.ReferenceDescriptor;
   
   /**
    * This is a minimal demonstration component that implements the 
  @@ -63,18 +66,39 @@
           m_kernel.initialize();
   
           //
  -        // get the manager
  +        // get the manager and the root container
           //
      
           ContainerManager manager = (ContainerManager) Thread.currentThread().getContextClassLoader();
  -        Type type = manager.loadType( "org.apache.excalibur.playground.SimpleComponent" );
  -        getLogger().info("TYPE: " + type );
  +        Container container = m_kernel.getRootContainer();
   
           //
  -        // create and add a profile to the container
  +        // we can either locate or create a profile - in the following example we will
  +        // attempt to locate an existing profile and add it to the container - if we wanted
  +        // to we could dynamically build the profile and add it to the container
           //
   
  -        m_container = m_kernel.getRootContainer();
  +        DependencyDescriptor descriptor = 
  +          new DependencyDescriptor( 
  +            "my-component",
  +            new ReferenceDescriptor( "org.apache.excalibur.playground.SimpleService" ) 
  +          );
  +        Profile profile = manager.getProfile( descriptor );
  +
  +        //
  +        // install the profile into the container triggering profile assembly
  +        //
  +
  +        if( profile != null )
  +        {
  +            getLogger().info("dynamic profile: " + profile );
  +            container.install( new Profile[]{ profile } );
  +            getLogger().info("installation sucessfull" );
  +        }
  +        else
  +        {
  +            getLogger().warn("manager return a null profile - cannot proceed");
  +        }
       }
   
       //=======================================================================
  
  
  
  1.12      +11 -11    jakarta-avalon-excalibur/assembly/src/java/org/apache/excalibur/merlin/DefaultController.java
  
  Index: DefaultController.java
  ===================================================================
  RCS file: /home/cvs/jakarta-avalon-excalibur/assembly/src/java/org/apache/excalibur/merlin/DefaultController.java,v
  retrieving revision 1.11
  retrieving revision 1.12
  diff -u -r1.11 -r1.12
  --- DefaultController.java	3 Aug 2002 09:29:05 -0000	1.11
  +++ DefaultController.java	4 Aug 2002 06:43:19 -0000	1.12
  @@ -60,8 +60,8 @@
    *     File <strong>base</strong> = new File( <font color="darkred"/>&quot;.&quot;</font> );
    *     String <strong>filename</strong> = <font color="darkred"/>&quot;src/etc/kernel.xml&quot;</font> );
    *     DefaultContext <strong>context</strong> = new DefaultContext();
  - *     <strong>context</strong>.put( DefaultController.APPLICATION_DIR_KEY, <strong>base</strong> );
  - *     <strong>context</strong>.put( DefaultController.CONTROLLER_PATH_KEY, <strong>filename</strong> );
  + *     <strong>context</strong>.put( DefaultController.DIR_KEY, <strong>base</strong> );
  + *     <strong>context</strong>.put( DefaultController.PATH_KEY, <strong>filename</strong> );
    *     <strong>context</strong>.makeReadOnly();
    *     
    *     <font color="gray">//
  @@ -94,8 +94,8 @@
       private static final int STOPPED = 3;
       private static final int DISPOSED = 4;
   
  -    public static final String CONTROLLER_PATH_KEY = "merlin:path";
  -    public static final String APPLICATION_DIR_KEY = "avalon:home";
  +    public static final String PATH_KEY = "merlin:path";
  +    public static final String DIR_KEY = "avalon:home";
   
       //=======================================================================
       // state
  @@ -116,15 +116,15 @@
      /**
       * Invoked by the bootstrap process to supply the path to the kernel configuration.
       * @param context the context object containing the working directory under the 
  -    *    context key {@link #APPLICATION_DIR_KEY} as a {@link File}, and the path to 
  -    *    the kernel configuration as a string, supplied under the key {@link #CONTROLLER_PATH_KEY} 
  -    * @exception ContextException if the supplied does not contain a CONTROLLER_PATH_KEY value 
  +    *    context key {@link #DIR_KEY} as a {@link File}, and the path to 
  +    *    the kernel configuration as a string, supplied under the key {@link #PATH_KEY} 
  +    * @exception ContextException if the supplied does not contain a PATH_KEY value 
       */
       public void contextualize( Context context ) throws ContextException
       {
           try
           {
  -            m_path = (String) context.get( CONTROLLER_PATH_KEY );
  +            m_path = (String) context.get( PATH_KEY );
           }
           catch( ContextException e )
           {
  @@ -132,7 +132,7 @@
           }
           try
           {
  -            m_home = (File) context.get( APPLICATION_DIR_KEY );
  +            m_home = (File) context.get( DIR_KEY );
           }
           catch( ContextException e )
           {
  @@ -188,7 +188,7 @@
           //
   
           DefaultContext context = new DefaultContext();
  -        context.put( DefaultKernel.APPLICATION_DIR_KEY, m_home );
  +        context.put( DefaultKernel.DIR_KEY, m_home );
           context.makeReadOnly();
   
           Configuration config = null;
  
  
  
  1.13      +3 -3      jakarta-avalon-excalibur/assembly/src/java/org/apache/excalibur/merlin/Main.java
  
  Index: Main.java
  ===================================================================
  RCS file: /home/cvs/jakarta-avalon-excalibur/assembly/src/java/org/apache/excalibur/merlin/Main.java,v
  retrieving revision 1.12
  retrieving revision 1.13
  diff -u -r1.12 -r1.13
  --- Main.java	3 Aug 2002 09:29:05 -0000	1.12
  +++ Main.java	4 Aug 2002 06:43:19 -0000	1.13
  @@ -157,8 +157,8 @@
   
           final DefaultController controller = new DefaultController();
           DefaultContext context = new DefaultContext();
  -        context.put( DefaultController.APPLICATION_DIR_KEY, base );
  -        context.put( DefaultController.CONTROLLER_PATH_KEY, filename );
  +        context.put( DefaultController.DIR_KEY, base );
  +        context.put( DefaultController.PATH_KEY, filename );
           context.makeReadOnly();
           Runtime.getRuntime().addShutdownHook(
               new Thread()
  
  
  
  1.4       +29 -18    jakarta-avalon-excalibur/assembly/src/java/org/apache/excalibur/merlin/assembly/ContainerManager.java
  
  Index: ContainerManager.java
  ===================================================================
  RCS file: /home/cvs/jakarta-avalon-excalibur/assembly/src/java/org/apache/excalibur/merlin/assembly/ContainerManager.java,v
  retrieving revision 1.3
  retrieving revision 1.4
  diff -u -r1.3 -r1.4
  --- ContainerManager.java	3 Aug 2002 10:52:45 -0000	1.3
  +++ ContainerManager.java	4 Aug 2002 06:43:20 -0000	1.4
  @@ -59,7 +59,9 @@
   import org.apache.excalibur.meta.verifier.ComponentVerifier;
   
   /**
  - * Classloader for an assembly of components.
  + * Classloader for an assembly of components that provides the complete
  + * assembly engine, profile selection management, and resource creation
  + * functionality.
    *
    * @author <a href="mailto:mcconnell@apache.org">Stephen McConnell</a>
    * @version $Revision$ $Date$
  @@ -75,7 +77,10 @@
       private static final Resources REZ =
           ResourceManager.getPackageResources( ContainerManager.class );
   
  -    public static final String DELIMITER = "/";
  +   /**
  +    * The delimiter used to seperate container names in a path.
  +    */
  +    public static final String DELIMITER = ContainerDescriptor.DELIMITER;
   
      /**
       * Context key used by the kernel to access the kernel meta-data descriptor.
  @@ -92,12 +97,12 @@
       //===================================================================
   
      /**
  -    * The default selector.
  +    * The lifecycle helper.
       */
       private LifecycleHelper m_helper = new LifecycleHelper();
   
      /**
  -    * The default selector.
  +    * The default selector to use in the absense of a custom selector.
       */
       private DefaultSelector m_selector = new DefaultSelector();
   
  @@ -149,29 +154,36 @@
       private DependencyGraph m_map;
   
      /**
  -    * Utility class to handle assembly.
  +    * Utility class that we use to offload the management of profiles 
  +    * and which provides the actual assembly process.
       */
       private ProfileRegistry m_registry;
   
      /**
  -    * Internal reference to the supplied context object.
  +    * Internal reference to the supplied context object.  This is the 
  +    * application context which is used to resolve import directives.
       */
       private Context m_context;
   
  -    private DefaultLoggerManager m_logging;
  +   /**
  +    * The description of the logging system that contains the declaration of 
  +    * the logging targets to use.  This value is used as the constructor 
  +    * argument to the DefaultLoggerManager.
  +    */
  +    private LoggingDescriptor m_loggingDescriptor;
   
  -    private Logger m_logger;
  +   /**
  +    * The logging manager that we use to construct logging catagories 
  +    * and logging channels.
  +    */
  +    private DefaultLoggerManager m_logging;
   
  +   /**
  +    * The container model that contains the container's classpath declaration, 
  +    * explicit profile declarations, and defintions of the subsidiary containers.
  +    */
       private ContainerDescriptor m_descriptor;
   
  -    /**
  -     * The component described within the scope of the container.
  -     */
  -    private final ArrayList m_managers = new ArrayList();
  -    private final ArrayList m_containers = new ArrayList();
  -
  -    private LoggingDescriptor m_loggingDescriptor;
  -
       private CategoriesDescriptor m_categories;
   
       private final boolean m_root;
  @@ -492,7 +504,6 @@
               }
               loader.contextualize( context );
               loader.initialize();
  -            m_managers.add( loader );
               return loader;
           }
           catch( Throwable e )
  
  
  
  1.2       +9 -2      jakarta-avalon-excalibur/assembly/src/java/org/apache/excalibur/merlin/assembly/DefaultSelector.java
  
  Index: DefaultSelector.java
  ===================================================================
  RCS file: /home/cvs/jakarta-avalon-excalibur/assembly/src/java/org/apache/excalibur/merlin/assembly/DefaultSelector.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- DefaultSelector.java	29 Jul 2002 06:14:29 -0000	1.1
  +++ DefaultSelector.java	4 Aug 2002 06:43:20 -0000	1.2
  @@ -30,10 +30,17 @@
       */
       public Profile select( Profile[] profiles )
       {
  +        if( profiles.length == 0 )
  +          return null;
  +
           Profile profile = select( profiles, Profile.EXPLICIT );
           if( profile == null ) profile = select( profiles, Profile.PACKAGED );
           if( profile == null ) profile = select( profiles, Profile.IMPLICIT );
  -        return profile;
  +        if( profile != null )
  +        {
  +            return profile;
  +        }
  +        return profiles[0];
       }
   
      /**
  
  
  
  1.5       +8 -35     jakarta-avalon-excalibur/assembly/src/java/org/apache/excalibur/merlin/assembly/TypeManager.java
  
  Index: TypeManager.java
  ===================================================================
  RCS file: /home/cvs/jakarta-avalon-excalibur/assembly/src/java/org/apache/excalibur/merlin/assembly/TypeManager.java,v
  retrieving revision 1.4
  retrieving revision 1.5
  diff -u -r1.4 -r1.5
  --- TypeManager.java	3 Aug 2002 09:29:05 -0000	1.4
  +++ TypeManager.java	4 Aug 2002 06:43:20 -0000	1.5
  @@ -456,10 +456,10 @@
       * @param classname the component type
       * @return the type
       */
  -    public Type loadType( String classname ) throws Exception
  +    public Type getType( String classname ) throws TypeException
       {
  -        getLocalLogger().debug("LOOKUP: " + classname );
  -        Type type = m_types.loadType( classname );
  +        getLocalLogger().debug("load: " + classname );
  +        Type type = m_types.getType( classname );
           if( type != null )
           {
               return type;
  @@ -469,7 +469,7 @@
               ClassLoader parent = getParent();
               if( parent instanceof TypeManager )
               {
  -                return ((TypeManager)parent).loadType( classname );
  +                return ((TypeManager)parent).getType( classname );
               }
               else
               {
  @@ -479,21 +479,12 @@
       }
   
      /**
  -    * Returns the set of component types know to the registry.
  +    * Returns the set of local component types know to the registry.
       * @return the set of component types registered with the registry
       */
  -    public Type[] getTypes()
  +    protected Type[] getTypes()
       {
  -        return m_types.getTypes( );
  -    }
  -
  -   /**
  -    * Returns the set of facilities know to the registry.
  -    * @return the set of facilities registered with the registry
  -    */
  -    public Facility[] getFacilities()
  -    {
  -        return m_types.getFacilities( );
  +        return m_types.getTypes();
       }
   
      /**
  @@ -504,24 +495,6 @@
       public Type[] getTypes( ReferenceDescriptor service )
       {
           return m_types.getTypes( service );
  -    }
  -
  -   /**
  -    * Returns the set of facilities know to the registry matching a supplied phase.
  -    * @return the set of facilities 
  -    */
  -    public Facility[] getFacilities( PhaseDescriptor phase )
  -    {
  -        return m_types.getFacilities( phase );
  -    }
  -
  -   /**
  -    * Returns a registered component type.
  -    * @return the component type from the registry or null if the type is unknown
  -    */
  -    public Type getType( String classname )
  -    {
  -        return m_types.getType( classname );
       }
   
       boolean isLocal( String classname )
  
  
  
  1.5       +7 -24     jakarta-avalon-excalibur/assembly/src/java/org/apache/excalibur/merlin/assembly/TypeRegistry.java
  
  Index: TypeRegistry.java
  ===================================================================
  RCS file: /home/cvs/jakarta-avalon-excalibur/assembly/src/java/org/apache/excalibur/merlin/assembly/TypeRegistry.java,v
  retrieving revision 1.4
  retrieving revision 1.5
  diff -u -r1.4 -r1.5
  --- TypeRegistry.java	3 Aug 2002 10:52:45 -0000	1.4
  +++ TypeRegistry.java	4 Aug 2002 06:43:20 -0000	1.5
  @@ -101,17 +101,6 @@
       }
   
      /**
  -    * Resolve a {@link Type} from a classname.
  -    *
  -    * @param classname the component type
  -    * @return the component type or null if unknown
  -    */
  -    public Type loadType( String classname ) throws Exception
  -    {
  -        return getType( classname );
  -    }
  -
  -   /**
       * Register a potential supplier component type.  The implementation will
       * create a component type instance for the entry if not already known and 
       * return the existing or new instance to the invoking client.
  @@ -297,18 +286,6 @@
       }
   
      /**
  -    * Register the facility resulting in the cross-referencing of the facility
  -    * with the set of phases is is capable of supporting.
  -    */
  -    protected void registerFacility( Facility facility )
  -    {
  -        register( facility );
  -        String key = facility.getInfo().getImplementationKey();
  -        m_facilities.put( key, facility );
  -        getLogger().debug( "Facility: '" + key + "' registered.");
  -    }
  -
  -   /**
       * Register the type resulting in the cross-referencing of the type with the set of 
       * service tables that the type is is capable of supporting.
       */
  @@ -321,6 +298,12 @@
           for( int i=0; i<services.length; i++ )
           {
               register( services[i].getService(), type );
  +        }
  +        if( type instanceof Facility )
  +        {
  +            Facility facility = (Facility) type;
  +            m_facilities.put( key, facility );
  +            getLogger().debug( "Facility: '" + key + "' registered.");
           }
       }
   
  
  
  
  1.9       +90 -10    jakarta-avalon-excalibur/assembly/src/java/org/apache/excalibur/merlin/container/Container.java
  
  Index: Container.java
  ===================================================================
  RCS file: /home/cvs/jakarta-avalon-excalibur/assembly/src/java/org/apache/excalibur/merlin/container/Container.java,v
  retrieving revision 1.8
  retrieving revision 1.9
  diff -u -r1.8 -r1.9
  --- Container.java	2 Aug 2002 12:31:01 -0000	1.8
  +++ Container.java	4 Aug 2002 06:43:20 -0000	1.9
  @@ -8,21 +8,18 @@
   
   package org.apache.excalibur.merlin.container;
   
  +import org.apache.excalibur.merlin.Controller;
   import org.apache.excalibur.merlin.model.Profile;
   import org.apache.excalibur.merlin.model.Resource;
   import org.apache.excalibur.meta.info.ReferenceDescriptor;
   import org.apache.excalibur.meta.info.Type;
  -import org.apache.excalibur.merlin.Verifiable;
  -import org.apache.excalibur.merlin.Controller;
   
   /**
    * A <code>Container</code> is a manager of a set of components and as such, is responsible 
    * for the establishment, deployment and decommissioning of components.  A container is a 
    * a {@link Controller} and as such can handle startup and shutdown requests.  On startup, 
    * a container is resoponsible for the orderly startup of the components it is managing.  On 
  - * shutdown the container is resposible for orderly service decommissioning.  As a 
  - * {@link Verifiable} object, a container is varified if all of the compoenent profiles it 
  - * is managing are verifiable. 
  + * shutdown the container is resposible for orderly service decommissioning.  
    *
    * <p><b>UML</b></p>
    * <p><image src="doc-files/Container.gif" border="0"/></p>
  @@ -30,9 +27,90 @@
    * @version $Revision$ $Date$
    * @see DefaultContainer
    */
  -public interface Container extends Controller, Verifiable
  +public interface Container extends Controller
   {
   
  +
  +   /**
  +    * Static state enumeration value indicating that the state of a container is unknown.
  +    */
  +    static final int UNKNOWN = 0;
  +
  +   /**
  +    * Static state enumeration value indicating that a container has been initialized, 
  +    * all of its subsidiary containers have been initialized, and all component profiles
  +    * have been assembled.
  +    */
  +    static final int INITIALIZED = 1;
  +
  +   /**
  +    * Static state enumeration value indicating that a container has completed
  +    * lifecycle processing on all components requesting startup establishment.
  +    */
  +    static final int STARTED = 2;
  +
  +   /**
  +    * Static state enumeration value indicating that a container has completed
  +    * the shutdown of all subsidiary containers and the internal components 
  +    * have been shutdown.
  +    */
  +    static final int STOPPED = 3;
  +
  +   /**
  +    * Static state enumeration value indicating that a container and all
  +    * subsidiary containers have been disposed of.
  +    */
  +    static final int DISPOSED = 4;
  +
  +   /**
  +    * Return the container name.
  +    *
  +    * @return the name of the container
  +    */
  +    String getName();
  +
  +   /**
  +    * Return the current state of the container.
  +    *
  +    * @return the container state
  +    */
  +    int getState();
  +
  +   /**
  +    * Adds a <code>StateListener</code> to the container.  A state listener 
  +    * will be informaed of changes to the state of the container it is listening to.
  +    * 
  +    * @param listener the listener to add to the container
  +    */
  +    void addStateListener( StateListener listener );
  +
  +   /**
  +    * Removes a <code>StateListener</code> from the container.
  +    *
  +    * @param listener the listener to remove from the container
  +    */
  +    void removeStateListener( StateListener listener );
  +
  +   /**
  +    * Adds a <code>ContainerListener</code> to the container.  The listener will be 
  +    * informed of the addition and removal of containers from/to the tartget container.
  +    *
  +    * @param listener the container listener to add
  +    */
  +    void addContainerListener( ContainerListener listener );
  +
  +   /**
  +    * Removes a <code>ContainerListener</code>.
  +    */
  +    void removeContainerListener( ContainerListener listener );
  +
  +   /**
  +    * Returns the set of subsidiary continers container within this container.
  +    *
  +    * @return the containers
  +    */
  +    Container[] getContainers();
  +
      /**
       * Post-assembly function that returns the set of resources 
       * available from the container.
  @@ -41,9 +119,11 @@
       */
       Resource[] getResources();
   
  -    Type getType( String classname );
  -
  -    public void include( Profile profile ) throws Exception;
  +   /**
  +    * Add and assemble the supplied set of profiles.
  +    * @param profiles the profiles to assemble
  +    */
  +    public void install( Profile[] profiles ) throws Exception;
   
   
   }
  
  
  
  1.24      +355 -217  jakarta-avalon-excalibur/assembly/src/java/org/apache/excalibur/merlin/container/DefaultContainer.java
  
  Index: DefaultContainer.java
  ===================================================================
  RCS file: /home/cvs/jakarta-avalon-excalibur/assembly/src/java/org/apache/excalibur/merlin/container/DefaultContainer.java,v
  retrieving revision 1.23
  retrieving revision 1.24
  diff -u -r1.23 -r1.24
  --- DefaultContainer.java	3 Aug 2002 10:52:45 -0000	1.23
  +++ DefaultContainer.java	4 Aug 2002 06:43:20 -0000	1.24
  @@ -59,12 +59,11 @@
   import org.apache.avalon.excalibur.extension.DefaultPackageRepository;
   import org.apache.avalon.excalibur.logger.LoggerManager;
   import org.apache.excalibur.meta.info.Type;
  -import org.apache.excalibur.meta.info.Type;
   import org.apache.excalibur.meta.info.ServiceDescriptor;
   import org.apache.excalibur.meta.info.DependencyDescriptor;
   import org.apache.excalibur.meta.info.ReferenceDescriptor;
  -import org.apache.excalibur.meta.verifier.VerifyException;
   import org.apache.excalibur.merlin.assembly.TypeManager;
  +import org.apache.excalibur.merlin.assembly.TypeException;
   import org.apache.excalibur.merlin.assembly.ContainerManager;
   import org.apache.excalibur.merlin.assembly.DefaultLoggerManager;
   import org.apache.excalibur.merlin.container.Container;
  @@ -73,10 +72,7 @@
   import org.apache.excalibur.merlin.model.Profile;
   import org.apache.excalibur.merlin.model.Resource;
   import org.apache.excalibur.merlin.model.CategoriesDescriptor;
  -import org.apache.excalibur.merlin.model.verifier.AssemblyVerifier;
  -import org.apache.excalibur.merlin.model.verifier.MetaDataVerifier;
   import org.apache.excalibur.merlin.model.builder.XMLContainerUtil;
  -import org.apache.excalibur.merlin.Verifiable;
   import org.apache.excalibur.merlin.Controller;
   
   /**
  @@ -88,7 +84,7 @@
    * @author <a href="mailto:mcconnell@apache.org">Stephen McConnell</a>
    * @version $Revision$ $Date$
    */
  -public class DefaultContainer extends AbstractLogEnabled implements Container, Contextualizable, Configurable, Initializable, Disposable, Runnable
  +public class DefaultContainer extends AbstractLogEnabled implements Container, Contextualizable, Configurable, Initializable, Disposable, Runnable, StateListener
   {
       //=======================================================================
       // static
  @@ -102,22 +98,18 @@
       private static final Resources REZ =
           ResourceManager.getPackageResources( DefaultContainer.class );
   
  -   /**
  -    * Static enumerations used in m_action and m_last where m_action is the requested 
  -    * state of the container and m_last is the current state of the container.
  -    */
  -    private static final int UNKNOWN = 0;
  -    private static final int INITIALIZE = 1;
  -    private static final int STARTUP = 2;
  -    private static final int SHUTDOWN = 3;
  -    private static final int DISPOSE = 4;
  -
       //=======================================================================
       // state
       //=======================================================================
   
      /**
  -    * The list of embedded containers.
  +    * Utility class that provides support for marshalling an XML configuration
  +    * into meta-data and meta-info instances.
  +    */
  +    private XMLContainerUtil m_creator = new XMLContainerUtil();
  +
  +   /**
  +    * The list of initialized embedded containers wrapped in Container instances.
       */
       private List m_containers = new LinkedList();
   
  @@ -132,44 +124,41 @@
       private ContainerDescriptor m_descriptor;
   
      /**
  -    * Flag showing initialization status.
  +    * A possible empty configuration supplied to the container that may 
  +    * container componet profiles and subsidiary container declarations.
       */
  -    private boolean m_initialized = false;
  +    private Configuration m_configuration;
   
      /**
  -    * Flag showing started status.
  +    * The thread periodically checks for state change requests enter in 
  +    * the m_action state member and attempts to bring the m_state value to 
  +    * be equal to the m_action value and once achieved goes off for a little 
  +    * sleep.
       */
  -    private boolean m_started = false;
  +    private Integer m_action = new Integer( UNKNOWN );
   
      /**
  -    * Flag showing stopped status.
  +    * The container is managed as a thread under which the current state 
  +    * is recorded in the m_state state member.
       */
  -    private boolean m_stopped = false;
  -
  -
  -    private Configuration m_configuration;
  -
  -    private XMLContainerUtil m_creator = new XMLContainerUtil();
  +    private int m_state = UNKNOWN;
   
      /**
  -    * The thread periodically checks for state change requests enter in 
  -    * the m_action state member and attemopts to bring the m_lst value to 
  -    * be equal to the m_action value and once achieved, goes off for a little 
  -    * rest.
  +    * The set of state listeners listening to this container.
       */
  -    private Integer m_action = new Integer( UNKNOWN );
  +    private ArrayList m_stateListeners = new ArrayList();
   
      /**
  -    * The container is managed as a thread under which the current state 
  -    * is recorded in the m_last state member.
  +    * The set of content listeners listening to this container.
       */
  -    private Integer m_last = new Integer( UNKNOWN );
  +    private ArrayList m_containerListeners = new ArrayList();
   
      /**
  -    * The thread group reference - used during dispose to wait for termaintaion
  -    * of subsidiary threads.
  +    * The thread that this container will run within - established during initialization
  +    * follwing which the container manager is associated as the container's context 
  +    * classloader.
       */
  -    private ThreadGroup m_group;
  +    private Thread m_thread;
   
       //=======================================================================
       // Contextualizable
  @@ -187,7 +176,6 @@
       {
           m_manager = (ContainerManager) context.get( MANAGER_KEY );
           m_descriptor = m_manager.getContainerDescriptor();
  -        m_group = new ThreadGroup( m_descriptor.getName() );
       }
   
       //=======================================================================
  @@ -205,23 +193,83 @@
       }
   
       //=======================================================================
  +    // Runnable
  +    //=======================================================================
  +
  +   /**
  +    * Invoked by the parent to initiate the thread after which the thread will 
  +    * monitor action requests arrising from initialize, startup, shutdown and dispose
  +    * requests.
  +    */
  +    public void run()
  +    {
  +        if( m_manager == null )
  +          throw new IllegalStateException("Container has not been contextualized.");
  +        Thread.currentThread().setContextClassLoader( m_manager );
  +        try
  +        {
  +            handleInitialize();
  +        }
  +        catch( Throwable e )
  +        {
  +            final String error = "Unexpected error during container initialization.";
  +            throw new ContainerRuntimeException( error, e );
  +        }
  +
  +        try
  +        {
  +            while( m_action.intValue() < DISPOSED )
  +            {
  +                synchronized( m_action )
  +                {
  +                    if( m_state != m_action.intValue() )
  +                    {
  +                        switch( m_action.intValue() )
  +                        {
  +                             case STARTED:
  +                                 if( m_state == INITIALIZED )
  +                                   handleStartup();
  +                                 break;
  +                             case STOPPED:
  +                                 if( m_state == STARTED )
  +                                   handleShutdown();
  +                                 break;
  +                        }
  +                    }
  +                }
  +                sleep();
  +            }
  +            handleDispose();
  +        }
  +        catch( Throwable e )
  +        {
  +            final String error = "Unexpected error during container execution.";
  +            throw new ContainerRuntimeException( error, e );
  +        }
  +    }
  +
  +    //=======================================================================
       // Initializable
       //=======================================================================
   
      /**
  -    * Initalization of a <code>Container</code>.  Initilization of types and
  -    * associated provides (inplicit, explicit and packaged) is undertaken 
  -    * following which primary propulation the container's components preceeds
  -    * the establishment of subsidiary containers.
  +    * Initalization of a <code>Container</code>.  The implementation launches
  +    * a new thread of execution within which the primary initalization actions
  +    * are undertaken during which all declared component {@link Profile} 
  +    * and subsidiary {@link ContainerDescriptor} instances are added to the 
  +    * container model.  Component profiles are assembled using the 
  +    * container {@link ContainerManager}, followed by the creation and 
  +    * initialization of the subsidiary containers.
       *
  -    * @exception Exception if an error occurs during initialization.
  +    * @exception Exception never throw but declared in order for specilized
  +    *   containers to manage local exceptions.  If a container initialization
  +    *   occurs it will raise a ContainerRuntimeException under the thread
  +    *   that is running this container.
       */
       public void initialize() throws Exception
       {
  -        synchronized( m_action )
  -        {
  -            m_action = new Integer( INITIALIZE );
  -        }
  +        m_thread = new Thread( (Runnable) this );
  +        m_thread.start();
       }
   
      /**
  @@ -231,16 +279,30 @@
       */
       public void handleInitialize() throws Exception
       {
  -        getLogger().info( "initialization" );
  +        if( m_state >= INITIALIZED ) 
  +          return;
  +
  +        getLogger().debug( "initialization" );
   
           Configuration[] components = m_configuration.getChildren("component");
           for( int i=0; i<components.length; i++ )
           {
               Configuration config = components[i];
  -            Type type = m_manager.loadType( config.getAttribute("class") );
  -            Profile profile = m_creator.createProfile( type, config );
  -            m_descriptor.addComponent( profile );
  -            m_manager.addProfile( profile );
  +            final String classname = config.getAttribute("class");
  +            try
  +            {
  +                Type type = m_manager.getType( classname );
  +                Profile profile = m_creator.createProfile( type, config );
  +                m_descriptor.addComponent( profile );
  +                m_manager.addProfile( profile );
  +            }
  +            catch( TypeException e )
  +            {
  +                final String warning =
  +                  "Ignoring component declaration at " + config.getLocation() 
  +                  + " due to unknown type: " + classname;
  +                getLogger().warn( warning );
  +            }
           }
   
           // 
  @@ -270,87 +332,26 @@
           for( int i=0; i<configs.length; i++ )
           {
               final Configuration conf = configs[i];
  -            m_containers.add( createContainer( conf ) );
  +            Container container = createContainer( conf );
  +            m_containers.add( container );
           }
   
  -        //
  -        // declare initialization completed
  -        //
  -
  -        m_initialized = true;
  -        m_last = new Integer( INITIALIZE );
  -
  -    }
  -
  -    //=======================================================================
  -    // Runnable
  -    //=======================================================================
  -
  -   /**
  -    * Invoked by the parent to initiate the thread after which the thread will 
  -    * monitor action requests arrising from initize, startup, shutdown and dispose
  -    * requests.
  -    */
  -    public void run()
  -    {
  -        if( m_manager == null )
  -          throw new IllegalStateException("Container has not been contextualized.");
  -        Thread.currentThread().setContextClassLoader( m_manager );
  -
  -        try
  +        getLogger().debug("commence wait" );
  +        while( !hasAchievedState( INITIALIZED ) )
           {
  -            while( m_action.intValue() < DISPOSE )
  +            try
               {
  -                synchronized( m_action )
  -                {
  -                    if( m_last.intValue() != m_action.intValue() )
  -                    {
  -                        switch( m_action.intValue() )
  -                        {
  -                        case INITIALIZE:
  -                          handleInitialize();
  -                          break;
  -                        case STARTUP:
  -                          handleStartup();
  -                          break;
  -                        case SHUTDOWN:
  -                          handleShutdown();
  -                          break;
  -                        }
  -                    }
  -                }
                   sleep();
               }
  -            handleDispose();
  -        }
  -        catch( Throwable e )
  -        {
  -            final String error = "Unexpected error during container execution.";
  -            throw new ContainerRuntimeException( error, e );
  -        }
  -    }
  -
  -    //=======================================================================
  -    // Verifiable
  -    //=======================================================================
  -
  -   /**
  -    * Method invoked by a parent container to request type and assembly validation of 
  -    * this container.
  -    *
  -    * @exception ValidationException if a validation failure occurs
  -    */
  -    public void verify() throws VerifyException
  -    {
  -        verifyContainer();
  -        Iterator iterator = m_containers.iterator();
  -        while( iterator.hasNext() )
  -        {
  -            ((Verifiable)iterator.next()).verify();
  +            catch( Throwable e )
  +            {
  +            }
           }
  +        m_state = INITIALIZED;
  +        getLogger().debug("initialized" );
  +        fireStateChange( new StateEvent( this, INITIALIZED ) );
       }
   
  -
       //======================================================================
       // Controller
       //======================================================================
  @@ -362,7 +363,7 @@
       {
           synchronized( m_action )
           {
  -            m_action = new Integer( STARTUP );
  +            m_action = new Integer( STARTED );
           }
       }
   
  @@ -371,8 +372,16 @@
       */
       private void handleStartup() throws Exception
       {
  -        if( !m_initialized )
  -          handleInitialize();
  +        if( m_state < INITIALIZED )
  +          throw new IllegalStateException(
  +            "Container has not been initialized.");
  +
  +        if( m_state == STARTED )
  +          return;
  +
  +        if( m_state > STARTED )
  +          throw new IllegalStateException(
  +            "Container has already passed through start phase.");
   
           if( getLogger().isDebugEnabled() )
             getLogger().debug("container startup");
  @@ -387,12 +396,15 @@
           Iterator iterator = m_containers.iterator();
           while( iterator.hasNext() )
           {
  -            ((Controller)iterator.next()).startup();
  +            ((Container)iterator.next()).startup();
           }
   
  +        while( !hasAchievedState( STARTED ) )
  +          sleep();
  +
           getLogger().debug("container startup complete");
  -        m_started = true;
  -        m_last = new Integer( STARTUP );
  +        m_state = STARTED;
  +        fireStateChange( new StateEvent( this, STARTED ) );
       }
   
      /**
  @@ -432,7 +444,7 @@
       {
           synchronized( m_action )
           {
  -            m_action = new Integer( SHUTDOWN );
  +            m_action = new Integer( STOPPED );
           }
       }
   
  @@ -441,9 +453,15 @@
       */
       public void handleShutdown()
       {
  -        if( !m_started )
  +        if( m_state < STARTED )
  +          return;
  +
  +        if( m_state == STOPPED )
             return;
   
  +        if( m_state > STOPPED )
  +          throw new IllegalStateException("Already stopped.");
  +
           if( getLogger().isDebugEnabled() )
             getLogger().debug("container shutdown");
   
  @@ -455,14 +473,17 @@
           Iterator iterator = m_containers.iterator();
           while( iterator.hasNext() )
           {
  -            ((Controller)iterator.next()).shutdown();
  +            ((Container)iterator.next()).shutdown();
           }
   
           stop();
   
  +        while( !hasAchievedState( STOPPED ) )
  +          sleep();
  +
           getLogger().debug("container shutdown complete");
  -        m_stopped = true;
  -        m_last = new Integer( SHUTDOWN );
  +        m_state = STOPPED;
  +        fireStateChange( new StateEvent( this, STOPPED ) );
       }
   
      /**
  @@ -497,19 +518,113 @@
           m_manager.stop();
       }
   
  +    //=======================================================================
  +    // StateListener
  +    //=======================================================================
  +
  +   /**
  +    * Method invoked when the root container state changes.  When subsidiary
  +    * containers transition to intialized state they will be published
  +    * by this container under a {@link ContainerEvent} event.
  +    */
  +    public void stateChanged( StateEvent event )
  +    {
  +        int state = event.getState();
  +        Container container = (Container) event.getSource();
  +        switch( state )
  +        {
  +            case INITIALIZED:
  +                getLogger().debug( 
  +                      "subsidiary container initialized: " + container.getName() );
  +                fireStructuralChange( 
  +                  new ContainerEvent( this, container, ContainerEvent.ADD ) ); 
  +                break;
  +            case DISPOSED:
  +                getLogger().debug(
  +                      "removing subsidiary container: " + container.getName() );
  +                container.removeStateListener( this );
  +                m_containers.remove( container );
  +                fireStructuralChange( 
  +                  new ContainerEvent( this, container, ContainerEvent.REMOVE ) ); 
  +        }
  +    }
   
       //=======================================================================
       // Container
       //=======================================================================
   
      /**
  +    * Return the container name.
  +    *
  +    * @return the name of the container
  +    */
  +    public String getName()
  +    {
  +        return m_descriptor.getName();
  +    }
  +
  +   /**
  +    * Return the current state of the container.
  +    *
  +    * @return the container state
  +    */
  +    public int getState()
  +    {
  +        return m_state;
  +    }
  +
  +   /**
  +    * Adds a <code>StateListener</code>.
  +    */
  +    public void addStateListener( StateListener listener )
  +    {
  +	  synchronized( m_stateListeners )
  +	  {
  +            m_stateListeners.add( listener );
  +        }
  +    }
  +
  +   /**
  +    * Removes a <code>StateListener</code>.
  +    */
  +    public void removeStateListener( StateListener listener )
  +    {
  +	  synchronized( m_stateListeners )
  +	  {
  +            m_stateListeners.remove( listener );
  +        }
  +    }
  +
  +   /**
  +    * Adds a <code>ContainerListener</code>.
  +    */
  +    public void addContainerListener( ContainerListener listener )
  +    {
  +	  synchronized( m_containerListeners )
  +	  {
  +            m_containerListeners.add( listener );
  +        }
  +    }
  +
  +   /**
  +    * Removes a <code>ContainerListener</code>.
  +    */
  +    public void removeContainerListener( ContainerListener listener )
  +    {
  +	  synchronized( m_containerListeners )
  +	  {
  +            m_containerListeners.remove( listener );
  +        }
  +    }
  +
  +   /**
       * Return the set of resources exported by this container.
       *
       * @return the set of exported resources
       */
       public Resource[] getResources()
       {
  -        if( !m_initialized )
  +        if( m_state < INITIALIZED )
             throw new IllegalStateException("not-initialized");
   
           ArrayList list = new ArrayList();
  @@ -533,15 +648,28 @@
           return (Resource[]) list.toArray( new Resource[0] );
       }
   
  -    public Type getType( String classname )
  +   /**
  +    * Returns the set of subsidiary continers container within this container.
  +    *
  +    * @return the containers
  +    */
  +    public Container[] getContainers()
       {
  -        return m_manager.getType( classname );
  +        return (Container[]) m_containers.toArray( new Container[0] );
       }
   
  -    public void include( Profile profile ) throws Exception
  +   /**
  +    * Add and assemble the supplied set of profiles.
  +    * @param profiles the profiles to assemble
  +    * @exception Exception if an assembly error occurs
  +    */
  +    public void install( Profile[] profiles ) throws Exception
       {
  -        m_manager.addProfile( profile );
  -        m_manager.assemble( new Profile[]{ profile } );
  +        for( int i=0; i<profiles.length; i++ )
  +        {
  +            m_manager.addProfile( profiles[i] );
  +        }
  +        m_manager.assemble( profiles );
       }
   
       //=======================================================================
  @@ -555,7 +683,7 @@
       {
           synchronized( m_action )
           {
  -            m_action = new Integer( DISPOSE );
  +            m_action = new Integer( DISPOSED );
           }
       }
   
  @@ -564,29 +692,34 @@
       */
       private void handleDispose()
       {
  -        if( m_started )
  +        if( m_state == STARTED )
           {
  -            if( !m_stopped )
                  handleShutdown();
           }
  -        getLogger().debug("dispose");
   
           //
           // dispose of all of the nested containers
           //
   
  +        getLogger().debug("dispose");
           Iterator iterator = m_containers.iterator();
           while( iterator.hasNext() )
           {
  -            ((Disposable)iterator.next()).dispose();
  +            Container container = (Container)iterator.next();
  +            if( container instanceof Disposable )
  +            {
  +               ((Disposable)container).dispose();
  +            }
           }
   
  -        while( m_group.activeCount() > 0 )
  -             sleep();
  +        while( !hasAchievedState( DISPOSED ) )
  +            sleep();
   
           m_manager.dispose();
   
  -        getLogger().info("done");
  +        getLogger().debug("done");
  +        m_state = DISPOSED;
  +        fireStateChange( new StateEvent( this, DISPOSED ) );
       }
   
       //=======================================================================
  @@ -594,68 +727,64 @@
       //=======================================================================
   
      /**
  -    * Internal verification of the container.
  -    *
  -    * @exception ValidationException if a validation failure occurs
  +    * Notifies all state listeners of a change in the state of the container.
  +    * @param event the state event.
       */
  -    private void verifyContainer() throws VerifyException
  +    protected void fireStateChange( StateEvent event )
       {
  -        getLogger().debug("verify");
  -        /*
  -        Profile[] profiles = m_manager.getStartupGraph( false );
  -        MetaDataVerifier mdv = new MetaDataVerifier();
  -        for( int i=0; i<profiles.length; i++ )
  -        {
  -            try
  +        synchronized( m_stateListeners )
  +	  {
  +            StateListener[] listeners = (StateListener[]) m_stateListeners.toArray( new StateListener[0] );
  +            for( int i=0; i<listeners.length; i++ )
               {
  -                mdv.verifyType( profiles[i], m_manager );
  -            }
  -            catch( Throwable e )
  -            {
  -                getLogger().error("verification failure", e );
  -            }
  -        }
  -
  -        AssemblyVerifier verifier = new AssemblyVerifier();
  -        verifier.enableLogging( getLogger().getChildLogger("verifier") );
  -        getLogger().debug("commencing assembly verification");
  -        verifier.verifyAssembly( profiles );
  -        listProfiles( profiles );
  -        */
  +                StateListener listener = listeners[i];
  +		    try
  +		    {
  +	  	        listener.stateChanged( event );
  +                }
  +		    catch( Exception e )
  +		    {
  +                    m_stateListeners.remove( listener );
  +			  final String warning = 
  +                      "State listener raised on error on notification. Removing listener: "
  +                      + listener;
  +			  if( getLogger().isWarnEnabled() ) 
  +                      getLogger().warn( warning );
  +		    }
  +	      }
  +	  }
       }
   
  -/*
  -    private void listProfiles( Profile[] profiles )
  -    {
  -        getLogger().debug("listing profiles");
  -        List reported = new LinkedList();
  -        for( int i=0; i<profiles.length; i++ )
  -        {
  -            listProfile( i+1, profiles[i], m_map, reported );
  -        }
  -    }
   
  -    private void listProfile( int n, Profile profile, DependencyGraph map, List reported )
  -    {
  -        if( !reported.contains( profile ) )
  -        {
  -            reported.add( profile );
  -            getLogger().debug( "" + n + ": " + profile.toString() );
  -            Profile[] suppliers = map.getProviderGraph( profile );
  -            for( int j=0; j<suppliers.length; j++ )
  -            {
  -                Profile supplier = suppliers[j];
  -                getLogger().debug("   supplier: " + supplier );
  -            }
  -            Profile[] consumers = map.getConsumerGraph( profile );
  -            for( int j=0; j<consumers.length; j++ )
  +   /**
  +    * Notifies all content listeners of a change in the content of the container.
  +    * @param event the content event.
  +    */
  +    protected void fireStructuralChange( ContainerEvent event )
  +    {
  +        synchronized( m_containerListeners )
  +	  {
  +            ContainerListener[] listeners = 
  +              (ContainerListener[]) m_containerListeners.toArray( new ContainerListener[0] );
  +            for( int i=0; i<listeners.length; i++ )
               {
  -                Profile consumer = consumers[j];
  -                getLogger().debug("   consumer: " + consumer.getName() );
  -            }
  -        }
  +                ContainerListener listener = listeners[i];
  +		    try
  +		    {
  +	  	        listener.structuralChange( event );
  +                }
  +		    catch( Exception e )
  +		    {
  +                    m_containerListeners.remove( listener );
  +			  final String warning = 
  +                      "Container listener raised on error on notification. Removing listener: "
  +                      + listener;
  +			  if( getLogger().isWarnEnabled() ) 
  +                      getLogger().warn( warning );
  +		    }
  +	      }
  +	  }
       }
  -*/
   
      /**
       * Internal utility to create a subsidiary container.
  @@ -686,7 +815,7 @@
           
           try
           {
  -            getLogger().info("creating subsidiary container: " + name );
  +            getLogger().debug("creating subsidiary container: " + name );
               DefaultContext context = new DefaultContext();
               context.put( MANAGER_KEY, manager );
               context.makeReadOnly();
  @@ -698,16 +827,7 @@
               container.enableLogging( logger );
               container.contextualize( context );
               container.configure( config );
  -
  -            Thread thread = new Thread( m_group, container, name );
  -            thread.start();
  -
  -            //
  -            // once the thread is started, the manager assigned to the context 
  -            // will be assigned as the thread's context classloader and we can 
  -            // initiate initialization with confidence
  -            //
  -
  +            container.addStateListener( this );
               container.initialize( );
               return container;
           }
  @@ -751,5 +871,23 @@
           catch( Throwable wakeup )
           {
           }
  +    }
  +
  +   /**
  +    * Internal utility to check if all of the subsidiary containers have 
  +    * achieved a particular state.  The implementation tests if ever container
  +    * has achieved a state greater than or equal to the supplied state.
  +    * @return TRUE if all of the containers have reached or exceed the supplied state
  +    */
  +    private boolean hasAchievedState( int state )
  +    {
  +        Iterator iterator = m_containers.iterator();
  +        while( iterator.hasNext() )
  +        {
  +            Container container = (Container)iterator.next();
  +            if( container.getState() < state )
  +              return false;
  +        }
  +        return true;
       }
   }
  
  
  
  1.7       +1 -5      jakarta-avalon-excalibur/assembly/src/java/org/apache/excalibur/merlin/container/DefaultContainer.xinfo
  
  Index: DefaultContainer.xinfo
  ===================================================================
  RCS file: /home/cvs/jakarta-avalon-excalibur/assembly/src/java/org/apache/excalibur/merlin/container/DefaultContainer.xinfo,v
  retrieving revision 1.6
  retrieving revision 1.7
  diff -u -r1.6 -r1.7
  --- DefaultContainer.xinfo	2 Aug 2002 06:36:10 -0000	1.6
  +++ DefaultContainer.xinfo	4 Aug 2002 06:43:20 -0000	1.7
  @@ -18,11 +18,7 @@
     </component>
   
     <context>
  -    <entry key="classloader" type="org.apache.excalibur.merlin.assembly.ContainerManager" optional="false"/>
  -    <entry key="logging" type="org.apache.excalibur.merlin.assembly.DefaultLoggerManager" optional="false"/>
  -    <entry key="descriptor" type="org.apache.excalibur.merlin.model.ContainerDescriptor" optional="false"/>
  -    <entry key="map" type="org.apache.excalibur.merlin.assembly.DependencyGraph" optional="false"/>
  -    <entry key="container" type="org.apache.excalibur.merlin.container.Container" optional="true"/>
  +    <entry key="manager" type="org.apache.excalibur.merlin.assembly.ContainerManager" optional="false"/>
     </context>
   
     <services>
  
  
  
  1.1                  jakarta-avalon-excalibur/assembly/src/java/org/apache/excalibur/merlin/container/ContainerEvent.java
  
  Index: ContainerEvent.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software License
   * version 1.1, a copy of which has been included with this distribution in
   * the LICENSE.txt file.
   */
  
  package org.apache.excalibur.merlin.container;
  
  import java.util.EventObject;
  import org.apache.excalibur.merlin.model.Profile;
  
  /**
   * The <code>ContentEvent</code> is an event raised by a container
   * signally the addition or removal of a component profile.
   */
  
  public class ContainerEvent extends EventObject
  {
  
      //============================================================
      // static
      //============================================================
  
      public static final int ADD = 0;
      public static final int REMOVE = 1;
  
      //============================================================
      // state
      //============================================================
  
     /**
      * The container added or removed from the source container.
      */
      private final Container m_container;
  
     /**
      * Mode value indicating (@link #ADD} or {@link #REMOVE} of a container
      * from the source container.
      */
      private final int m_mode;
  
      //============================================================
      // constructor
      //============================================================
  
     /**
      * Creation of a new ContainerEvent.
      *
      * @param container the source container
      * @param container the container that has been added or removed
      * @param mode int value of (@link #ADD} or {@link #REMOVE}
      */
      public ContainerEvent( Container source, Container container, int mode ) 
      {
          super( source );
          this.m_container = container;
          this.m_mode = mode;
      }
  
      //============================================================
      // ContainerEvent
      //============================================================
  
     /**
      * Returns the container issuing the event.
      * @return the source container
      */
      public Container getContainer()
      {
          return (Container) getSource();
      }
  
     /**
      * Returns the container that was added or removed from the source container.
      */
      public Container getChildContainer()
      {
          return m_container;
      }
  
     /**
      * Returns the event mode.
      */
      public int getMode()
      {
          return m_mode;
      }
  }
  
  
  
  
  1.1                  jakarta-avalon-excalibur/assembly/src/java/org/apache/excalibur/merlin/container/ContainerListener.java
  
  Index: ContainerListener.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software License
   * version 1.1, a copy of which has been included with this distribution in
   * the LICENSE.txt file.
   */
  
  package org.apache.excalibur.merlin.container;
  
  
  /**
   * A <code>ContainerListener</code> listens to <code>ContainerEvent</code> events
   * singnalling the addition and removal of containers from a source container.
   */
  
  public interface ContainerListener
  {
  
     /**
      * Method invoked when a container is added or removed from a container.
      */
      public void structuralChange( ContainerEvent event );
  
  }
  
  
  
  1.1                  jakarta-avalon-excalibur/assembly/src/java/org/apache/excalibur/merlin/container/StateEvent.java
  
  Index: StateEvent.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software License
   * version 1.1, a copy of which has been included with this distribution in
   * the LICENSE.txt file.
   */
  
  package org.apache.excalibur.merlin.container;
  
  import java.util.EventObject;
  
  /**
   * The <code>StateEvent</code> is an event raised by a component
   * signally a change in state.
   */
  public class StateEvent extends EventObject
  {
  
      //============================================================
      // state
      //============================================================
  
     /**
      * Container state.
      */
      private final int m_state;
  
      //============================================================
      // constructor
      //============================================================
  
     /**
      * Creation of a new StateEvent.
      *
      * @param container the source container
      * @param state int value of (@link Container#INITIALIZED}, {@link Container#STARTED}, 
      *    {@link Container#STOPPED} or {@link Container#DISPOSED}
      */
      public StateEvent( Container container, int state ) 
      {
          super( container );
          m_state = state;
      }
  
      //============================================================
      // StateEvent
      //============================================================
     
     /**
      * Returns the container that raised the event.
      * @return the source container under whch the state event occured
      */
      public Container getContainer()
      {
          return (Container) getSource();
      }
  
     /**
      * Returns the state that the component has raised inidicating
      * that the component has completed transitioning to that state.
      */
      public int getState()
      {
          return m_state;
      }
  }
  
  
  
  
  1.1                  jakarta-avalon-excalibur/assembly/src/java/org/apache/excalibur/merlin/container/StateListener.java
  
  Index: StateListener.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software License
   * version 1.1, a copy of which has been included with this distribution in
   * the LICENSE.txt file.
   */
  
  package org.apache.excalibur.merlin.container;
  
  /**
   * A <code>StateListener</code> listens to <code>StateEvent</code> events.
   */
  
  public interface StateListener
  {
  
     /**
      * Method invoked when a container state changes.
      */
      public void stateChanged( StateEvent event );
  
  }
  
  
  
  1.5       +15 -10    jakarta-avalon-excalibur/assembly/src/java/org/apache/excalibur/merlin/container/doc-files/Container.gif
  
  	<<Binary file>>
  
  
  1.6       +37 -32    jakarta-avalon-excalibur/assembly/src/java/org/apache/excalibur/merlin/container/doc-files/DefaultContainer.gif
  
  	<<Binary file>>
  
  
  1.28      +211 -120  jakarta-avalon-excalibur/assembly/src/java/org/apache/excalibur/merlin/kernel/DefaultKernel.java
  
  Index: DefaultKernel.java
  ===================================================================
  RCS file: /home/cvs/jakarta-avalon-excalibur/assembly/src/java/org/apache/excalibur/merlin/kernel/DefaultKernel.java,v
  retrieving revision 1.27
  retrieving revision 1.28
  diff -u -r1.27 -r1.28
  --- DefaultKernel.java	3 Aug 2002 09:29:06 -0000	1.27
  +++ DefaultKernel.java	4 Aug 2002 06:43:20 -0000	1.28
  @@ -59,11 +59,13 @@
   import org.apache.avalon.excalibur.extension.DefaultPackageRepository;
   import org.apache.avalon.excalibur.logger.LoggerManager;
   import org.apache.excalibur.meta.info.Type;
  -import org.apache.excalibur.meta.info.Type;
   import org.apache.excalibur.meta.info.ServiceDescriptor;
   import org.apache.excalibur.meta.info.DependencyDescriptor;
   import org.apache.excalibur.meta.info.ReferenceDescriptor;
   import org.apache.excalibur.meta.info.EntryDescriptor;
  +import org.apache.excalibur.meta.verifier.VerifyException;
  +import org.apache.excalibur.merlin.model.verifier.AssemblyVerifier;
  +import org.apache.excalibur.merlin.model.verifier.MetaDataVerifier;
   import org.apache.excalibur.merlin.model.builder.XMLContainerUtil;
   import org.apache.excalibur.merlin.model.DirsetDescriptor;
   import org.apache.excalibur.merlin.model.ExtensionsDescriptor;
  @@ -78,6 +80,8 @@
   import org.apache.excalibur.merlin.model.LoggingDescriptor;
   import org.apache.excalibur.merlin.container.Container;
   import org.apache.excalibur.merlin.container.DefaultContainer;
  +import org.apache.excalibur.merlin.container.StateListener;
  +import org.apache.excalibur.merlin.container.StateEvent;
   
   /**
    * Default kernel implementation.
  @@ -135,13 +139,13 @@
    * @version $Revision$ $Date$
    */
   public class DefaultKernel extends AbstractLogEnabled
  -  implements Kernel, Contextualizable, Configurable, Initializable, Startable, Disposable
  +  implements Kernel, Contextualizable, Configurable, Initializable, Startable, Disposable, StateListener
   {
       //=======================================================================
       // static
       //=======================================================================
   
  -    public static final String APPLICATION_DIR_KEY = "avalon:home";
  +    public static final String DIR_KEY = "avalon:home";
   
       //=======================================================================
       // state
  @@ -189,12 +193,12 @@
       * Invoked by the bootstrap process to supply the root directory.
       * @param context the context object containing the inital parameters
       * @exception ContextException if the supplied does not contain a 
  -    *   APPLICATION_DIR_KEY value.
  +    *   DIR_KEY value.
       */
       public void contextualize( Context context ) throws ContextException
       {
           m_context = context;
  -        context.get( APPLICATION_DIR_KEY );
  +        context.get( DIR_KEY );
       }
   
       //=======================================================================
  @@ -234,14 +238,11 @@
               ctx.put( ContainerManager.CLASSPATH_DESCRIPTOR_KEY, classpath );
               m_manager.contextualize( ctx );
               m_manager.initialize();
  -
               Thread.currentThread().setContextClassLoader( m_manager );
   
               if( getLogger() == null )
  -            {
                   enableLogging( m_manager.getLoggingManager().getLoggerForCategory( name ) );
  -            }
  -            getLogger().debug("kernel manager established");
  +            getLogger().info("kernel established");
   
           }
           catch( Throwable e )
  @@ -252,20 +253,204 @@
   
           final Configuration config = m_config.getChild("container");
           m_container = createContainer( config );
  +
  +        while( !m_initialized )
  +            sleep();
  +
  +    }
  +
  +    //=======================================================================
  +    // Startable
  +    //=======================================================================
  +
  +   /**
  +    * Invoked by a contrainer to requested disposal of the kernel and all
  +    * consumed resources.
  +    */
  +    public void start() throws Exception
  +    {
  +        startup();
  +    }
  +
  +    public void stop()
  +    {
  +        shutdown();
  +    }
  +
  +    //=======================================================================
  +    // Controller
  +    //=======================================================================
  +
  +
  +    public void startup() throws Exception
  +    {
  +        if( !m_initialized )
  +          throw new IllegalStateException("not initialized");
  +        if( m_stopped )
  +          throw new IllegalStateException("already stopped");
  +        if( m_started )
  +          throw new IllegalStateException("already started");
  +
  +        if( getLogger().isInfoEnabled() )
  +          getLogger().info("startup");
  +
  +        try
  +        {
  +            m_container.startup();
  +        }
  +        catch( Throwable e )
  +        {
  +            final String error = "Kernel startup failure.";
  +            getLogger().error( error, e );
  +            throw new KernelException( error, e );
  +        }
  +
  +        getLogger().info("startup initiated");
  +
  +        while( !m_started )
  +          sleep();
  +
  +        if( getLogger().isInfoEnabled() )
  +          getLogger().info("started");
  +    }
  +
  +    public void shutdown()
  +    {    
  +        if( !m_initialized )
  +          throw new IllegalStateException("not initialized");
  +        if( m_stopped )
  +          throw new IllegalStateException("already stopped");
  +        if( !m_started )
  +          throw new IllegalStateException("not started");
  +
  +        m_container.shutdown();
  +        if( getLogger().isInfoEnabled() )
  +          getLogger().info("shutdown intiated");
  +
  +        while( !m_stopped )
  +          sleep();
  +
  +        if( getLogger().isInfoEnabled() )
  +          getLogger().info("stopped");
  +    }
  +
  +    //=======================================================================
  +    // Disposable
  +    //=======================================================================
  +
  +   /**
  +    * Invoked by a contrainer to requested disposal of the kernel and all
  +    * consumed resources.
  +    */
  +    public void dispose()
  +    {
  +        if( m_container != null )
  +        {
  +            m_container.dispose();
  +            while( !m_disposed )
  +              sleep();
  +        }
  +    }
  +
  +    //=======================================================================
  +    // StateListener
  +    // Listens to the state of the root container.
  +    //=======================================================================
  +
  +   /**
  +    * Method invoked when the root container state changes.
  +    */
  +    public void stateChanged( StateEvent event )
  +    {
  +        int state = event.getState();
  +        switch( state )
  +        {
  +            case Container.INITIALIZED:
  +                m_initialized = true;
  +                getLogger().info("initilialized");
  +                try
  +                {
  +                    verify();
  +                    getLogger().info( "verified" );
  +                    Logger export = getLogger().getChildLogger( "export" );
  +                    if( export.isInfoEnabled() )
  +                    {
  +                        getLogger().info( "listing exportable resources" );
  +                        Resource[] resources = getResources();
  +                        for( int i=0; i<resources.length; i++ )
  +                        {
  +                            export.info( resources[i].getPath() );
  +                        }
  +                    }
  +                }
  +                catch( Throwable e )
  +                {
  +                    getLogger().error("verification failure", e );
  +                    m_container.dispose();
  +                }
  +                break;
  +            case Container.STARTED:
  +                m_started = true;
  +                break;
  +            case Container.STOPPED:
  +                m_stopped = true;
  +                break;
  +            case Container.DISPOSED:
  +                m_disposed = true;
  +                break;
  +        }
  +    }
  +
  +    //=======================================================================
  +    // Kernel
  +    //=======================================================================
  +
  +    public Container getRootContainer()
  +    {
  +        return m_container;
  +    }
  +
  +    public Resource[] getResources()
  +    {
  +        return m_container.getResources();
  +    }
  +
  +   /**
  +    * Internal verification of the container.
  +    *
  +    * @exception ValidationException if a validation failure occurs
  +    */
  +    public void verify() throws VerifyException
  +    {
  +        if( !m_initialized )
  +          throw new IllegalStateException("not initialized");
  +
  +        getLogger().debug("verify");
           
  -        /*
  -        // ### need to resolve some problems here
  -        getLogger().info( "listing exportable resources" );
  -        Resource[] resources = getResources();
  -        Logger export = getLogger().getChildLogger( "export" );
  -        for( int i=0; i<resources.length; i++ )
  +        Profile[] profiles = m_manager.getStartupGraph( false );
  +        MetaDataVerifier mdv = new MetaDataVerifier();
  +        for( int i=0; i<profiles.length; i++ )
           {
  -            export.info( resources[i].getPath() );
  +            try
  +            {
  +                mdv.verifyType( profiles[i], m_manager );
  +            }
  +            catch( Throwable e )
  +            {
  +                getLogger().error("verification failure", e );
  +            }
           }
  -        */
  -        m_initialized = true;
  +
  +        AssemblyVerifier verifier = new AssemblyVerifier();
  +        verifier.enableLogging( getLogger().getChildLogger("verifier") );
  +        getLogger().debug("commencing assembly verification");
  +        verifier.verifyAssembly( profiles );
       }
   
  +    //=======================================================================
  +    // internals
  +    //=======================================================================
  +
      /**
       * Internal utility to create the root container.
       *
  @@ -279,7 +464,7 @@
           String classname = null;
           try
           {
  -            name = config.getAttribute( "name", "root");
  +            name = config.getAttribute( "name", "root" );
               classname = config.getAttribute( "class", DefaultContainer.class.getName() );
               ClasspathDescriptor classpath = 
                 m_creator.createClasspathDescriptor( config.getChild("classpath") );
  @@ -297,7 +482,7 @@
   
           try
           {
  -            getLogger().info("creating root container: " + name );
  +            getLogger().debug("creating root container: " + name );
               DefaultContext context = new DefaultContext();
               context.put( DefaultContainer.MANAGER_KEY, manager );
               context.makeReadOnly();
  @@ -307,10 +492,7 @@
               container.enableLogging( logger );
               container.contextualize( context );
               container.configure( config );
  -            
  -		m_thread = new Thread( (Runnable) container );
  -		m_thread.start();
  -
  +            container.addStateListener( this );
               container.initialize( );
               return container;
           }
  @@ -334,109 +516,18 @@
           }
       }
   
  -    //=======================================================================
  -    // Disposable
  -    //=======================================================================
  -
  -   /**
  -    * Invoked by a contrainer to requested disposal of the kernel and all
  -    * consumed resources.
  -    */
  -    public void dispose()
  -    {
  -        if( m_container != null )
  -        {
  -            m_container.dispose();
  -            try
  -            {
  -                m_thread.join();
  -                getLogger().info("done");
  -            }
  -            catch( InterruptedException ie )
  -            {
  -            }
  -        }
  -    }
  -
  -    //=======================================================================
  -    // Startable
  -    //=======================================================================
  -
      /**
  -    * Invoked by a contrainer to requested disposal of the kernel and all
  -    * consumed resources.
  +    * Internel utility to sleep a bit.
       */
  -    public void start() throws Exception
  +    private void sleep()
       {
  -        if( !m_initialized ) return;
  -        //listProfiles();
  -
  -        if( getLogger().isInfoEnabled() )
  -          getLogger().info("startup");
  -
           try
           {
  -            m_container.startup();
  +            Thread.currentThread().sleep( 100 );
           }
  -        catch( Throwable e )
  +        catch( Throwable wakeup )
           {
  -            final String error = "Kernel startup failure.";
  -            getLogger().error( error, e );
  -            throw new KernelException( error, e );
           }
  -
  -        getLogger().info("startup complete");
  -    }
  -
  -    public void stop()
  -    {
  -        if( !m_initialized ) return;
  -        if( getLogger().isInfoEnabled() )
  -          getLogger().info("shutdown intiated");
  -        m_container.shutdown();
       }
   
  -    //=======================================================================
  -    // Controller
  -    //=======================================================================
  -
  -    public void startup() throws Exception
  -    {
  -        if( !m_initialized )
  -          throw new IllegalStateException("not initialized");
  -        if( m_stopped )
  -          throw new IllegalStateException("already stopped");
  -        if( m_started )
  -          throw new IllegalStateException("already started");
  -
  -        start();
  -        m_started = true;
  -    }
  -
  -    public void shutdown()
  -    {    
  -        if( !m_initialized )
  -          throw new IllegalStateException("not initialized");
  -        if( m_stopped )
  -          throw new IllegalStateException("already stopped");
  -        if( !m_started )
  -          throw new IllegalStateException("not started");
  -
  -        stop();
  -        m_stopped = true;
  -    }
  -
  -    //=======================================================================
  -    // Kernel
  -    //=======================================================================
  -
  -    public Container getRootContainer()
  -    {
  -        return m_container;
  -    }
  -
  -    public Resource[] getResources()
  -    {
  -        return m_container.getResources();
  -    }
   }
  
  
  
  1.11      +9 -1      jakarta-avalon-excalibur/assembly/src/java/org/apache/excalibur/merlin/kernel/Kernel.java
  
  Index: Kernel.java
  ===================================================================
  RCS file: /home/cvs/jakarta-avalon-excalibur/assembly/src/java/org/apache/excalibur/merlin/kernel/Kernel.java,v
  retrieving revision 1.10
  retrieving revision 1.11
  diff -u -r1.10 -r1.11
  --- Kernel.java	30 Jul 2002 13:49:08 -0000	1.10
  +++ Kernel.java	4 Aug 2002 06:43:20 -0000	1.11
  @@ -12,6 +12,7 @@
   import org.apache.excalibur.merlin.model.Resource;
   import org.apache.excalibur.meta.info.ServiceDescriptor;
   import org.apache.excalibur.meta.info.EntryDescriptor;
  +import org.apache.excalibur.meta.verifier.VerifyException;
   
   /**
    * A service that provides support for the establishment of services and service context.
  @@ -23,6 +24,13 @@
    */
   public interface Kernel extends Controller
   {
  +
  +   /**
  +    * Method invoked to request type level validation of the application.
  +    *
  +    * @exception ValidationException if a validation failure occurs
  +    */
  +    void verify() throws VerifyException;
   
       /**
        * Return the set of resources that this kernel is capable of providing.
  
  
  
  1.2       +12 -1     jakarta-avalon-excalibur/assembly/src/java/org/apache/excalibur/meta/info/ReferenceDescriptor.java
  
  Index: ReferenceDescriptor.java
  ===================================================================
  RCS file: /home/cvs/jakarta-avalon-excalibur/assembly/src/java/org/apache/excalibur/meta/info/ReferenceDescriptor.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- ReferenceDescriptor.java	29 Jul 2002 06:14:33 -0000	1.1
  +++ ReferenceDescriptor.java	4 Aug 2002 06:43:20 -0000	1.2
  @@ -39,6 +39,17 @@
        * @param classname the name of the service
        * @param version the version of service
        */
  +    public ReferenceDescriptor( final String classname )
  +    {
  +        this( classname, Version.getVersion( "1.0" ) );
  +    }
  +
  +    /**
  +     * Construct a service with specified name, version and attributes.
  +     *
  +     * @param classname the name of the service
  +     * @param version the version of service
  +     */
       public ReferenceDescriptor( final String classname,
                                 final Version version )
       {
  
  
  

--
To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>