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/03/03 16:51:13 UTC

cvs commit: jakarta-avalon-excalibur/src/scratchpad/org/apache/avalon/excalibur/service DefaultServiceManager.java DependencyInfo.java PipelineException.java PipelineRuntimeException.java ServiceContext.java ServiceFactory.java ServiceInfo.java ServiceLoader.java ServiceLoaderContext.java ServiceProvider.java ServiceRegistry.java SingletonProvider.java TransientProvider.java UnitInfo.java package.html

mcconnell    02/03/03 07:51:13

  Added:       src/scratchpad/org/apache/avalon/excalibur/service
                        DefaultServiceManager.java DependencyInfo.java
                        PipelineException.java
                        PipelineRuntimeException.java ServiceContext.java
                        ServiceFactory.java ServiceInfo.java
                        ServiceLoader.java ServiceLoaderContext.java
                        ServiceProvider.java ServiceRegistry.java
                        SingletonProvider.java TransientProvider.java
                        UnitInfo.java package.html
  Log:
  initial implementation of a service management framework
  
  Revision  Changes    Path
  1.1                  jakarta-avalon-excalibur/src/scratchpad/org/apache/avalon/excalibur/service/DefaultServiceManager.java
  
  Index: DefaultServiceManager.java
  ===================================================================
  /*
   * File: DefaultServiceManager.java
   * License: etc/LICENSE.TXT
   * Copyright: Copyright (C) The Apache Software Foundation. All rights reserved.
   * Copyright: OSM SARL 2002, All Rights Reserved.
   */
  
  package org.apache.avalon.excalibur.service;
  
  import java.util.Enumeration;
  import java.util.Hashtable;
  import org.apache.avalon.framework.service.ServiceManager;
  import org.apache.avalon.framework.service.ServiceException;
  
  
  /**
   * Internal helper class the implements the service manager interface and 
   * is supplied to dynamically crerated componets during service lifecyle
   * pipeline processing.
   */
  class DefaultServiceManager implements ServiceManager
  {
  
     /**
      * Hashtable containing service providers keyed by role name.  
      * The manager use the providers in this table to aquire services
      * in response to <code>lookup</code> invocations.  Provider 
      * types fall into one of the following three catagories:
      *
      * <table>
      * <tr><td><b>Policy</b></td><td><b>Description</b></td><tr>
      * <tr><td>SINGLETON_LIFETIME_POLICY</td><td>
      * Service of the type singleton are distinguished by the fact 
      * that they do not inherit from Pool or Transient.  The singleton
      * provider object is a reference to the singleton service and is 
      * return directly by the implemetation on invocation of lookup.
      * </td>
      * <tr><td>POOLED_LIFETIME_POLICY</td><td>
      * Pooled services implement the Pool interface.  The service
      * resolves lookup aquires the pooled service by invoking 
      * <code>checkout</code> on the pool implementation. Clients 
      * using pooled services are required to release services using
      * the manager <code>release</code> method.  The implemetation will
      * attempt to locate the issuing pool and release the object on 
      * behalf of the client. 
      * </td>
      * <tr><td>TRANSIENT_LIFETIME_POLICY</td><td>
      * A transient provider is factory from which new instances are 
      * created and pipelined following a invocation of <code>lookup</code>.
      * The invocing client is totally responsible for service disposal.
      * </td>
      */
      private Hashtable m_providers = new Hashtable();
  
      public DefaultServiceManager( Hashtable providers ) throws Exception
      {
          m_providers = providers;
      }
  
      public boolean hasService( String role )
      {
          return (m_providers.get( role ) != null );
      }
  
      public Object lookup( String role ) throws ServiceException
      {
          Object provider = m_providers.get( role );
          if( provider == null ) throw new ServiceException(
              "Could not locate a provider for the role: " + role );
  
          if( provider instanceof TransientProvider )
          {
              //
              // return a transient instance
              //
  
              return ((TransientProvider)provider).create( );
          }
  /*
          else if( provider instanceof PooledProvider )
          {
              //
              // return a pooled service
              //
  
              return ((PooledProvider)provider).checkout( );
          }
  */
          else
          {
              //
              // return a singleton service
              //
  
              return ((SingletonProvider)provider).provide( );
          }
      }
  
      public void release( Object object )
      {
          //
          // release a pooled service
          //
  /*
          Class c = object.getClass();
          Enumeration providers = m_providers.elements();
          while( providers.hasMoreElements()) 
          {
              Object provider = providers.nextElement();
              if( provider instanceof PooledProvider )
              {
                  PooledProvider pool = (PooledProvider) provider;
                  if( pool.getBaseClass().isAssignableFrom( c ) )
                  {
                      pool.release( object );
                      break;
                  }
              }
          }
  */
      }
  }
  
  
  
  
  1.1                  jakarta-avalon-excalibur/src/scratchpad/org/apache/avalon/excalibur/service/DependencyInfo.java
  
  Index: DependencyInfo.java
  ===================================================================
  /*
   * File: DependencyInfo.java
   * License: etc/LICENSE.TXT
   * Copyright: Copyright (C) The Apache Software Foundation. All rights reserved.
   * Copyright: OSM SARL 2002, All Rights Reserved.
   */
  
  package org.apache.avalon.excalibur.service;
  
  import org.apache.avalon.framework.configuration.Configuration;
  
  /**
   * Abstract meta-information that describes a single dependancy that a 
   * <code>Serviceable</code> object may have towards other 
   * components.
   */
  
  class DependencyInfo extends ServiceInfo
  {
      private String m_role;
  
     /**
      * Creation of a new <code<DependencyInfo</code> instance.
      * @param config a configuration corresponding to a &lt;depends&gt; statement
      */
      public DependencyInfo( final Configuration config ) throws Exception
      {
          super( config.getChild("service") );
          m_role = config.getChild("role").getValue();
      }
  
     /**
      * Returns the role name that the component uses to lookup a 
      * the dependency.
      * @return the dependecy role name
      * @see org.apache.avalon.framework.service.ServiceManager
      * @see org.apache.avalon.framework.service.Serviceable
      */
      public String getRole()
      {
          return m_role;
      }
  }
  
  
  
  1.1                  jakarta-avalon-excalibur/src/scratchpad/org/apache/avalon/excalibur/service/PipelineException.java
  
  Index: PipelineException.java
  ===================================================================
  /*
   * File: PipelineException.java
   * License: etc/LICENSE.TXT
   * Copyright: Copyright (C) The Apache Software Foundation. All rights reserved.
   * Copyright: OSM SARL 2002, All Rights Reserved.
   */
  
  package org.apache.avalon.excalibur.service;
  
  import java.io.StringWriter;
  import java.util.StringTokenizer;
  import java.io.PrintWriter;
  
  import org.apache.avalon.framework.CascadingException;
  
  /**
   * Thrown by an Pipeline as a result of an unexpected error 
   * during execution.
   *
   * @author  mcconnell
   * @version 1.0
   */
  
  public class PipelineException extends CascadingException {
  
      /**
       * Construct a new <code>PipelineRuntimeException</code> instance with the 
       * supplied message parameter and a null value for the cause exception.
       *
       * @param message Message summarising the exception.
       */
  
      public PipelineException( final String message ) 
      {
          this( message, null );
      }
  
      /**
       * Construct a new <code>PipelineRuntimeException</code> instance with the 
       * supplied message parameter and a supplied cause exception.
       *
       * @param message The detail message for this exception.
       * @param cause the root cause of the exception
       */
  
      public PipelineException( final String message, final Throwable cause ) 
      {
          super( message, cause );
      }
  
      public String toString()
      {
          final StringBuffer sb = new StringBuffer();
          sb.append( "\n=================================================" );
  	  sb.append( "\nException: " + this.getClass().getName() + ", " + getMessage());
  	  if( this.getCause() != null ) appendCause( sb, this.getCause() );
  	  sb.append( "\n=================================================" );
          return sb.toString();
      }
  
      private void appendCause( StringBuffer buffer, Throwable cause )
      {
          if( cause == null ) return;
  	  buffer.append( "\nCause: " + cause.getClass().getName() 
            + ", " + cause.getMessage() );
  	  if( cause.getCause() != null )
          {
              appendCause( buffer, cause.getCause() );
          }
          else
          {
  	      buffer.append( "\n-------------------------------------------------" );
              String[] stack = captureStackTrace( cause );
              for( int i=0; i<stack.length; i++ )
              {
                  buffer.append( "\n" + stack[i] );
              }
          }
      }
  
      private static String[] captureStackTrace( final Throwable throwable )
      {
          final StringWriter sw = new StringWriter();
          throwable.printStackTrace( new PrintWriter( sw, true ) );
          return splitString( sw.toString(), "\n" );
      }
  
      /**
       * Splits the string on every token into an array of stack frames.
       *
       * @param string the string
       * @param onToken the token
       * @return the resultant array
       * @deprecated This is an internal utility method that should not be used
       */
      private static String[] splitString( final String string, final String onToken )
      {
          final StringTokenizer tokenizer = new StringTokenizer( string, onToken );
          final String[] result = new String[ tokenizer.countTokens() ];
  
          for( int i = 0; i < result.length; i++ )
          {
              result[ i ] = tokenizer.nextToken();
          }
  
          return result;
      }
  
  }
  
  
  
  
  1.1                  jakarta-avalon-excalibur/src/scratchpad/org/apache/avalon/excalibur/service/PipelineRuntimeException.java
  
  Index: PipelineRuntimeException.java
  ===================================================================
  /*
   * File: PipelineRuntimeException.java
   * License: etc/LICENSE.TXT
   * Copyright: Copyright (C) The Apache Software Foundation. All rights reserved.
   * Copyright: OSM SARL 2002, All Rights Reserved.
   */
  
  package org.apache.avalon.excalibur.service;
  
  import java.io.StringWriter;
  import java.util.StringTokenizer;
  import java.io.PrintWriter;
  
  import org.apache.avalon.framework.CascadingRuntimeException;
  
  /**
   * Thrown by an Pipeline as a result of an unexpected runtime error 
   * during execution.
   *
   * @author  mcconnell
   * @version 1.0
   */
  
  public class PipelineRuntimeException extends CascadingRuntimeException {
  
      /**
       * Construct a new <code>PipelineRuntimeException</code> instance with the 
       * supplied message parameter and a null value for the cause exception.
       *
       * @param message Message summarising the exception.
       */
  
      public PipelineRuntimeException( final String message ) 
      {
          this( message, null );
      }
  
      /**
       * Construct a new <code>PipelineRuntimeException</code> instance with the 
       * supplied message parameter and a supplied cause exception.
       *
       * @param message The detail message for this exception.
       * @param cause the root cause of the exception
       */
  
      public PipelineRuntimeException( final String message, final Throwable cause ) 
      {
          super( message, cause );
      }
  
      public String toString()
      {
          final StringBuffer sb = new StringBuffer();
          sb.append( "\n=================================================" );
  	  sb.append( "\nException: " + this.getClass().getName() + ", " + getMessage());
  	  if( this.getCause() != null ) appendCause( sb, this.getCause() );
  	  sb.append( "\n=================================================" );
          return sb.toString();
      }
  
      private void appendCause( StringBuffer buffer, Throwable cause )
      {
          if( cause == null ) return;
  	  buffer.append( "\nCause: " + cause.getClass().getName() 
            + ", " + cause.getMessage() );
  	  if( cause.getCause() != null )
          {
              appendCause( buffer, cause.getCause() );
          }
          else
          {
  	      buffer.append( "\n-------------------------------------------------" );
              String[] stack = captureStackTrace( cause );
              for( int i=0; i<stack.length; i++ )
              {
                  buffer.append( "\n" + stack[i] );
              }
          }
      }
  
      private static String[] captureStackTrace( final Throwable throwable )
      {
          final StringWriter sw = new StringWriter();
          throwable.printStackTrace( new PrintWriter( sw, true ) );
          return splitString( sw.toString(), "\n" );
      }
  
      /**
       * Splits the string on every token into an array of stack frames.
       *
       * @param string the string
       * @param onToken the token
       * @return the resultant array
       * @deprecated This is an internal utility method that should not be used
       */
      private static String[] splitString( final String string, final String onToken )
      {
          final StringTokenizer tokenizer = new StringTokenizer( string, onToken );
          final String[] result = new String[ tokenizer.countTokens() ];
  
          for( int i = 0; i < result.length; i++ )
          {
              result[ i ] = tokenizer.nextToken();
          }
  
          return result;
      }
  
  }
  
  
  
  
  1.1                  jakarta-avalon-excalibur/src/scratchpad/org/apache/avalon/excalibur/service/ServiceContext.java
  
  Index: ServiceContext.java
  ===================================================================
  /*
   * File: ServiceContext.java
   * License: etc/LICENSE.TXT
   * Copyright: Copyright (C) The Apache Software Foundation. All rights reserved.
   * Copyright: OSM SARL 2002, All Rights Reserved.
   */
  
  package org.apache.avalon.excalibur.service;
  
  import java.io.File;
  import org.apache.avalon.phoenix.BlockContext;
  import org.apache.avalon.framework.logger.Logger;
  
  import org.apache.avalon.framework.context.DefaultContext;
  
  /**
   * ServiceContext context object to hold command line arguments and 
   * base directory that is supplied to a <code>Contextualizable</code>
   * component.
   * @author <a href="mailto:mcconnell@osm.net">Stephen McConnell</a>
   */
  
  public class ServiceContext extends DefaultContext implements BlockContext
  {
  
      public static final String ARGS_KEY = "ARGS";
      public static final String BASE_DIRECTORY_KEY = "APP_DIR";
  
      private String[] m_args;
      private File m_root;
      private String m_name;
      private Logger m_logger;
  
      public ServiceContext( String[] args, File base, String name )
      {
          m_args = args;
          m_root = base;
          m_name = name;
  
          super.put( ARGS_KEY, m_args );
          super.put( BASE_DIRECTORY_KEY, m_root );
      }
  
      public String[] getArgs()
      {
          return m_args;
      }
  
      public File getBaseDirectory()
      {
          return m_root;
      }
  
      public Logger getLogger( String name )
      {
          throw new RuntimeException("Not implemented.");
      }
  
      public String getName()
      {
          return m_name;   
      }
  }
  
  
  
  1.1                  jakarta-avalon-excalibur/src/scratchpad/org/apache/avalon/excalibur/service/ServiceFactory.java
  
  Index: ServiceFactory.java
  ===================================================================
  /*
   * File: ServiceFactory.java
   * License: etc/LICENSE.TXT
   * Copyright: Copyright (C) The Apache Software Foundation. All rights reserved.
   * Copyright: OSM SARL 2002, All Rights Reserved.
   */
  
  package org.apache.avalon.excalibur.service;
  
  import java.io.File;
  import java.util.Hashtable;
  import java.util.Enumeration;
  import java.util.Vector;
  
  import org.apache.log.Hierarchy;
  import org.apache.log.Priority;
  import org.apache.log.output.io.StreamTarget;
  import org.apache.avalon.framework.logger.Logger;
  import org.apache.avalon.framework.CascadingRuntimeException;
  import org.apache.avalon.framework.CascadingException;
  import org.apache.avalon.framework.logger.LogKitLogger;
  import org.apache.avalon.framework.logger.AvalonFormatter;
  import org.apache.avalon.framework.logger.AbstractLogEnabled;
  import org.apache.avalon.framework.logger.LogEnabled;
  import org.apache.avalon.framework.parameters.Parameterizable;
  import org.apache.avalon.framework.parameters.Parameters;
  import org.apache.avalon.framework.configuration.Configurable;
  import org.apache.avalon.framework.configuration.Configuration;
  import org.apache.avalon.framework.configuration.ConfigurationException;
  import org.apache.avalon.framework.configuration.DefaultConfiguration;
  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.framework.component.Component;
  import org.apache.avalon.framework.component.Composable;
  import org.apache.avalon.framework.component.ComponentManager;
  import org.apache.avalon.framework.component.DefaultComponentManager;
  import org.apache.avalon.framework.component.ComponentException;
  import org.apache.avalon.framework.service.Serviceable;
  import org.apache.avalon.framework.service.ServiceManager;
  import org.apache.avalon.framework.service.ServiceException;
  import org.apache.avalon.framework.activity.Initializable;
  import org.apache.avalon.framework.activity.Startable;
  import org.apache.avalon.framework.activity.Disposable;
  
  import org.apache.avalon.excalibur.configuration.CascadingConfiguration;
  
  /**
   * 
   */
  class ServiceFactory extends AbstractLogEnabled implements Disposable
  {
      private Hierarchy m_hierarchy;
      private ServiceRegistry m_registry;
      private Hashtable m_table = new Hashtable();
      private Hashtable m_pools = new Hashtable();
      private Hashtable m_singletons = new Hashtable();
      private Hashtable m_transients = new Hashtable();
      private File m_root;
      private boolean m_verbose;
  
      private Hashtable m_services = new Hashtable();
      private Hashtable m_lookup = new Hashtable();
  
      public ServiceFactory( Hierarchy hierarchy, Configuration config, File base, boolean verbose ) throws Exception
      {
          m_hierarchy = hierarchy;
          m_registry = new ServiceRegistry( verbose );
          m_table = initalizeBlockConfigurations( config );
          m_root = base;
          m_verbose = verbose;
      }
  
      public void enableLogging( Logger logger )
      {
          super.enableLogging( logger );
          m_registry.enableLogging( logger.getChildLogger("registry") );
      }
  
     /**
      * Populates the set of available services based on a supplied 
      * vector of jar files.
      * @param list a list of jar files
      */
      public void register( Vector list ) throws PipelineException
      {
          m_registry.register( list );
      }
  
      public void validate( UnitInfo info ) throws Exception
      {
          DependencyInfo[] dependencies = info.getDependencies();
          for( int i=0; i<dependencies.length; i++ )
          {
              ServiceInfo d = dependencies[i];
              if( m_registry.lookup( d ) == null ) throw new Exception(
                 "Could not resolve dependent service " + d.getInterface().getName() 
                 + " for block " + info.getClassName() );
          }
      }
  
      private ServiceManager createServiceManager( DependencyInfo[] dependencies ) throws ServiceException
      {
          Hashtable providers = new Hashtable();
          try
          {
              for( int i=0; i<dependencies.length; i++ )
              {
                  DependencyInfo info = dependencies[i];
                  providers.put( info.getRole(), getProvider( info ));
              }
              return new DefaultServiceManager( providers );
          }
          catch( Throwable e )
          {
              final String error = "Unexpected exception while attempting to create a ServiceManager.";
              throw new ServiceException( error, e );
          }
      }
  
      private Object getProvider( DependencyInfo info ) throws Exception
      {
  
          UnitInfo block_info = m_registry.lookup( info );
  
          //
          // Try to establish the type of object by the interface it implements.
          //
  
          Object provider = null;
          Class provider_class = block_info.getBaseClass();
  
          //
          // Resolve the provider based on meta-infomation in the .xinfo file
          // which will result in a transient service if no other info available.
          //
  
          int policy = block_info.getPolicy();
  
          switch( policy )
          {
              case UnitInfo.SINGLETON_LIFETIME_POLICY :
  
                //
                // return a singleton instance
                //
  
                provider = m_singletons.get( provider_class );
                if( provider == null )
                {
                    if( m_verbose ) if( getLogger().isDebugEnabled() ) getLogger().debug( 
                      "Creating singleton provider for :" + provider_class.getName());
  
                    // create and pipeline the singleton instance and 
                    // add it to the list of singletons
  
                    Object object = pipeline( block_info, info.getRole() );
                    provider = new SingletonProvider( object, info.getRole() );
                    m_singletons.put( provider_class, provider );
                }
                return provider;
  
              case UnitInfo.POOLED_LIFETIME_POLICY :
  
                final String error = "Cannot provide a default provider for a pool at this time.";
                throw new RuntimeException( error );
  
              default :
  
                //
                // UnitInfo.TRANSIENT_LIFETIME_POLICY :
                // new service instances are always created on invocation of
                // a service lookup
                //
  
                provider = m_transients.get( provider_class );
                if( provider == null )
                {
                    if( m_verbose ) if( getLogger().isDebugEnabled() ) getLogger().debug( 
                      "Creating transient provider for :" + provider_class.getName());
  
                    // create and pipeline the singleton instance and 
                    // add it to the list of singletons
  
                    provider = new TransientProvider( this, block_info, info.getRole() );
                    m_transients.put( provider_class, provider );
                }
                return provider;
           }
      }
  
      public Object pipeline( UnitInfo info, String role ) throws Exception
      {
  
          //
          // create and pipeline the new instance
          //
  
          Object m_object;
          try
          {
              m_object = info.getBaseClass().newInstance();
          }
          catch( Throwable e )
          {
              final String error = "Failed to instantiate an object: ";
              throw new PipelineException( error + info.getBaseClass().getName(), e );
          }
  
          if( m_verbose ) if( getLogger().isDebugEnabled() ) getLogger().debug(
            "pipeline for role: " + role + ", implementation: " + m_object.getClass().getName() );
  
  
          //
          // assign a logging channel
          //
  
          if( m_object instanceof LogEnabled ) try
          {
              Logger logger = new LogKitLogger( m_hierarchy.getLoggerFor( role ) );
              if( m_verbose ) getLogger().debug( "applying logger to " + role );
              ((LogEnabled)m_object).enableLogging( logger );
          }
          catch( Throwable e )
          {
              final String error = "Failed to assign a logger channel.";
              throw new PipelineException( error, e );
          }
  
          //
          // configure the object
          //
  
          if( m_object instanceof Configurable ) try
          {
              if( m_verbose ) getLogger().debug( role + " configuration" );
              Configuration defaults = info.getDefaultConfiguration();
              Configuration primary = getConfigurationForClass( info.getClassName() );
              ((Configurable)m_object).configure( new CascadingConfiguration( primary, defaults ));
          }
          catch( Throwable e )
          {
              final String error = "Failed to configure an object.";
              throw new PipelineException( error, e );
          }
          else if( m_object instanceof Parameterizable ) try
          {
              if( m_verbose ) getLogger().debug( role + " parameterization" );
              ((Parameterizable)m_object).parameterize( 
                  Parameters.fromConfiguration( getConfigurationForClass( info.getClassName() ) ) );
          }
          catch( Throwable e )
          {
              final String error = "Failed to parameterize an object.";
              throw new PipelineException( error, e );
          }
  
          //
          // contextualize the server
          // [need to update this to handle an args sequence]
          //
  
          if( m_object instanceof Contextualizable ) try
          {
              if( m_verbose ) getLogger().debug( role + " contextualization" );
              Context context = new ServiceContext( 
                new String[0], m_root, info.getClassName() );
              ((Contextualizable)m_object).contextualize( context );
          }
          catch( Throwable e )
          {
              final String error = "Failed to contextualize the object.";
              throw new PipelineException( error, e );
          }
  
          //
          // get the blocks required to support the dependencies
          //
  
          if( m_object instanceof Serviceable ) try
          {
              if( m_verbose ) getLogger().debug( role + " service composition" );
              DependencyInfo[] dependencies = info.getDependencies();
              ServiceManager manager = createServiceManager( dependencies );
              ((Serviceable)m_object).service( manager );
          }
          catch( Throwable e )
          {
              final String error = "Failed to service the object.";
              throw new PipelineException( error, e );
          }
          else if( m_object instanceof Composable ) try
          {
              if( m_verbose ) getLogger().debug( role + " composition" );
              DefaultComponentManager manager = new DefaultComponentManager();
              DependencyInfo[] dependencies = info.getDependencies();
              for( int i=0; i<dependencies.length; i++ )
              {
                  DependencyInfo dependency = dependencies[i];
                  String dependency_role = dependency.getRole();
                  UnitInfo block_info = m_registry.lookup( dependency );
                  Object object = pipeline( block_info, dependency_role );
                  manager.put( dependency_role, (Component) object );
              }
              ((Composable)m_object).compose( manager );
          }
          catch( Throwable e )
          {
              final String error = "Failed to compose the object.";
              throw new PipelineException( error, e );
          }
  
          //
          // initialize the object
          //
  
          if( m_object instanceof Initializable ) try
          {
              if( m_verbose ) getLogger().debug( role + " initilization" );
              ((Initializable)m_object).initialize();
          }
          catch( Throwable e )
  
          {
              final String error = "Failed to initilize the object.";
              throw new PipelineException( error, e );
          }
  
          //
          // start the object
          //
  
          if( m_object instanceof Startable ) try
          {
              if( m_verbose ) getLogger().debug( "starting " + role );
              ((Startable)m_object).start();
          }
          catch( Throwable e )
          {
              final String error = "Failed to start the service.";
              throw new PipelineException( error, e );
          }
  
          return m_object;
      }
  
     /**
      * Notification byb the controlling application to dispose of the 
      * service factory.
      */
      public void dispose()
      {
          //
          // dispose of all of the service pools
          //
  
          if( m_verbose ) if( getLogger().isDebugEnabled() ) getLogger().debug( 
            "pool disposal (" + m_pools.size() + ")");
          Enumeration pools = m_pools.elements();
          while( pools.hasMoreElements() )
          {
              
              Object pool = pools.nextElement();
              if( pool instanceof Disposable )
              {
                  try
                  {
                      ((Disposable)pool).dispose();
                  }
                  catch( Throwable e )
                  {
                      final String warning = "Ignoring exception while invoking pool disposal.";
                      if( getLogger().isWarnEnabled() ) getLogger().warn( warning, e );
                  }
              }
          }
  
          //
          // dispose of all of the service singletons
          //
  
          if( m_verbose ) if( getLogger().isDebugEnabled() ) getLogger().debug( 
             "singleton disposal (" + m_singletons.size() + ")");
          Enumeration singletons = m_singletons.elements();
          while( singletons.hasMoreElements() )
          {
              Object singleton = singletons.nextElement();
              if( singleton instanceof Disposable )
              {
                  try
                  {
                      ((Disposable)singleton).dispose();
                  }
                  catch( Throwable e )
                  {
                      final String warning = "Ignoring exception while invoking singleton provider disposal.";
                      if( getLogger().isWarnEnabled() ) getLogger().warn( warning, e );
                  }
              }
          }
  
          //
          // dispose of all of the transient service providers
          //
  
          if( m_verbose ) if( getLogger().isDebugEnabled() ) getLogger().debug( 
            "transient disposal (" + m_transients.size() + ")");
          Enumeration transients = m_transients.elements();
          while( transients.hasMoreElements() )
          {
              Object object = transients.nextElement();
              if( object instanceof Disposable )
              {
                  try
                  {
                      ((Disposable)object).dispose();
                  }
                  catch( Throwable e )
                  {
                      final String warning = "Ignoring exception while invoking transient provider disposal.";
                      if( getLogger().isWarnEnabled() ) getLogger().warn( warning, e );
                  }
              }
          }
      }
  
      //==========================================================
      // configuration
      //==========================================================
  
     /**
      * Creates a hashtable of configurations keyed by the block implmentation
      * class name.  The configuration file is ssumed to in the following form.
      * <pre>
      *     &lt;block class="org.apache.demo.MyFirstBlock"&gt;
      *        &lt;any-child value="red"/&gt;
      *     &lt;/block&gt;
      * 
      *     &lt;k class="org.apache.demo.MySecondBlock"/&gt;
      * </pre>
      */
      private Hashtable initalizeBlockConfigurations( Configuration config ) throws ConfigurationException
      {
          Hashtable configs = new Hashtable();
          Configuration[] blocks = config.getChildren("block");
          for( int i=0; i<blocks.length; i++ )
          {
              final String key = blocks[i].getAttribute("class");
              configs.put( key, blocks[i] );
          }
          return configs;
      }
  
      private Configuration getConfigurationForClass( String name )
      {
          Configuration config = (Configuration) m_table.get( name );
          if( config != null ) return config;
          return new DefaultConfiguration( name, null );
      }
  
  }
  
  
  
  
  1.1                  jakarta-avalon-excalibur/src/scratchpad/org/apache/avalon/excalibur/service/ServiceInfo.java
  
  Index: ServiceInfo.java
  ===================================================================
  /*
   * File: ServiceInfo.java
   * License: etc/LICENSE.TXT
   * Copyright: Copyright (C) The Apache Software Foundation. All rights reserved.
   * Copyright: OSM SARL 2002, All Rights Reserved.
   */
  
  package org.apache.avalon.excalibur.service;
  
  import org.apache.avalon.framework.Version;
  import org.apache.avalon.framework.configuration.Configuration;
  
  /**
   * Meta-information about a particular <code>service</code> exposed by a component.
   */
  
  class ServiceInfo
  {
  
      private Class m_interface;
      private Version m_version;
      
     /**
      * Creation of a new <code>ServiceInfo</code> instance.
      */
      public ServiceInfo( Configuration config ) throws Exception
      {
          ClassLoader loader = Thread.currentThread().getContextClassLoader( ); 
          m_interface = loader.loadClass( config.getAttribute("name") );
          m_version = Version.getVersion( config.getAttribute("version") );
      }
  
     /**
      * Equality test.
      * @return TRUE if this instance is equal to the supplied instance, where 
      *   equality is derived from equivalent interface values and versions.
      */
      public boolean equals( Object object )
      {
          if( object instanceof ServiceInfo ) return equals( (ServiceInfo) object );
          return false;
      }
  
     /**
      * Equality test.
      * @return TRUE if this instance is equal to the supplied instance, where 
      *   equality is derived from equivalent interface values and versions.
      */
      public boolean equals( ServiceInfo other )
      {
          if( !other.getInterface().isAssignableFrom( m_interface ) ) return false;
          return m_version.equals( other.getVersion() ); 
      }
  
     /**
      * Returns the class representing the service interface.
      * @return the service interface
      */
      public Class getInterface()
      {
          return m_interface;
      }
  
     /**
      * Returns the service version.
      * @return the service version
      */
      public Version getVersion()
      {
          return m_version;
      }
  
  }
  
  
  
  
  1.1                  jakarta-avalon-excalibur/src/scratchpad/org/apache/avalon/excalibur/service/ServiceLoader.java
  
  Index: ServiceLoader.java
  ===================================================================
  /*
   * File: ServiceLoader.java
   * License: etc/LICENSE.TXT
   * Copyright: Copyright (C) The Apache Software Foundation. All rights reserved.
   * Copyright: OSM SARL 2002, All Rights Reserved.
   */
  
  package org.apache.avalon.excalibur.service;
  
  import java.io.File;
  import java.net.URL;
  import java.net.URLClassLoader;
  import java.net.MalformedURLException;
  import java.util.jar.JarFile;
  import java.util.jar.Attributes;
  import java.util.jar.Attributes.Name;
  import java.util.Vector;
  import java.util.Hashtable;
  import java.util.Enumeration;
  import java.io.InputStream;
  import java.io.OutputStream;
  import java.io.FileInputStream;
  
  import org.apache.log.Hierarchy;
  import org.apache.log.Priority;
  import org.apache.log.output.io.StreamTarget;
  import org.apache.avalon.framework.logger.Logger;
  import org.apache.avalon.framework.CascadingRuntimeException;
  import org.apache.avalon.framework.CascadingException;
  import org.apache.avalon.framework.logger.LogKitLogger;
  import org.apache.avalon.framework.logger.AvalonFormatter;
  import org.apache.avalon.framework.logger.AbstractLogEnabled;
  import org.apache.avalon.framework.logger.LogEnabled;
  import org.apache.avalon.framework.configuration.Configurable;
  import org.apache.avalon.framework.configuration.Configuration;
  import org.apache.avalon.framework.configuration.ConfigurationException;
  import org.apache.avalon.framework.configuration.DefaultConfiguration;
  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.framework.component.Component;
  import org.apache.avalon.framework.component.Composable;
  import org.apache.avalon.framework.component.ComponentManager;
  import org.apache.avalon.framework.component.DefaultComponentManager;
  import org.apache.avalon.framework.component.ComponentException;
  import org.apache.avalon.framework.service.Serviceable;
  import org.apache.avalon.framework.service.ServiceManager;
  import org.apache.avalon.framework.service.ServiceException;
  import org.apache.avalon.framework.activity.Initializable;
  import org.apache.avalon.framework.activity.Startable;
  import org.apache.avalon.framework.activity.Disposable;
  
  /**
   * A service loader that loads a target class, manages full component lifecycle
   * processing for the target and dependent services, and service decommissioning.
   *
   * <p><table border="1" cellpadding="3" cellspacing="0" width="100%">
   * <tr bgcolor="#ccccff">
   * <td colspan="2"><b>Pipeline Lifecycle Phases</b></td>
   * <tr><td width="20%"><b>Phase</b></td><td><b>Description</b></td></tr>
   * <tr>
   * <td width="20%" valign="top">Configurable</td>
   * <td>
   * The configuration phase supplies static information to the pipeline processor
   * that may be used to configure target and supporting services.  During the loading
   * of a component, the pipline processor will attempt to locate a block configuration
   * based on the class name of the block.  If there is no configuration matching the 
   * class name an empty configuration will be supplied to the component or a component
   * the the target component is depedant on (assuming the component in question 
   * implements the Configurable interface).
   *
   * <pre>
   * &lt;config&gt;
   *
   *   &lt;block class="com.magic.DirectoryBlock"&gt;
   *     &lt;-- block specific content --&gt;
   *   &lt;/block&gt;
   *
   *   &lt;block class="com.magic.ActivatorBlock"&gt;
   *     &lt;-- block specific content --&gt;
   *   &lt;/block&gt;
   *
   * &lt;/config&gt;
   * </pre>
   * </td></tr>
   * <tr>
   * <td width="20%" valign="top">Contextualizable</td>
   * <td>
   * The contextualization phase hadles the capture of runtime context information
   * needed by the pipeline processor.  This information must be provided in the 
   * for of a <code>ServiceLoaderContext</code> otherwise the contextualize method will
   * throw an exception.  The following information is provided by the 
   * <code>ServiceLoaderContext</code>:
   * <p><table border="0" cellpadding="3" cellspacing="0" width="100%">
   * <tr>
   * <td width="20%" valign="top"><code>ARGS_KEY</code></td>
   * <td>
   * Contains the command line arguments as a <code>String[]</code>. 
   * </td></tr>
   * <tr>
   * <td width="20%" valign="top"><code>BASE_DIRECTORY_KEY</code></td>
   * <td>
   * Contains the application base directory <code>File</code>. 
   * </td></tr>
   * <tr>
   * <td width="20%" valign="top"><code>TARGET_KEY</code></td>
   * <td>
   * Contains the name of the target class to be instantiated. 
   * </td></tr>
   * <tr>
   * <td width="20%" valign="top"><code>INCLUDES_KEY</code></td>
   * <td>
   * Contains an array of jar files that will be added to the pipeline classloader.
   * Jar files included in the array will be checked for block manifest entries.  If 
   * block entries exist that will be registered as potetentially available services
   * that may be instantiated during the recursive dependecy resolution process. 
   * </td></tr>
   * <tr>
   * <td width="20%" valign="top"><code>CONFIGURATION_FILE_KEY</code></td>
   * <td>
   * A <code>File</code> instance that may or may not exist. If the file exists and is 
   * confiugration, it will be used as the base configuration reference when looking up
   * service configuration details.  The default behaviour is to look for a file named
   * "config.xml" in the user's working directory. 
   * </td></tr>
   * <tr>
   * <td width="20%" valign="top"><code>DISPOSAL_POLICY_KEY</code></td>
   * <td>
   * A <code>Boolean</code> value that is applied on completionof the startup of a 
   * <code>Startable</code> component.  If the value TRUE, the component is stopped 
   * and disposed of (including termination of all dependencies) immediately following
   * startup.  This policy only applies to <code>Startable</code> components.  Setting
   * policy value to FALSE ensures that the component can respond as a server.  Non
   * <code>Startable</code> target component are immediately terminated (providing a 
   * useful for component testing during development cycles).
   * </td></tr>
   * <td width="20%" valign="top"><code>LOGGING_PRIORITY_KEY</code></td>
   * <td>
   * Contains the logging priority to be applied during the pipeline session.
   * </td></tr>
   * <td width="20%" valign="top"><code>VERBOSE_POLICY_KEY</code></td>
   * <td>
   * If this value is TRUE, debug logging entries from the pipeline processor will be 
   * if the overall logging priority permits this. If FALSE (the default), the logging 
   * entires generated by the pipeline processor will be limited to WARN, ERROR, 
   * and FATAL_ERROR.
   * </td></tr>
   * </table>
   *
   * </td></tr>
   * <tr><td width="20%">Initalizable</td>
   * <td>
   * The initilization phase handles the creation of a new instance of the supplied
   * target class, resolves any service dependencies, and runs the instance through 
   * the lifecycle pipeline. 
   * </td></tr>
   * <tr><td width="20%" valign="top">Disposable</td>
   * <td>
   * Cleanup and disposal of state members following termination and diposal of 
   * all current components.
   * </td></tr>
   * </table>
   */
  public class ServiceLoader extends AbstractLogEnabled 
      implements Configurable, Contextualizable, Initializable, Disposable
  {
      private static final String DEFAULT_FORMAT = "[%7.7{priority}] (%{category}): %{message}\\n%{throwable}";
      private static OutputStream m_out = System.out;
  
      private String[] m_args;
      private PipelineClassLoader m_classloader;
  
      private Priority m_priority = Priority.INFO;
      private String m_target;
      private Object m_object;
      private File[] m_includes;
      private boolean m_policy = true;
      private boolean m_verbose = false;
  
      private boolean m_terminated = false;
      private boolean m_disposed = false;
  
      private ServiceFactory m_factory;
      private Configuration m_config;
      
     /**
      * Command line entry point supporting establishment and initalization of a service 
      * loader instance with a supplied target component and supporting services.
      *
      *   <p><strong>java -jar form</strong></p>
      *   <p>Execution using java -jar pattern requires the presence 
      *   of the following files under the same directory:</p>
      *       <ul>
      *         <li><code>merlin.jar</code>
      *         <li><code>avalon-framework.jar</code>
      *         <li><code>logkit.jar</code>
      *       </ul>
      *   <p>An example command line is shown below:</p>
      *   <pre>
      * $ java -jar <strong>merlin.jar</strong> &lt;supporting-jar-files&gt; 
      *     -target &lt;class-name&gt; 
      *   </pre>
      *   <p><strong>java -classpath form</strong></p>
      *   <p>Execution using java -classpath pattern requires the inclusions 
      *   of the pipeline, framework and logkit jar files in the classpath 
      *   statement.</p>
      *   <p>An example command line is shown below:</p>
      *   <pre>
      * $ java -classpath <strong>merlin.jar;avalon-framework.jar;logkit.jar</strong> 
      *     org.apache.avalon.excalibur.service.ServiceLoader
      *      &lt;supporting-jar-files&gt; -target &lt;class-name&gt; 
      *   </pre>
      * </ul>
      * 
      * <p><table border="1" cellpadding="3" cellspacing="0" width="100%">
      * <tr bgcolor="#ccccff">
      * <td colspan="2"><b>Command Line Parameters and Arguments</b></td>
      * <tr><td width="20%"><b>Parameter</b></td><td><b>Description</b></td></tr>
      * <tr>
      * <td width="20%" valign="top"><code>-target &lt;class-name&gt;</code></td>
      * <td>
      * <p>The class to instantiate.  If the class exposes any Avalon lifecycle interface
      * (such as <code>Configurable</code>, <code>Contextualizable</code>, <code>Serviceable</code>,  
      * <code>Initializable</code>, <code>Startable</code>, or <code>Disposable</code>, the 
      * pipeline will automate lifecycle processing and termination.
      * </p>
      * </td></tr>
      * <tr>
      * <td width="20%" valign="top"><code>&lt;supporting-jar-files&gt;</code></td>
      * <td>
      * <p>A list of space seperated jar files that will be added to the pipeline
      * as supporting classes and components.  Any jar file included in the list
      * that contains an Avalon <code>Block</code> manifest will be registered as
      * an available service when resolving component dependecies.</p>
      * </td></tr>
      * <tr><td width="20%"><code>-verbose &lt;boolean&gt;</code></td>
      * <td>
      * <p>A value of <code>true</code> will force debug level logging of the actual pipeline
      * processor.  A value of <code>false</code> will disable pipeline debug priority logging.
      * Visibility of logging inffomration is dependent on the level supplied under the 
      * <code>priority</code parameter.</p>
      * </td></tr>
      * <tr><td width="20%" valign="top"><code>-priority &lt;priority&gt;</code></td>
      * <td>
      * <p>Declaration of the logging priority to use during pipeline execution.  Valid values
      * include FATAL_ERROR, ERROR, WARN, INFO, and DEBUG. </p>
      * </td></tr>
      * <tr><td width="20%" valign="top"><code>-dispose &lt;boolean&gt;</code></td>
      * <td>
      * If the target component is <code>Startable</code>, and the dispose argument is <code>FALSE</code> the
      * component will be treated as a server and will continue to run following initialization.
      * Otherwise, the component will be disposed of.
      * </td></tr>
      * <tr><td width="20%" valign="top"><code>-configuration &lt;file-path&gt;</code></td>
      * <td>
      * Optional parameter naming a file to be used as the configuration source.
      * </td></tr>
      * </table>
      *
      * @param args a array of <code>String</code> argument values passed under the command line. 
      */
      public static void main( String[] args )
      {
          ServiceLoader pipeline = null;
          try
          {
              CLI cli = new CLI( args );
              pipeline = new ServiceLoader();
              ServiceLoaderContext context = cli.getContext();
              File path = cli.getConfigurationPath();
              Configuration config = new DefaultConfiguration("-", null );
              if( path != null ) config = getRuntimeConfiguration( path );
              pipeline.configure( config );
              pipeline.contextualize( context );
              pipeline.initialize();
          }
          catch( IllegalParameterException ipe )
          {
              System.err.println( ipe.getMessage() );
          }
          catch( PipelineException e )
          {
              final String error = "Service loader processing exception.";
              System.err.println( error );
              System.err.println( e );
          }
          catch( PipelineRuntimeException e )
          {
              final String error = "Service loader runtime exception.";
              System.err.println( error );
              System.err.println( e );
          }
          catch( Throwable e )
          {
              final String error = "Unexpected service loader exception.";
              System.err.println( error );
              e.printStackTrace();
          }
          finally
          {
              if( pipeline != null )
              {
                  pipeline.dispose();
              }
          }
      }
  
      private boolean getVerbose()
      {
          return m_verbose;
      }
  
     /**
      * Configuration of the pipeline.
      */
      public void configure( Configuration config ) throws ConfigurationException
      {
          m_config = config;
      }
  
     /**
      * Contextualization of the pipeline including the supply of command-line
      * arguments, include files, target class, and related execution policies.
      * @see ServiceLoaderContext
      * @param context the pipeline context
      * @exception ContextException if the supplied context is not an instance
      *   of ServiceLoaderContext, or if an internal error occurs while resolving 
      *   context information.
      */
      public void contextualize( Context context ) throws ContextException
      {
          try
          { 
              ServiceLoaderContext c = (ServiceLoaderContext) context;
              m_includes = c.getIncludes();
              m_verbose = c.getVerbose();
              m_priority = c.getLoggingPriority();
              m_policy = c.getDisposalPolicy();
              m_target = c.getTarget();
          }
          catch( Throwable e )
          {
              final String error = "Unexpected error while reslving pipeline context.";
              throw new ContextException( error, e );
          }
      }
  
     /**
      * Start the pipeline and handle any errors arrising from loader execution.
      */
      public void initialize() throws PipelineException
      {
          if( m_target == null ) throw new PipelineException(
            "The pipeline task required attribute 'target' has not been not supplied.");
  
          try
          {
              Hierarchy hierarchy = createBootstrapLogger();
              Logger logger = new LogKitLogger( hierarchy.getLoggerFor( "loader" ) );
              if( getLogger() == null ) super.enableLogging( logger );
              if( m_classloader == null ) m_classloader = createClassloader();
              m_factory = new ServiceFactory( hierarchy, m_config,
                new File( System.getProperty("user.dir") ), getVerbose() );
              m_factory.enableLogging( getLogger().getChildLogger("factory") );
          }
          catch( Throwable e )
          {
              final String error = "Service loader validation error.";
              getLogger().error( error, e );
              return;
          }
  
          try
          {
              process();
          }
          catch( PipelineException e )
          {
              final String error = "Service loader processing exception.";
              getLogger().error( error );
          }
          catch( PipelineRuntimeException e )
          {
              final String error = "Service loader runtime exception.";
              getLogger().error( error );
          }
          catch( Throwable e )
          {
              final String error = "Unexpected pipeline exception.";
              getLogger().error( error, e );
          }
          finally
          {
              if( m_policy )
              {
                  if( m_object != null ) terminate();
                  dispose();
                  return;
              }
          }
      }
  
      /**
       * Initates execution of the loading of supporting services derived from a 
       * target.
       */
      private void process( ) throws PipelineException
      {
          //
          // add the included jar files to the classloader
          //
  
          Vector list = new Vector();
          Vector stack = new Vector();
          for (int i=0; i<m_includes.length; i++) 
          {
              File target = m_includes[i];
              stack.add( target );
              list.add( target );
          }
          load( stack );
  
          // build the registry of available services
  
          try
          {
              m_factory.register( list );
          }
          catch( Throwable e )
          {
              final String error = "Service loader exception encounter while preparing services.";
              throw new PipelineException( error, e ); 
          }
  
          //
          // create an instance of the target and if verify that we can in fact build a 
          // service manager if needed
          //
  
          Class target;
          UnitInfo info;
          try
          {
              target = m_classloader.loadClass( m_target );
          }
          catch( Throwable e )
          {
              final String error = "Could not load target class: " + m_target;
              throw new PipelineException( error , e ); 
          }
  
          try
          {
              info = ServiceRegistry.createUnitInfo( target );
              if( getVerbose() ) if( getLogger().isDebugEnabled() ) getLogger().debug( "validating target\n" + info );
              try
              {
                  m_factory.validate( info );
              }
              catch( Throwable e )
              {
                  final String error = "Could not resolve a valid dependency solution for ";
                  throw new CascadingException( error + info.getClassName(), e );
              }
          }
          catch( Throwable e )
          {
              final String error = "Service loader exception encounter while preparing services.";
              throw new PipelineException( error, e ); 
          }
  
          //
          // process the target
          //
  
          try
          {
              m_object = m_factory.pipeline( info, "target" );
          }
          catch( Throwable e )
          {
              final String error = "Service loader exception encounter during target execution.";
              throw new PipelineException( error, e ); 
          }
  
          //
          // add a shutdown hook so we can stop services and target and invoke disposal
          //
  
          Runtime.getRuntime().addShutdownHook( 
            new Thread()
            {
                public void run()
                {
                    terminate();
                    dispose();
                }
            }
          );
      }
  
     /**
      * Run the termination lifecycle actions on the primary object.
      */
      private void terminate( )
      {
          if( m_terminated ) return;
          m_terminated = true;
          if( m_object == null ) return;
          if( getVerbose() ) if( getLogger().isDebugEnabled() ) getLogger().debug( 
             "terminating " + m_object.getClass().getName() );
  
          if( m_object instanceof Startable )
          {
              try
              {
                  ((Startable)m_object).stop();
              }
              catch( Throwable e )
              {
                  final String warning = "Ignoring error while stopping target.";
                  if( getLogger().isWarnEnabled() ) getLogger().warn( warning, e );
              }
          }
  
          if( m_object instanceof Disposable )
          {
              try
              {
                  ((Disposable)m_object).dispose();
              }
              catch( Throwable e )
              {
                  final String warning = "Ignoring error while disposing of target.";
                  if( getLogger().isWarnEnabled() ) getLogger().warn( warning, e );
              }
          }
      }
  
     /**
      * Disposal of the pipeline and release of all resources.
      */
      public void dispose()
      {
          if( m_disposed ) return;
  
          if( !m_terminated ) try
          {
              terminate();
          }
          catch( Throwable e )
          {
              // ignore and continue
          }
  
          m_disposed = true;
  
          if( getVerbose() ) if( getLogger().isDebugEnabled() ) getLogger().debug( "loader disposal" );
          if( m_factory instanceof Disposable )
          {
              try
              {
                  ((Disposable)m_factory).dispose();
              }
              catch( Throwable e )
              {
                  final String warning = "Ignoring error while disposing of service factory.";
                  getLogger().warn( warning, e );
              }
          }
      }
  
      //==========================================================
      // classloader
      //==========================================================
      
      private PipelineClassLoader createClassloader()
      {
          try
          {
              PipelineClassLoader loader = new PipelineClassLoader();
              Thread.currentThread().setContextClassLoader( loader );
              return loader;
          }
          catch( Throwable e )
          {
               final String error = "Failed to instantial a classloader.";
               throw new CascadingRuntimeException( error, e );
          }
      }
  
      class PipelineClassLoader extends URLClassLoader
      {
          PipelineClassLoader( )
          {
              super( new URL[0], Thread.currentThread().getContextClassLoader() );
          }
  
          protected void addURL( URL url ) 
          {
              try
              {
                  URL jarURL = new URL("jar:" + url.toString() + "!/");
                  super.addURL( jarURL );
              }
              catch( Throwable e )
              {
                  throw new CascadingRuntimeException(
                    "Unexpected error while attempting to add classloader URL: " + url, e );
              }
          }
          protected Class loadClass( String name, boolean resolve ) throws ClassNotFoundException
          {
              return super.loadClass( name, resolve );
          } 
      }
  
     /**
      * Load the supplied jar files under the pipeline classloader.
      * For each entry in the stack, try to load it and 
      * if sucessfull, remove it from the stack - on completion
      * the stack should be less than its original size - recursivly
      * invoke load until the stack is empty.
      * @param stack a <code>Vecor</code> containing a sequence of jar files
      *   to be added to the classloader.
      */
      private void load( Vector stack )
      {
          int size = stack.size();
          Hashtable errors = new Hashtable();
          Enumeration enum = stack.elements();
          while( enum.hasMoreElements() )
          {
              File target = (File) enum.nextElement();
              try
              {
                  m_classloader.addURL( target.toURL() );
                  if( getVerbose() ) getLogger().debug( "Loaded file: " + target );
                  stack.remove( target );
              }
              catch( Throwable error )
              {
                  errors.put( target, error );
              }
          }
  
          if( stack.size() == 0 ) return;
          if( stack.size() < size )
          {
              load( stack );
          }
          else
          {
              Enumeration keys = errors.keys();
              getLogger().error("Load error count = " + errors.size() );
              while( keys.hasMoreElements() )
              {
                  File key = (File) keys.nextElement();
                  getLogger().error( 
                     "Error while loading file."
                     + "\n\tfile: " + key.toString(), (Throwable) errors.get( key ) );
              }
              throw new RuntimeException("Unable to load file stack - see trace for details.");
          }
      }
  
      //==========================================================
      // configuration
      //==========================================================
  
     /**
      * Get client configuration from a file. 
      */ 
      private static Configuration getRuntimeConfiguration( final File file ) 
      {
          try
          {
              DefaultConfigurationBuilder builder = new DefaultConfigurationBuilder( ); 
              InputStream is = new FileInputStream( file );
              if( is == null ) throw new Exception( 
                "Could not load the configuration resource \"" + file + "\"" ); 
              return builder.build( is ); 
          }
          catch( Throwable e )
          {
              final String error = "Unable to create configuration.";
              throw new CascadingRuntimeException( error, e );
          }
      }
  
      //==========================================================
      // logging
      //==========================================================
  
      private Hierarchy createBootstrapLogger()
      {
          try
          {
              Hierarchy hierarchy = Hierarchy.getDefaultHierarchy();
              hierarchy.setDefaultLogTarget( 
                 new StreamTarget( m_out, new AvalonFormatter( DEFAULT_FORMAT ) ) );
              hierarchy.setDefaultPriority( m_priority );
              return hierarchy;
          }
          catch( Throwable e )
          {
              final String error = "Unexpected exception while creating bootstrap logger.";
              throw new CascadingRuntimeException( error, e );
          }
      }
      //==========================================================
      // command-line
      //==========================================================
  
      private static class IllegalParameterException extends Exception 
      {
         /**
          * Construct a new <code>IllegalParameterException</code> instance with the 
          * supplied message parameter.
          * @param message Message summarising the exception.
          */
          public IllegalParameterException( final String message ) 
          {
             super( message );
          }
      }
  
      private static class CLI
      {
          private String[] m_args = new String[0];
          private Priority m_priority = Priority.INFO;
          private String m_target = "";
          private boolean m_policy = true;
          private boolean m_verbose = false;
          private File[] m_files = new File[0];
          private File m_path = null;
  
          public CLI( String[] args ) throws IllegalParameterException
          {
              m_args = args;
              Vector vector = new Vector();
              for( int i=0; i < m_args.length; i++ )
              {
                  if( m_args[i].toLowerCase().startsWith("-tar") )
                  {
                      if( i+1 < m_args.length ) 
                      {
                          m_target = m_args[i+1];
                          i = i+1;
                      }
                      else
                      {
                          final String error = "Missing -target parameter.";
                          throw new RuntimeException( error );
                      }
                  }
                  else if( m_args[i].toLowerCase().startsWith("-conf") )
                  {
                      if( i+1 < m_args.length ) 
                      {
                          m_path = new File( m_args[i+1] );
                          i = i+1;
                      }
                      else
                      {
                          final String error = "Missing -configuration parameter.";
                          throw new RuntimeException( error );
                      }
                  }
                  else if( m_args[i].toLowerCase().startsWith("-pri") )
                  {
                      if( i+1 < m_args.length ) 
                      {
                          m_priority = Priority.getPriorityForName( m_args[i+1].toUpperCase() );
                          i = i+1;
                      }
                      else
                      {
                          final String error = "Missing -priority argument.";
                          throw new RuntimeException( error );
                      }
                  }
                  else if( m_args[i].toLowerCase().startsWith("-dis") )
                  {
                      if( i+1 < m_args.length ) 
                      {
                          m_policy = (m_args[i+1].toUpperCase().equals("TRUE"));
                          i = i+1;
                      }
                      else
                      {
                          final String error = "Missing -disposal argument.";
                          throw new RuntimeException( error );
                      }
                  }
                  else if( m_args[i].toLowerCase().startsWith("-ver") )
                  {
                      if( i+1 < m_args.length ) 
                      {
                          m_verbose = (m_args[i+1].toUpperCase().equals("TRUE"));
                          i = i+1;
                      }
                      else
                      {
                          final String error = "Missing -verbose argument.";
                          throw new RuntimeException( error );
                      }
                  }
                  else if( m_args[i].startsWith("-") )
                  {
                      final String error = "Unrecognized parameter: " + m_args[i];
                      throw new IllegalParameterException( error );
                  }
                  else
                  {    
                      final File file = new File( m_args[i] );
                      if( file.exists() ) vector.add( file );
                  }
              }
              m_files = (File[]) vector.toArray( new File[0] );
          }
  
          public ServiceLoaderContext getContext()
          {
               return new ServiceLoaderContext( m_args, m_target, m_files, m_policy, m_priority, m_verbose );
          }
  
          public File getConfigurationPath()
          {
               return m_path;
          }
      }
  }
  
  
  
  
  1.1                  jakarta-avalon-excalibur/src/scratchpad/org/apache/avalon/excalibur/service/ServiceLoaderContext.java
  
  Index: ServiceLoaderContext.java
  ===================================================================
  /*
   * File: ServiceLoaderContext.java
   * License: etc/LICENSE.TXT
   * Copyright: Copyright (C) The Apache Software Foundation. All rights reserved.
   * Copyright: OSM SARL 2002, All Rights Reserved.
   */
  
  package org.apache.avalon.excalibur.service;
  
  import java.io.File;
  import org.apache.avalon.framework.context.DefaultContext;
  import org.apache.avalon.framework.context.ContextException;
  import org.apache.log.Priority;
  
  /**
   * <code>ServiceLoaderContext</code> context to hold command line arguments, 
   * base directory, target class name, and include files for a 
   * <code>ServiceLoader</code> component.
   *
   * @author <a href="mailto:mcconnell@osm.net">Stephen McConnell</a>
   */
  public class ServiceLoaderContext extends DefaultContext
  {
     /**
      * Context key for command line arguments.
      * @see #getArgs()
      */
      public static final String ARGS_KEY = "ARGS";
  
     /**
      * Context key for the base directory.
      * @see #getBaseDirectory()
      */
      public static final String BASE_DIRECTORY_KEY = "APP_DIR";
  
     /**
      * Context key for the target class name.
      * @see #getTarget()
      */
      public static final String TARGET_KEY = "TARGET";
  
     /**
      * Context key for the set of supporting include jar files.
      * @see #getIncludes()
      */
      public static final String INCLUDES_KEY = "INCLUDES";
  
     /**
      * Context key for the disposal policy.
      * @see #getDisposalPolicy()
      */
      public static final String DISPOSAL_POLICY_KEY = "DISPOSAL.POLICY";
  
     /**
      * Context key for the logging priority.
      * @see #getLoggingPriority()
      */
      public static final String LOGGING_PRIORITY_KEY = "LOGGING.PRIORITY";
  
     /**
      * Context key for the verbose policy.
      * @see #getVerbose()
      */
      public static final String VERBOSE_POLICY_KEY = "VERBOSE.POLICY";
  
     /**
      * Creation of a new <oce>ServiceLoaderContext</code> with the supplied 
      * arguments.
      * @param args command line arguments
      * @param target class name of the target object to be loaded
      * @param includes set of jar files to be added to the loader classloader
      * @param disposal boolean disposal policy
      * @param priority logging priority
      * @param verbose policy concerning display of loader debug messages
      */
      public ServiceLoaderContext( final String[] args, final String target, final File[] includes, final boolean disposal, final Priority priority, final boolean verbose )
      {
          super.put( ARGS_KEY, args );
          super.put( TARGET_KEY, target );
          super.put( BASE_DIRECTORY_KEY, new File( System.getProperty("user.dir")) );
          super.put( INCLUDES_KEY, includes );
          super.put( DISPOSAL_POLICY_KEY, new Boolean( disposal ));
          super.put( VERBOSE_POLICY_KEY, new Boolean( verbose ));
          super.put( LOGGING_PRIORITY_KEY, priority );
      }
  
     /**
      * Returns the command-line argument <code>String[]</code>.
      * @return String[] command line arguments
      */
      public String[] getArgs()
      {
          try
          {
              return (String[]) super.get( ARGS_KEY );
          }
          catch( ContextException e )
          {
              final String error = "Unexpected exception while retrieving command line arguments.";
              throw new PipelineRuntimeException( error, e );
          }
      }
  
     /**
      * Returns the base directory as a <code>File</code>.
      * @return File the base working directory
      */
      public File getBaseDirectory()
      {
          try
          {
              return (File) super.get( BASE_DIRECTORY_KEY );
          }
          catch( ContextException e )
          {
              final String error = "Unexpected exception while retrieving base directory.";
              throw new PipelineRuntimeException( error, e );
          }
      }
  
     /**
      * Returns the disposal policy to apply if the target component implements
      * the <code>Startable</code> interface.
      * @return boolean the target component disposal policy
      */
      public boolean getDisposalPolicy()
      {
          try
          {
              return ((Boolean)super.get( DISPOSAL_POLICY_KEY )).booleanValue();
          }
          catch( ContextException e )
          {
              final String error = "Unexpected exception while retrieving disposal policy.";
              throw new PipelineRuntimeException( error, e );
          }
      }
  
     /**
      * Class name of a target object.
      * @return String the class name of the target
      */
      public String getTarget()
      {
          try
          {
              return (String) super.get( TARGET_KEY );
          }
          catch( ContextException e )
          {
              final String error = "Unexpected exception while retrieving include files.";
              throw new PipelineRuntimeException( error, e );
          }
      }
  
     /**
      * Returns the set of supporting jar files.
      * @return File[] an array of jar files supporting target composition and execution
      */
      public File[] getIncludes()
      {
          try
          {
              return (File[]) super.get( INCLUDES_KEY );
          }
          catch( ContextException e )
          {
              final String error = "Unexpected exception while retrieving include files.";
              throw new PipelineRuntimeException( error, e );
          }
      }
  
     /**
      * Returns the logging priority.
      * @return Priority the logging priority to apply.
      */
      public Priority getLoggingPriority()
      {
          try
          {
              return (Priority) super.get( LOGGING_PRIORITY_KEY );
          }
          catch( ContextException e )
          {
              final String error = "Unexpected exception while retrieving logging priority.";
              throw new PipelineRuntimeException( error, e );
          }
      }
  
     /**
      * Returns the verbose policy - if true, logging entries from the pipeline 
      * will be inclued, otherwise, logging entries will be restricted to the 
      * target component.
      * @return boolean the verbose policy
      */
      public boolean getVerbose()
      {
          try
          {
              return ((Boolean)super.get( VERBOSE_POLICY_KEY )).booleanValue();
          }
          catch( ContextException e )
          {
              final String error = "Unexpected exception while retrieving verbose policy.";
              throw new PipelineRuntimeException( error, e );
          }
      }
  }
  
  
  
  1.1                  jakarta-avalon-excalibur/src/scratchpad/org/apache/avalon/excalibur/service/ServiceProvider.java
  
  Index: ServiceProvider.java
  ===================================================================
  /*
   * File: ServiceProvider.java
   * License: etc/LICENSE.TXT
   * Copyright: Copyright (C) The Apache Software Foundation. All rights reserved.
   * Copyright: OSM SARL 2002, All Rights Reserved.
   */
  
  package org.apache.avalon.excalibur.service;
  
  import org.apache.avalon.framework.activity.Disposable;
  
  /**
   * <code>ServiceProvider</code> is an abstract base class to services
   * factories supporting TRANSIENT, POOLED, and SINGLETON services. The 
   * abstract class provides the single <code>getRole</code> method that
   * can be used by a <code>ServiceManager</code> implementation to identity
   * a service provider for a particular role.
   * A concrete <code>ServiceProvider</code> instance will typically be 
   * created by an implementation when constructing a <code>ServiceManager</code> 
   * for a target component.
   */
  abstract class ServiceProvider implements Disposable
  {
      private String m_role;
  
     /**
      * Creation of a new <code>ServiceProvider</code> instance based on 
      * a supplied role.
      * @param role the role of the service provided by the provider relative
      *   to a <code>ServiceManager</code> that is exposing provider services.
      */
      public ServiceProvider( String role )
      {
          m_role = role;
      }
  
     /**
      * Returns the role of this provider within the scope of a <code>ServiceManager</code>.
      * @return String the role of the service provider by the provider.
      */
      public String getRole()
      {
          return m_role;
      }
  
     /**
      * Disposal of the provider and release of related resources.
      */
      public void dispose()
      {
          m_role = null;
      }
  }
  
  
  
  
  1.1                  jakarta-avalon-excalibur/src/scratchpad/org/apache/avalon/excalibur/service/ServiceRegistry.java
  
  Index: ServiceRegistry.java
  ===================================================================
  /*
   * File: ServiceRegistry.java
   * License: etc/LICENSE.TXT
   * Copyright: Copyright (C) The Apache Software Foundation. All rights reserved.
   * Copyright: OSM SARL 2002, All Rights Reserved.
   */
  
  package org.apache.avalon.excalibur.service;
  
  import java.io.File;
  import java.io.InputStream;
  import java.io.IOException;
  import java.util.Vector;
  import java.util.Iterator;
  import java.util.Map;
  import java.util.Hashtable;
  import java.util.Enumeration;
  import java.util.jar.JarFile;
  import java.util.jar.Attributes;
  import java.util.jar.Attributes.Name;
  
  import org.apache.avalon.framework.logger.Logger;
  import org.apache.avalon.framework.logger.AbstractLogEnabled;
  import org.apache.avalon.framework.CascadingRuntimeException;
  import org.apache.avalon.framework.CascadingException;
  import org.apache.avalon.framework.configuration.Configuration;
  import org.apache.avalon.framework.configuration.ConfigurationException;
  import org.apache.avalon.framework.configuration.DefaultConfiguration;
  import org.apache.avalon.framework.configuration.DefaultConfigurationBuilder;
  
  /**
   * Internal class supporting registration of available services.
   */
  class ServiceRegistry extends AbstractLogEnabled
  {
  
      private Vector m_repository = new Vector();
      private UnitInfo[] m_block_info_set;
      private Hashtable m_table;
      private boolean m_verbose = false;
  
      public ServiceRegistry( boolean verbose )
      {
          m_verbose = verbose;
      }
  
      public void register( UnitInfo info )
      {
          m_repository.add( info );
      }
  
     /**
      * Populates the set of available services based on a supplied 
      * vector of jar files.
      * @param list a list of jar files
      */
      public void register( Vector list ) throws PipelineException
      {
          Vector registry = new Vector();
          Enumeration enum = list.elements();
          while( enum.hasMoreElements() )
          {
              File target = (File) enum.nextElement();
              UnitInfo[] blocks = register( target );
              if( m_verbose ) if( blocks.length > 0 ) if( getLogger().isDebugEnabled() ) 
                getLogger().debug(
                "file: " + target + " has " + blocks.length + " block declarations" );
          }
      }
  
     /**
      * Register a jar file with the registry.
      * @param file the jar file to register
      * 
      */
      public UnitInfo[] register( File target ) throws PipelineException
      {
          UnitInfo[] blocks = getUnitInfo( target );
          for( int i=0; i<blocks.length; i++ )
          {
              UnitInfo info = blocks[i];
              m_repository.add( info );
          }
          return blocks;
      }
  
      public UnitInfo lookup( ServiceInfo info )
      {
          Enumeration enum = m_repository.elements();
          while( enum.hasMoreElements() )
          {
              UnitInfo block_info = (UnitInfo) enum.nextElement();
              if( block_info.provides( info ) ) return block_info;
          }
          return null;
      }
  
     /**
      * Returns an array of block infos provided by the jar file.
      * @return a <code>UnitInfo[]<code> provided by the jar file
      */
      private UnitInfo[] getUnitInfo( File file ) throws PipelineException
      {
          Vector vector = new Vector();
          try
          {
              //
              // if the file contains block declarations, then pipeline and
              // blocks as a supporting service that will be provided to the 
              // target server
              //
   
              String[] blocks = getBlocks( file );
              for( int i=0; i<blocks.length; i++ )
              {
                  //
                  // get the block implementation class and check for
                  // dependecies - if dependencies > 0 then ignore it
                  // otherwise pipeline the block and add it as a 
                  // service
                  //
  
                  final String path = blocks[i];
                  Configuration config = loadConfiguration( path + ".conf", true );
                  Configuration xinfo = loadConfiguration( path + ".xinfo", false );
                  if( xinfo == null ) throw new IllegalStateException(
                        "Could not locate <class>.xinfo resource for: " + path );
  
                  final String classname = path.replace('/','.');
                  Class block = Thread.currentThread().getContextClassLoader().loadClass( classname );
                  vector.add( new UnitInfo( block, xinfo, config ));
              }
          }
          catch( Throwable e )
          {
              throw new CascadingRuntimeException(
                "Unexpected error while attempting to load file: " + file, e );
          }
          return (UnitInfo[]) vector.toArray( new UnitInfo[0] );
      }
  
     /**
      * Returns a single block info relative to a supplied class.
      * @return a <code>UnitInfo<code> for the class.
      */
      public static UnitInfo createUnitInfo( Class block ) throws PipelineException
      {
          try
          {
              String path = block.getName().replace('.','/');
              Configuration config = loadConfiguration( path + ".config", true );
              Configuration xinfo = loadConfiguration( path + ".xinfo", false );
              if( xinfo == null ) xinfo = new DefaultConfiguration("", null);
              return new UnitInfo( block, xinfo, config );
          }
          catch( Throwable e )
          {
              throw new CascadingRuntimeException(
                "Unexpected error while attempting to resolve block info for a class: " + block.getName(), e );
          }
      }
  
      //===============================================================================
      // utilities
      //===============================================================================
  
     /**
      * Returns an array of <code>String</code>s corresponding to the set of classnames
      * where each classname is a declared block within the supplied jar file.
      * @param file a jar file
      */
      private String[] getBlocks( File file )
      throws CascadingException, IllegalArgumentException
      {
          final Vector vector = new Vector();
          try
          {
              JarFile jar = new JarFile( file );
              Map map = jar.getManifest().getEntries();
              Iterator iterator = map.keySet().iterator();
              while( iterator.hasNext() )
              {
                  String name = (String) iterator.next();
                  Attributes attributes = (Attributes) map.get( name );
                  Iterator it = attributes.keySet().iterator();
                  while( it.hasNext() )
                  {
                      Object entry = it.next();
                      if( entry.toString().equals("Avalon-Block") ) 
                      {
                          if( attributes.get( entry ).equals("true") )
                          {
                              vector.add( name.substring(0,name.indexOf(".class")));
                          }
                      }
                  }
              }
          }
          catch( IOException e )
          {
              final String error = "IO exception while attempt to read block manifest.";
              throw new CascadingException( error, e );
          }
          catch( Throwable e )
          {
              final String error = "Unexpected exception while inspecting manifest on file: ";
              throw new CascadingException( error + file, e );
          }
          finally
          {
              return (String[]) vector.toArray( new String[0] );
          }
      }
  
     /**
      * Returns a configuration resource form a jar file. 
      * @param path the package path to the resource e.g. net/osm/config.xml
      * @param create if TRUE and no configuration found, return an empty 
      *    configuration, else, return null
      * @exception ConfigurationException if there is a problem
      */
      private static Configuration loadConfiguration( String path, boolean create ) 
      throws ConfigurationException 
      {
          try
          {
              DefaultConfigurationBuilder builder = new DefaultConfigurationBuilder( );
              InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream( path );
              if( is != null ) return builder.build( is );
              if( create ) return new DefaultConfiguration("-",null);
              return null;
          }
          catch( Throwable e )
          {
              final String error = "Unexpected exception while attempting to load a configuration from path: ";
              throw new ConfigurationException( error, e ); 
          } 
      }
  }
  
  
  
  
  1.1                  jakarta-avalon-excalibur/src/scratchpad/org/apache/avalon/excalibur/service/SingletonProvider.java
  
  Index: SingletonProvider.java
  ===================================================================
  /*
   * File: SingletonProvider.java
   * License: etc/LICENSE.TXT
   * Copyright: Copyright (C) The Apache Software Foundation. All rights reserved.
   * Copyright: OSM SARL 2002, All Rights Reserved.
   */
  
  package org.apache.avalon.excalibur.service;
  
  import org.apache.avalon.framework.activity.Disposable;
  
  /**
   * A <code>SingletonProvider</code> is a provider of singleton services.  A 
   * singleton service is a service that is managed by the container providing the
   * the service. The container providing the service is reposible for all lifecycle
   * actions including service decommissioning.
   */
  class SingletonProvider extends ServiceProvider
  {
  
      private Object m_object;
  
     /**
      * Creation of a new <code>SingletonProvider</code>.
      * @param object the singleton object to provide.
      */
      public SingletonProvider( Object object, String role )
      {
          super( role );
          m_object = object;
      }
  
     /**
      * Provides a reference to a singleton service.
      * @return Object the singleton service
      */
      public Object provide()
      {
          return m_object;
      }
  
     /**
      * Disposal of the provider and release of related resources.
      */
      public void dispose()
      {
          if(( m_object != null ) && ( m_object instanceof Disposable )) try
          { 
              ((Disposable)m_object).dispose();
          }
          catch( Throwable anything )
          {
              // ignore it
          }
          finally
          {
              super.dispose();
          }
      }
  }
  
  
  
  
  1.1                  jakarta-avalon-excalibur/src/scratchpad/org/apache/avalon/excalibur/service/TransientProvider.java
  
  Index: TransientProvider.java
  ===================================================================
  /*
   * File: TransientProvider.java
   * License: etc/LICENSE.TXT
   * Copyright: Copyright (C) The Apache Software Foundation. All rights reserved.
   * Copyright: OSM SARL 2002, All Rights Reserved.
   */
  
  package org.apache.avalon.excalibur.service;
  
  import org.apache.avalon.framework.CascadingRuntimeException;
  
  /**
   * A <code>TransientProvider</code> is a provider of transient services.  A 
   * transient service is a service where total responsibility for the lifetime
   * of the service rests with client aquiring the service.
   */
  class TransientProvider extends ServiceProvider
  {
      private ServiceFactory m_factory;
      private UnitInfo m_info;
      private boolean m_disposed;
  
      public TransientProvider( ServiceFactory factory, UnitInfo info, String role )
      {
          super( role );
          m_info = info;
          m_factory = factory;
      }
  
     /**
      * Create a new instance of a transient service.  
      * @return Object a new instance of a transient service
      */
      public Object create()
      {
          if( m_disposed ) throw new IllegalStateException( "Transient provider has been disposed.");
          try
          {
              return m_factory.pipeline( m_info, super.getRole() );
          }
          catch( Throwable e )
          {
              final String error = "Unexpected error while creating transient service.";
              throw new CascadingRuntimeException( error, e );
          }
      }
  
     /**
      * Disposal of the provider and release of related resources.
      */
      public void dispose()
      {
          m_disposed = true;
          m_factory = null;
          m_info = null;
          super.dispose();
      }
  
  }
  
  
  
  
  1.1                  jakarta-avalon-excalibur/src/scratchpad/org/apache/avalon/excalibur/service/UnitInfo.java
  
  Index: UnitInfo.java
  ===================================================================
  /*
   * File: UnitInfo.java
   * License: etc/LICENSE.TXT
   * Copyright: Copyright (C) The Apache Software Foundation. All rights reserved.
   * Copyright: OSM SARL 2002, All Rights Reserved.
   */
  
  package org.apache.avalon.excalibur.service;
  
  import java.util.Vector;
  import org.apache.avalon.framework.CascadingException;
  import org.apache.avalon.framework.configuration.Configuration;
  
  /**
   * Meta information about a <code>Serviceable</code> component.  
   */
  class UnitInfo
  {
  
      public static final int SINGLETON_LIFETIME_POLICY = 0;
      public static final int POOLED_LIFETIME_POLICY = 1;
      public static final int TRANSIENT_LIFETIME_POLICY = 2;
  
      private Class m_block;
      private Configuration m_xinfo;
      private Configuration m_config;
      private ServiceInfo[] m_services;
      private DependencyInfo[] m_dependencies;
      private boolean m_installed = false;
      private Object m_object;
      private int m_policy = SINGLETON_LIFETIME_POLICY;
  
     /**
      * Creation of a new UnitInfo based a xinfo configuration
      * derived from the supplied class name.
      * The UnitInfo recognises the the following structures within
      * the xinfo configuration:
      * <pre>
      *   &lt;blockinfo&gt;
      *   
      *     &lt;block>
      *       &lt;version>1.0&lt;/version&gt;
      *     &lt;/block&gt;
      *   
      *     &lt;!--
      *     services that are offered by this block 
      *     --&gt;
      *   
      *     &lt;services&gt;
      *         &lt;service name="hello.Hello" version="1.0"/&gt;
      *     &lt;/services&gt;
      *   
      *     &lt;!--
      *     Implementation policy may one of the following enumerations:
      *     (a) SINGLETON, service is available for the lifetime of the manager
      *     (b) POOLED, the implementation implements Pool
      *     (c) TRANSIENT, manager is a factory of transient service instances
      *     --&gt;
      *   
      *     &lt;implementation policy="SINGLETON" /&gt;
      *   
      *   &lt;/blockinfo&gt;
      * </pre>
      * 
      * @param block the implementation class
      * @param the xinfo meta-information in the form of a Configuration
      * @param the default component configuration
      */
      public UnitInfo( Class block, Configuration xinfo, Configuration config ) throws Exception
      {
          m_block = block;
          m_xinfo = xinfo;
          m_config = config;
          try
          {
              Configuration[] services = xinfo.getChild("services").getChildren("service");
              Vector vector = new Vector();
              for( int i=0; i<services.length; i++ )
              {
                  vector.add( new ServiceInfo( services[i] ));
              }
              m_services = (ServiceInfo[]) vector.toArray( new ServiceInfo[ vector.size() ] );
          }
          catch( Throwable e )
          {
              throw new CascadingException( "Could not construct service information.", e );
          }
          try
          {
              Configuration[] dependencies = xinfo.getChild("dependencies").getChildren("dependency");
              Vector vector = new Vector();
              for( int i=0; i<dependencies.length; i++ )
              {
                  vector.add( new DependencyInfo( dependencies[i] ));
              }
              m_dependencies = (DependencyInfo[]) vector.toArray( new DependencyInfo[ vector.size() ] );
          }
          catch( Throwable e )
          {
              throw new CascadingException( "Could not construct dependency information.", e );
          }
  
          String policy = xinfo.getChild("implementation").getAttribute("policy","TRANSIENT");
          if( policy.equalsIgnoreCase( "SINGLETON" ) )
          {
              m_policy = SINGLETON_LIFETIME_POLICY;
          }
          else if( policy.equalsIgnoreCase( "POOLED" ) )
          {
              m_policy = POOLED_LIFETIME_POLICY;
          }
          else
          {
              m_policy = TRANSIENT_LIFETIME_POLICY;
          }
      }
  
     /**
      * Returns the name of the class implemenmting the service.
      * @return the class name
      */
      public String getClassName()
      {
          return m_block.getName();
      }
  
     /**
      * Returns the set of services provided by the component.
      * @return an array of <code>ServiceInfo</code> instance
      */
      public ServiceInfo[] getServices()
      {
          return m_services;
      }
  
     /**
      * Returns a <code>ServiceInfo</code> from the <code>UnitInfo</code> matching 
      * the supplied service descriptor.
      * @param info a <code>ServiceInfo</code> to locate with the <code>UnitInfo</code> instance
      * @return a <code>ServiceInfo</code> instance matching the supplied service descriptor
      */
      public ServiceInfo getService( ServiceInfo info )
      {
          ServiceInfo[] services = getServices();
          for( int i=0; i<services.length; i++ )
          {
              if( services[i].equals( info )) return services[i];
          }
          return null;
      }
  
     /**
      * Returns a <code>TRUE</code> if the supplied <code>ServiceInfo</code> can be 
      * provided by the implementation. 
      * @param service the requested service
      * @return boolean TRUE if the service is available otherwise FALSE
      */
      public boolean provides( ServiceInfo service )
      {
          return ( getService( service ) != null );
      }
  
     /**
      * Returns a array of <code>DependencyInfo</code> descriptors that detail
      * the dependencies that this component has on other components.
      * @return component dependencies
      */
      public DependencyInfo[] getDependencies()
      {
          return m_dependencies;
      }
  
     /**
      * Returns the implemetation policy.  The value returned shall be one of
      * SINGLETON_LIFETIME_POLICY, POOLED_LIFETIME_POLICY, or TRANSIENT_LIFETIME_POLICY.
      * @return implementation policy
      */
      public int getPolicy()
      {
          return m_policy;
      }
  
     /**
      * The component implementation class.
      * @return the component implementation class
      */
      public Class getBaseClass()
      {
          return m_block;
      }
  
     /**
      * Return the default configuration.
      * @return the default configuration
      */
      public Configuration getDefaultConfiguration()
      {
          return m_config;
      }
  
     /**
      * Returns a string representation of the descriptor.
      * @return stringified representation
      */
      public String toString()
      {
          final StringBuffer buffer = new StringBuffer();
          buffer.append( "  block: " + getClassName() );
          ServiceInfo[] services = getServices();
          for( int i=0; i<services.length; i++ )
          {
              buffer.append( "\n  service: " + services[i].getInterface().getName() 
                + ", version: " + services[i].getVersion() );
          }
          DependencyInfo[] dependencies = getDependencies();
          for( int i=0; i<dependencies.length; i++ )
          {
              buffer.append( "\n  dependecy: " 
                + "role: " + dependencies[i].getRole() 
                + ", service: " + dependencies[i].getInterface().getName() 
                + ", version: " + dependencies[i].getVersion() );
          }
          return buffer.toString();
      }
  }
  
  
  
  
  1.1                  jakarta-avalon-excalibur/src/scratchpad/org/apache/avalon/excalibur/service/package.html
  
  Index: package.html
  ===================================================================
  <body>
  <p>Resource supporting the management of components using dynamic service composition.</p>
  <table border="1" cellpadding="3" cellspacing="0" width="100%">
  <tr bgcolor="#ccccff">
  <td colspan="2"><b>Features Summary</b></td>
  <tr><td width="20%"><b>Feature</b></td>
  <td><b>Description</b></td></tr>
  
  <tr><td width="20%" valign="top">Service Composition</td>
  <td>Handles automated composition of services based on declared component dependencies.</td></tr>
  <tr><td>Default Configurations</td>
  <td>Provides support for configuration using component default configurations together
  with supplied configuration information using the CascadingConfiguration model.</td></tr>
  <tr><td>Mixed execution modes</td>
  <td>Supports execution from the command line (main method), as a jar file, as an Ant task,
  and as an embedded component.</td></tr>
  </table>
  
  <h3>Component Creation</h3>
  
  The pipeline class manages the creation and deployment of a target component and dynamic
  resolution of dependencies based on meta-information contained in a jar manifest file.  Entries
  in the manifest file reference class names that are used to load the component implementation
  and configuration the component based on meta-information contained in .xinfo and .conf files 
  of the same name as the implementation class.
  
  <h4>The Manifest File</h4>
  
  <p>Reusable components are published through a manifest declaration show below.  When 
  a jar file is supplied to the Pipeline the manifest is checked for any block declarations.
  Blocks declared within the manifest are registered by the pipeline as potentially available 
  services that can be used in service dependency resolution.  Each Avalon-block declaration
  in the manifest refers to a component implementation class and its associated .xinfo file.</p>
  
  <pre>
    Manifest-Version: 1.0
  
    Name: org/apache/DirectoryBlock.class
    Avalon-Block: true
  
    Name: org/apache/ReferralBlock.class
    Avalon-Block: true
  </pre>
  
  <h4>The &lt;classname&gt;.xinfo File</h4>
  
  <p>For each component declared in a manifest, the implementation establishes the available services
  and dependencies based on information contained in an <code>.xinfo</code> file.  Given a component
  implementation class <strong><code>org/apache/DirectoryBlock.class</code></strong> the <code>Pipeline</code> processor
  will attempt to locate a <strong><code>org/apache/DirectoryBlock.xinfo</code></strong> resource in the jar file.</P>
  
  <pre>
    &lt;?xml version="1.0"?&gt;
  
    &lt;blockinfo&gt;
  
        <font color="blue"><i>&lt;!--
        Block version.
        --&gt;</i></font>
  
        &lt;block&gt;
          &lt;version&gt;1.0&lt;/version&gt;
        &lt;/block&gt;
  
        <font color="blue"><i>&lt;!--
        Services that are offered by the component are declared under the 
        services element.  A services element may contain multiple service
        declarations.
        --&gt;</i></font>
  
        &lt;services&gt;
  
            <font color="blue"><i>&lt;!--
            A service declaration includes a class name (typically an interface)
            and a service version identifier.  Service versions may have up to 
            three fiels (e.g. 1.1.3).
            --&gt;</i></font>
  
            &lt;service name="org.apache.ReferralService" version="1.0" /&gt;
  
        &lt;/services&gt;
  
        <font color="blue"><i>&lt;!--
        A component declares the dependencies it has with other components under 
        the dependencies element.  A dependencies element may contain multiple
        dependency statements.
        --&gt;</i></font>
  
        &lt;dependencies&gt;
  
            <font color="blue"><i>&lt;!--
            A dependency element contains the declaration of a role and a service
            that the component is dependent on. The pipeline processor will attempt
            to resolve dependencies based on registered services and dynamically 
            establish and provide the dependencies via the component Serviceable 
            implementation.  The role name corresponds to the identifying string
            that the component implementation will use to lookup a service from
            a service manger during the serviceable lifecycle phase.
            --&gt;</i></font>
  
            &lt;dependency&gt;
                &lt;role&gt;directory&lt;/role&gt;
                &lt;service name="org.apache.DirectoryService" version="1.0"/&gt;
            &lt;/dependency&gt;
  
        &lt;/dependencies&gt;
  
        <font color="blue"><i>&lt;!--
        Component implementation policy may one of the following:
        (a) SINGLETON, service is available for the lifetime of the manager
        (b) POOLED, the implementation implements Pool (implementation pending)
        (c) TRANSIENT, manager is a factory of transient service instances
        --&gt;</i></font>
      
        &lt;implementation policy="SINGLETON" /&gt;
  
    &lt;/blockinfo&gt;
  </pre>
  
  <h4>The &lt;classname&gt;.conf File</h4>
  
  <p>The pipeline processor provides support for the automated retrieval of default
  configurations for a component.  During lifecycle processing, the pipeline processor
  will attempt to locate a configuration resource with the same path and name as 
  the component implementation class.  For example, for the component <strong><code>org/apache/DirectoryBlock.class</code></strong>, the implementation will look for 
  a default configuration under the resource path <strong><code>org/apache/DirectoryBlock.conf</code></strong>.
  During the configuration stage, the pipeline processor will supply the component with 
  a <code>CascadingConfiguration</code> where the primary configuration is configuration 
  derived from the pipeline processor configuration, and a default configuration corresponding 
  to the .conf configuration. 
  </p>
  <pre>
  
  </body>
  
  

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