mcconnell    02/05/10 10:53:10

  Added:       merlin/src/java/org/apache/excalibur/merlin
                        AbstractManager.java DefaultComponentManager.java
                        DefaultServiceManager.java DependencyInfo.java
                        PipelineException.java
                        PipelineRuntimeException.java PipelineService.java
                        ServiceContext.java ServiceFactory.java
                        ServiceInfo.java ServiceLoader.java
                        ServiceLoader.xinfo ServiceLoaderContext.java
                        ServiceProvider.java ServiceRegistry.java
                        SingletonProvider.java TransientProvider.java
                        UnitInfo.java package.html
               merlin/src/java/org/apache/excalibur/merlin/ant Load.java
                        package.html
  Log:
  merlin repackaging
  
  Revision  Changes    Path
  1.1                  
jakarta-avalon-excalibur/merlin/src/java/org/apache/excalibur/merlin/AbstractManager.java
  
  Index: AbstractManager.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software License
   * version 1.1, a copy of which has been included with this distribution in
   * the LICENSE.TXT file.
   *
   * Original contribution by OSM SARL, http://www.osm.net
   */
  
  package org.apache.excalibur.merlin;
  
  import java.util.Map;
  import org.apache.avalon.framework.service.ServiceException;
  
  
  /**
   * Internal helper class the handles the functional requirements of 
   * both ComponetManager and ServiceManager.
   * @author <a href="mailto:[EMAIL PROTECTED]">Stephen McConnell</a>
   */
  class AbstractManager 
  {
  
     /**
      * 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>
      * Not supported - pending finalization of fortess package.
      * 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 implementation 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 Map m_providers;
  
     /**
      * Internal table that maintains a mapping betyween pooled objects and
      * the issuing pool.  The object is used as the key to lookup the pool
      * when handling object release.
      */
      //private Hashtable m_pooledTable = new Hashtable();
  
      public AbstractManager( Map providers )
      {
          m_providers = providers;
      }
  
      public boolean has( String role )
      {
          return (m_providers.get( role ) != null );
      }
  
      public Object resolve( 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 after registering the usage
              //
  
              //Object object = null;
              //try
              //{
              //    object = ((PooledProvider)provider).acquire( );
              //}
              //catch( Throwable e )
              //{
              //    final String error = "Pool implementation error.";
              //    throw new ServiceException( error, e );
              //}
              //finally
              //{
                  // it is invalid for a pool to provide the same object without
                  // it being released beforehand
  
              //    if( m_pooledTable.get( object ) != null ) 
              //    {
              //        final String error = 
              //          "Manager has an existing reference to an aquired 
object from '" 
              //          + role + "'.";
              //        throw new ServiceException( error );
              //    }
              //    m_pooledTable.put( object, provider );
              //    return object;
              //}
          //}
          else
          {
              //
              // return a singleton service
              //
  
              return ((SingletonProvider)provider).provide( );
          }
      }
  
     /**
      * Release a pooled object.
      * @param object a pooled object
      */
      public void disgard( Object object )
      {
          //
          // release a pooled service
          //
  
          //PooledProvider provider = (PooledProvider) m_pooledTable.get( 
object );
          //if( provider != null ) provider.release( object );
      }
  }
  
  
  
  
  1.1                  
jakarta-avalon-excalibur/merlin/src/java/org/apache/excalibur/merlin/DefaultComponentManager.java
  
  Index: DefaultComponentManager.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software License
   * version 1.1, a copy of which has been included with this distribution in
   * the LICENSE.TXT file.
   *
   * Original contribution by OSM SARL, http://www.osm.net
   */
  
  package org.apache.excalibur.merlin;
  
  import java.util.Map;
  import org.apache.avalon.framework.component.Component;
  import org.apache.avalon.framework.component.ComponentManager;
  import org.apache.avalon.framework.component.ComponentException;
  
  
  /**
   * Internal helper class the implements the <code>ComponentManager</code> 
interface and 
   * is supplied to dynamically created componets during lifecycle pipeline 
processing.
   * @author Stephen McConnell <[EMAIL PROTECTED]>
   */
  class DefaultComponentManager extends AbstractManager implements 
ComponentManager
  {
  
      public DefaultComponentManager( Map providers )
      {
          super( providers );
      }
  
      public boolean hasComponent( String role )
      {
          return super.has( role );
      }
  
      public Component lookup( String role ) throws ComponentException
      {
          Object object = null;
          try
          {
              object = super.resolve( role );
          }
          catch( Throwable e )
          {
              final String error = "Provider related error during service 
resolution.";
              throw new ComponentException( error, e );
          }
          finally
          {
              if( object instanceof Component ) 
              {
                  return (Component) object;
              }
              throw new ComponentException( "Service provider returned a 
non-Component." );
          }
      }
  
     /**
      * Release a pooled object.
      * @param object a pooled object
      */
      public void release( Component component )
      {
          super.disgard( component );
      }
  }
  
  
  
  
  1.1                  
jakarta-avalon-excalibur/merlin/src/java/org/apache/excalibur/merlin/DefaultServiceManager.java
  
  Index: DefaultServiceManager.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software License
   * version 1.1, a copy of which has been included with this distribution in
   * the LICENSE.TXT file.
   *
   * Original contribution by OSM SARL, http://www.osm.net
   */
  
  package org.apache.excalibur.merlin;
  
  import java.util.Map;
  import org.apache.avalon.framework.service.ServiceManager;
  import org.apache.avalon.framework.service.ServiceException;
  
  
  /**
   * Internal helper class the implements the <code>ServiceManager</code> 
interface and 
   * is supplied to dynamically created componets during lifecyle pipeline 
processing.
   * @author Stephen McConnell <[EMAIL PROTECTED]>
   */
  class DefaultServiceManager extends AbstractManager implements ServiceManager
  {
      /**
       * Construct ServiceManager.
       */
      public DefaultServiceManager( Map providers )
      {
          super( providers );
      }
  
     /**
      * Returns true if a provider exists for the supplied role.
      * @param role the service identifier
      * @return boolean TRUE if the service is available else FALSE
      */
      public boolean hasService( String role )
      {
          return super.has( role );
      }
  
      /**
       * Retrieve Object by role from ServiceManager.
       * @param role the role
       * @return the Object
       * @exception ServiceException if an error occurs
       */
      public Object lookup( String role ) throws ServiceException
      {
          return super.resolve( role );
      }
  
     /**
      * Release a pooled object.
      * @param object a pooled object
      */
      public void release( Object object )
      {
          super.disgard( object );
      }
  }
  
  
  
  
  1.1                  
jakarta-avalon-excalibur/merlin/src/java/org/apache/excalibur/merlin/DependencyInfo.java
  
  Index: DependencyInfo.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software License
   * version 1.1, a copy of which has been included with this distribution in
   * the LICENSE.TXT file.
   *
   * Original contribution by OSM SARL, http://www.osm.net
   */
  
  package org.apache.excalibur.merlin;
  
  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.
   * @author Stephen McConnell <[EMAIL PROTECTED]>
   */
  
  class DependencyInfo
  {
      private String m_role;
      private ServiceInfo m_service;
      private Configuration m_config;
  
     /**
      * 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
      {
          m_role = config.getChild("role").getValue();
          m_service = new ServiceInfo( config.getChild("service") );
          m_config = config.getChild("configuration");
      }
  
     /**
      * 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;
      }
  
      public ServiceInfo getService()
      {
          return m_service;
      }
  
      public Configuration getConfiguration()
      {
          return m_config;
      }
  
  }
  
  
  
  1.1                  
jakarta-avalon-excalibur/merlin/src/java/org/apache/excalibur/merlin/PipelineException.java
  
  Index: PipelineException.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software License
   * version 1.1, a copy of which has been included with this distribution in
   * the LICENSE.TXT file.
   *
   * Original contribution by OSM SARL, http://www.osm.net
   */
  
  package org.apache.excalibur.merlin;
  
  import java.io.StringWriter;
  import java.util.StringTokenizer;
  import java.io.PrintWriter;
  import java.lang.reflect.Method;
  
  import org.apache.avalon.framework.CascadingException;
  import org.apache.avalon.framework.CascadingThrowable;
  
  /**
   * Thrown by an Pipeline as a result of an unexpected error 
   * during execution.
   * @author Stephen McConnell <[EMAIL PROTECTED]>
   * @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 );
      }
  
     /**
      * Returns a stringified representation of the exception.
      * @return String the stringified representation of the exception
      */
      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() );
          Throwable subCause = resolveCause( cause );
          if( subCause != null )
          {
              appendCause( buffer, subCause );
          }
          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" );
      }
  
      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;
      }
  
      private static Throwable resolveCause( Throwable target )
      {
          if( target instanceof CascadingThrowable ) 
          {
              return ((CascadingThrowable)target).getCause();
          }
          
          try
          {
              Method method = target.getClass().getMethod( "getCause", new 
Class[0] );
              if( method != null ) 
              {
                  return (Throwable) method.invoke( target, new Object[0] );
              }
              return null;
          }
          catch( Throwable e )
          {
              return null;
          }
      }
  }
  
  
  
  
  1.1                  
jakarta-avalon-excalibur/merlin/src/java/org/apache/excalibur/merlin/PipelineRuntimeException.java
  
  Index: PipelineRuntimeException.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software License
   * version 1.1, a copy of which has been included with this distribution in
   * the LICENSE.TXT file.
   *
   * Original contribution by OSM SARL, http://www.osm.net
   */
  
  package org.apache.excalibur.merlin;
  
  import java.io.StringWriter;
  import java.util.StringTokenizer;
  import java.io.PrintWriter;
  import java.lang.reflect.Method;
        
  import org.apache.avalon.framework.CascadingRuntimeException;
  import org.apache.avalon.framework.CascadingThrowable;
  
  /**
   * Thrown by an Pipeline as a result of an unexpected runtime error 
   * during execution.
   * @author Stephen McConnell <[EMAIL PROTECTED]>
   * @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 );
      }
  
     /**
      * Returns a stringified representation of the exception.
      * @return String the stringified representation of the exception
      */
      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() );
          Throwable subCause = resolveCause( cause );
          if( subCause != null )
          {
              appendCause( buffer, subCause );
          }
          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" );
      }
  
      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;
      }
  
      private static Throwable resolveCause( Throwable target )
      {
          if( target instanceof CascadingThrowable ) 
          {
              return ((CascadingThrowable)target).getCause();
          }
          try
          {
              Method method = target.getClass().getMethod( "getCause", new 
Class[0] );
              if( method != null ) 
              {
                  return (Throwable) method.invoke( target, new Object[0] );
              }
              return null;
          }
          catch( Throwable e )
          {
              return null;
          }
      }
  }
  
  
  
  
  1.1                  
jakarta-avalon-excalibur/merlin/src/java/org/apache/excalibur/merlin/PipelineService.java
  
  Index: PipelineService.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software License
   * version 1.1, a copy of which has been included with this distribution in
   * the LICENSE.TXT file.
   *
   * Original contribution by OSM SARL, http://www.osm.net
   */
  
  package org.apache.excalibur.merlin;
  
  import org.apache.avalon.framework.component.Component;
  import org.apache.avalon.framework.configuration.Configurable;
  import org.apache.avalon.framework.context.Contextualizable;
  import org.apache.avalon.framework.activity.Initializable;
  import org.apache.avalon.framework.activity.Disposable;
  
  /**
   * Interface supporting service loading and execution.
   * @author Stephen McConnell <[EMAIL PROTECTED]>
   */
  public interface PipelineService 
    extends Component, Configurable, Contextualizable, Initializable, Disposable
  {
  
     /**
      * Service lookup key.
      */
      public static final String PIPELINE_SERVICE_KEY = "PIPELINE_SERVICE_KEY";
  
     /**
      * Applies sercies logging, contextulization, configuration, initalization 
      * and disposal, including dependent service composition and pipline 
exeecution.
      * @param target the name of the implementation class of the the component 
to 
      *   load into the pipeline
      * @return Object the initalized service
      * @exception Exception if no corresponding [class-name].xinfo file can be 
found, 
      *    or if a service pipeline general execution is encountered
      */
      public Object pipeline( String target ) throws Exception;
  
  
  }
  
  
  
  
  
  
  1.1                  
jakarta-avalon-excalibur/merlin/src/java/org/apache/excalibur/merlin/ServiceContext.java
  
  Index: ServiceContext.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software License
   * version 1.1, a copy of which has been included with this distribution in
   * the LICENSE.TXT file.
   *
   * Original contribution by OSM SARL, http://www.osm.net
   */
  
  package org.apache.excalibur.merlin;
  
  import java.io.File;
  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 Stephen McConnell <[EMAIL PROTECTED]>
   */
  
  public class ServiceContext extends DefaultContext 
  {
  
     /**
      * Argument lookup key.
      */
      public static final String ARGS_KEY = "ARGS";
  
     /**
      * Base directory lookup key.
      */
      public static final String BASE_DIRECTORY_KEY = "app.home";
  
      private String[] m_args;
      private File m_root;
      private String m_name;
      private Logger m_logger;
  
     /**
      * Creation of a new ServiceContext.
      * @param args command line arguments
      * @param base the base directory
      * @param name the name ??
      */
      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 );
      }
  
     /**
      * Returns the command line argument array
      * @return String[] the command line arguments
      */
      public String[] getArgs()
      {
          return m_args;
      }
  
     /**
      * Returns the base directory.
      * @return File the base directory
      */
      public File getBaseDirectory()
      {
          return m_root;
      }
  }
  
  
  
  1.1                  
jakarta-avalon-excalibur/merlin/src/java/org/apache/excalibur/merlin/ServiceFactory.java
  
  Index: ServiceFactory.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software License
   * version 1.1, a copy of which has been included with this distribution in
   * the LICENSE.TXT file.
   *
   * Original contribution by OSM SARL, http://www.osm.net
   */
  
  package org.apache.excalibur.merlin;
  
  import java.io.File;
  import java.util.Map;
  import java.util.Hashtable;
  import java.util.Enumeration;
  import java.util.Vector;
  
  import org.apache.avalon.framework.logger.Logger;
  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.context.Contextualizable;
  import org.apache.avalon.framework.component.Composable;
  import org.apache.avalon.framework.component.ComponentManager;
  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.excalibur.configuration.ConfigurationUtil;
  import org.apache.excalibur.configuration.CascadingConfiguration;
  
  /**
   * The <code>ServiceFactory</code> class provides support for the 
   * instantiation of objects based on supplied service meta-info.
   * @author Stephen McConnell <[EMAIL PROTECTED]>
   */
  class ServiceFactory extends AbstractLogEnabled 
    implements Configurable, Initializable, Disposable
  {
      private File m_root;
      private boolean m_verbose;
      private Configuration m_config;
      private Logger m_baseLogger;
  
      private ServiceRegistry m_registry;
      private Hashtable m_table = new Hashtable();
      private Hashtable m_singletons = new Hashtable();
      private Hashtable m_transients = new Hashtable();
      //private Hashtable m_pools = new Hashtable();
  
      private Hashtable m_services = new Hashtable();
      private Hashtable m_lookup = new Hashtable();
  
     /**
      * Creation of a new service factory.
      * @param root the base directory
      * @param verbose if TRUE then logging of internal service activity is 
enabled
      */
      public ServiceFactory( File root, boolean verbose ) throws Exception
      {
          m_root = root;
          m_verbose = verbose;
      }
  
     /**
      * Configuration of the factory.
      * @param config the configuration object
      * @exception ConfigurationException if an configuration related error 
occurs
      */
      public void configure( Configuration config ) throws 
ConfigurationException
      {
          m_config = config;
      }
  
      //=======================================================================
      // Initializable
      //=======================================================================
  
     /**
      * Initialize the factory.
      * @exception Exception if an initialization related error occurs
      */
      public void initialize() throws Exception
      {
          m_baseLogger = getLogger();
          super.enableLogging( 
            m_baseLogger.getChildLogger( "loader" ).getChildLogger( "factory" ) 
);
  
          m_registry = new ServiceRegistry( m_root, m_verbose );
          m_registry.enableLogging( getLogger().getChildLogger("registry") );
          m_registry.configure( m_config );
          m_registry.initialize();
      }
  
      //=======================================================================
      // ServiceFactory
      //=======================================================================
  
     /**
      * Populates the set of available services based on a supplied 
      * vector of jar files.  The implementation delegates registration
      * actions to the factories registry.
      * @param list a list of jar files
      */
      public void register( Vector list ) throws PipelineException
      {
          m_registry.register( list );
      }
  
     /**
      * Validates that the set of dependecies declared for a given 
      * implementation can be resolved and that all dependencies 
      * can be validated.
      * @param info the <code>UnitInfo</code> to validate
      */
      public void validate( UnitInfo info ) throws Exception
      {
          DependencyInfo[] dependencies = info.getDependencies();
          for( int i=0; i<dependencies.length; i++ )
          {
              DependencyInfo d = dependencies[i];
              if( m_registry.lookup( d ) == null ) 
              {
                   throw new Exception(
                     "Could not resolve dependent service '" + d.getRole() 
                      + "' with service: '" + 
d.getService().getInterface().getName() 
                      + "' for block '" + info.getName() + "'"  );
              }
          }
      }
  
     /**
      * Dynamic creation of a <code>ServiceManager</code> based on a set of 
      * supplied dependencies and container configuration.
      * @param info meta information about the service
      * @param base the base logger
      * @return ServiceManager a new service manager
      */
      private ServiceManager createServiceManager( UnitInfo info, Logger base ) 
        throws ServiceException
      {
          return new DefaultServiceManager( getProviders( info, base ) );
      }
  
     /**
      * Dynamic creation of a <code>ComponentManager</code> based on a set of 
      * supplied dependencies and container configuration.
      * @param info meta information about the component
      * @param base the base logger
      * @return ComponentManager a new component manager
      */
      private ComponentManager createComponentManager( UnitInfo info, Logger 
base ) 
        throws ServiceException
      {
          return new DefaultComponentManager( getProviders( info, base ) );
      }
  
     /**
      * Returns a table of providers based on the supplied meta-info and 
      * container configuration.
      * @param info meta-info about the service
      * @param composition the container composition configuration
      * @return Map provider table
      */
      private Map getProviders( UnitInfo unit, Logger base ) 
        throws ServiceException
      {
          DependencyInfo[] dependencies = unit.getDependencies();
          Hashtable providers = new Hashtable();
  
          try
          {
              for( int i=0; i<dependencies.length; i++ )
              {
                  DependencyInfo info = dependencies[i];
                  providers.put( info.getRole(), getProvider( unit, info, base 
) );
              }
              return providers;
          }
          catch( Throwable e )
          {
              final String error = 
                "Unexpected exception while attempting to create a 
ServiceManager.";
              throw new ServiceException( error, e );
          }
      }
  
     /**
      * Create a provider implementation.
      * @param info the dependecy declaration
      * @param profile the configuration profile
      * @return Object the service provider
      */
      private Object getProvider( UnitInfo unit, DependencyInfo info, Logger 
base )
        throws Exception
      {
  
          UnitInfo blockInfo = m_registry.lookup( info );
          if( blockInfo == null ) 
          {
              throw new IllegalStateException(
                "Registry returned a null block info.");
          }
  
          //
          // Establish the type of object.
          //
  
          Object provider = null;
          Class providerClass = blockInfo.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 = blockInfo.getPolicy();
  
          switch( policy )
          {
              case UnitInfo.SINGLETON_LIFETIME_POLICY :
  
                //
                // return a singleton instance
                //
  
                provider = m_singletons.get( providerClass );
                if( provider == null )
                {
                    if( m_verbose && getLogger().isDebugEnabled() ) 
                    {
                        getLogger().debug( 
                          "generating singleton provider" );
                    }
  
                    // create and pipeline the singleton instance and 
                    // add it to the list of singletons
  
                    Object object = execute( unit, blockInfo, info.getRole(), 
base );
                    provider = new SingletonProvider( object, info.getRole() );
                    m_singletons.put( providerClass, provider );
                }
                return provider;
  
              //case UnitInfo.POOLED_LIFETIME_POLICY :
  
                //provider = m_pools.get( providerClass );
                //if( provider == null )
                //{
                //    if( m_verbose ) if( getLogger().isDebugEnabled() ) 
getLogger().debug( 
                //      "generating pooled provider" );
                    // create and pipeline the singleton instance and 
                    // add it to the list of singletons
                //    Object object = execute( unit, blockInfo, info.getRole(), 
base );
                //    provider = new PooledProvider( (Pool) object, 
info.getRole() );
                //    m_pools.put( providerClass, provider );
                //}
                //return provider;
  
              case UnitInfo.TRANSIENT_LIFETIME_POLICY :
  
                //
                // UnitInfo.TRANSIENT_LIFETIME_POLICY :
                // new service instances are always created on invocation of
                // a service lookup
                //
  
                provider = m_transients.get( providerClass );
                if( provider == null )
                {
                    if( m_verbose && getLogger().isDebugEnabled() ) 
                    {
                        getLogger().debug( 
                          "generating transient provider" );
                    }
  
                    // create and pipeline the singleton instance and 
                    // add it to the list of singletons
  
                    provider = new TransientProvider( this, blockInfo, 
info.getRole() );
                    m_transients.put( providerClass, provider );
                }
                return provider;
  
              default :
                throw new PipelineException("Unsupported lifecycle policy: " + 
policy );
           }
      }
  
     /**
      * Applies lifecycle pipeline processing to an object described by a 
supplied
      * service meta description.
      * @param info service meta-information
      * @return Object the service
      */
      public Object pipeline( UnitInfo info ) throws Exception
      {
          return pipeline( info, info.getName() );
      }
  
     /**
      * Applies lifecycle pipeline processing to an object described by a 
supplied
      * service meta description and role.
      * @param info service meta-information
      * @param role service role
      * @return Object the service
      */
      public Object pipeline( UnitInfo info, String role ) throws Exception
      {
          return execute( null, info, role, m_baseLogger ); 
      }
  
      private Object execute( UnitInfo container, UnitInfo info, 
        String role, Logger logger ) 
        throws Exception
      {
  
          if( m_verbose && getLogger().isDebugEnabled() ) 
          {
              getLogger().debug(
                "pipelining " + role + " (" + info.getClassName() + ")");
          }
  
          Configuration config = null;
          if( container != null )
          {
              config = new CascadingConfiguration( 
                container.getConfiguration().getChild(role), 
info.getConfiguration());
          }
          else
          {
              config = info.getConfiguration();
          }
  
          //
          // create and pipeline the new instance
          //
  
          Object object;
          try
          {
              object = info.getBaseClass().newInstance();
          }
          catch( Throwable e )
          {
              final String error = "Failed to instantiate an object: ";
              throw new PipelineException( error + 
info.getBaseClass().getName(), e );
          }
  
          //
          // assign a logging channel
          //
  
          Logger base = logger.getChildLogger( role );
          if( object instanceof LogEnabled ) 
          {
              try
              {
                  if( m_verbose )
                  {
                      getLogger().debug( "applying logger" );
                  }
                  ((LogEnabled)object).enableLogging( base );
              }
              catch( Throwable e )
              {
                  final String error = "Failed to assign a logger channel.";
                  getLogger().error( error, e );
                  handleDisposal( object );
                  throw new PipelineException( error, e );
              }
          }
  
          //
          // configure the object
          //
  
          if( object instanceof Configurable ) 
          {
              try
              {
                  if( m_verbose ) 
                  {
                      getLogger().debug(
                        "applying configuration to " + info.getName() + "\n"
                        + ConfigurationUtil.list( config ));
                  }
                  ((Configurable)object).configure( config );
              }
              catch( Throwable e )
              {
                  final String error = "Failed to configure an object.";
                  getLogger().error( error, e );
                  handleDisposal( object );
                  throw new PipelineException( error, e );
              }
          }
          else if( object instanceof Parameterizable ) 
          {
              try
              {
                  if( m_verbose ) 
                  {
                      getLogger().debug( "parameterization" );
                  }
                  ((Parameterizable)object).parameterize( 
                      Parameters.fromConfiguration( config ) );
              }
              catch( Throwable e )
              {
                  final String error = "Failed to parameterize an object.";
                  getLogger().error( error, e );
                  handleDisposal( object );
                  throw new PipelineException( error, e );
              }
          }
  
          //
          // contextualize the server
          // [need to update this to handle an args sequence]
          //
  
          if( object instanceof Contextualizable ) 
          {
              try
              {
                  if( m_verbose ) 
                  {
                      getLogger().debug( "contextualization" );
                  }
                 ((Contextualizable)object).contextualize( info.getContext() );
              }
              catch( Throwable e )
              {
                  final String error = "Failed to contextualize the object.";
                  getLogger().error( error, e );
                  handleDisposal( object );
                  throw new PipelineException( error, e );
              }
          }
  
          //
          // get the blocks required to support the dependencies
          //
  
          if( object instanceof Serviceable ) 
          {
              try
              {
                  if( m_verbose ) 
                  {
                      getLogger().debug( "composition" );
                  }
                  ServiceManager manager = createServiceManager( info, base );
                  ((Serviceable)object).service( manager );
              }
              catch( Throwable e )
              {
                  final String error = "Failed to service the object.";
                  getLogger().error( error, e );
                  handleDisposal( object );
                  throw new PipelineException( error, e );
              }
          }
          else if( object instanceof Composable )
          {
              try
              {
                  if( m_verbose ) 
                  {
                      getLogger().debug( "composition" );
                  }
                  ComponentManager manager = createComponentManager( info, base 
);
                  ((Composable)object).compose( manager );
              }
              catch( Throwable e )
              {
                  final String error = "Failed to compose the object.";
                  getLogger().error( error, e );
                  handleDisposal( object );
                  throw new PipelineException( error, e );
              }
          }
  
          //
          // initialize the object
          //
  
          if( object instanceof Initializable ) 
          {
              if( m_verbose ) 
              {
                  getLogger().debug( "initilization" );
              }
              try
              {
                  ((Initializable)object).initialize();
              }
              catch( Throwable e )
              {
                  final String error = "Failed to initilize the object.";
                  getLogger().error( error, e );
                  handleDisposal( object );
                  throw new PipelineException( error, e );
              }
          }
  
          //
          // start the object
          //
  
          if( object instanceof Startable ) 
          {
              try
              {
                  if( m_verbose ) 
                  {
                      getLogger().debug( "starting" );
                  }
                  ((Startable)object).start();
              }
              catch( Throwable e )
              {
                  final String error = "Failed to start the service.";
                  getLogger().error( error, e );
                  handleDisposal( object );
                  throw new PipelineException( error, e );
              }
          }
  
          return object;
      }
  
      private void handleDisposal( Object object )
      {
          if( object instanceof Disposable )
          {
              try
              {
                  ((Disposable)object).dispose();
              }
              catch( Throwable e )
              {
                  if( getLogger().isDebugEnabled() )
                  {
                      getLogger().debug("ignoring disposal error", e );
                  }
              }
          }
      }
  
     /**
      * Notification by the controlling application to dispose of the 
      * service factory.
      */
      public void dispose()
      {
          //
          // dispose of all of the service pools
          //
  
          //Enumeration pools = m_pools.elements();
          //while( pools.hasMoreElements() )
          //{
          //    
          //    ServiceProvider pool = (ServiceProvider) pools.nextElement();
          //    if( pool instanceof Disposable )
          //    {
          //        try
          //        {
          //             if( m_verbose ) if( getLogger().isDebugEnabled() ) 
getLogger().debug( 
          //               "pool entry disposal (" + pool.getRole() + ")");
          //            ((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
          //
  
          Enumeration singletons = m_singletons.elements();
          while( singletons.hasMoreElements() )
          {
              ServiceProvider  singleton = (ServiceProvider) 
singletons.nextElement();
              if( singleton instanceof Disposable )
              {
                  try
                  {
                      if( m_verbose && getLogger().isDebugEnabled() ) 
                      {
                          getLogger().debug( 
                            "singleton entry disposal (" + singleton.getRole() 
+ ")");
                      }
                      ((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
          //
  
          Enumeration transients = m_transients.elements();
          while( transients.hasMoreElements() )
          {
              ServiceProvider object = (ServiceProvider) 
transients.nextElement();
              if( object instanceof Disposable )
              {
                  try
                  {
                      if( m_verbose && getLogger().isDebugEnabled() ) 
                      {
                          getLogger().debug( 
                            "transient entry disposal (" + object.getRole() + 
")");
                      }
                      ((Disposable)object).dispose();
                  }
                  catch( Throwable e )
                  {
                      final String warning = 
                        "Ignoring exception while invoking transient provider 
disposal.";
                      if( getLogger().isWarnEnabled() ) 
                      {
                          getLogger().warn( warning, e );
                      }
                  }
              }
          }
      }
  }
  
  
  
  
  1.1                  
jakarta-avalon-excalibur/merlin/src/java/org/apache/excalibur/merlin/ServiceInfo.java
  
  Index: ServiceInfo.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software License
   * version 1.1, a copy of which has been included with this distribution in
   * the LICENSE.TXT file.
   *
   * Original contribution by OSM SARL, http://www.osm.net
   */
  
  package org.apache.excalibur.merlin;
  
  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.
   * @author Stephen McConnell <[EMAIL PROTECTED]>
   */
  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/merlin/src/java/org/apache/excalibur/merlin/ServiceLoader.java
  
  Index: ServiceLoader.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software License
   * version 1.1, a copy of which has been included with this distribution in
   * the LICENSE.TXT file.
   *
   * Original contribution by OSM SARL, http://www.osm.net
   */
  
  package org.apache.excalibur.merlin;
  
  import java.io.File;
  import java.net.URL;
  import java.net.URLClassLoader;
  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.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.ContextException;
  import org.apache.avalon.framework.service.ServiceManager;
  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>
   * <p>The configuration phase supplies static information to the pipeline 
processor
   * that may be used to configure the target component.
   *
   * <pre>
   * &lt;config&gt;
   *
   *   &lt;about&gt;This is a sample entry in configuration.&lt;/about&gt;
   *
   * &lt;/config&gt;
   * </pre>
   * <p><strong>Note:</strong> The ability to suppliment configurations 
associated with component
   * dependencies is not available at this time.  The above configuration is 
limited in scope to
   * the modification of the target component only.</p>
   * </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="30%" valign="top"><code>ARGS_KEY</code></td>
   * <td>
   * Contains the command line arguments as a <code>String[]</code>. 
   * </td></tr>
   * <tr>
   * <td valign="top"><code>BASE_DIRECTORY_KEY</code></td>
   * <td>
   * Contains the application base directory <code>File</code>. 
   * </td></tr>
   * <tr>
   * <td valign="top"><code>TARGET_KEY</code></td>
   * <td>
   * Contains the name of the target class to be instantiated. 
   * </td></tr>
   * <tr>
   * <td 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 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>
   * <tr>
   * <td 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>
   * @author Stephen McConnell <[EMAIL PROTECTED]>
   */
  public class ServiceLoader extends AbstractLogEnabled implements 
PipelineService
  {
      private static final String DEFAULT_FORMAT = 
         "[%7.7{priority}] (%{category}): %{message}\\n%{throwable}";
      private static OutputStream c_out = System.out;
  
      private String[] m_args;
      private PipelineClassLoader m_classloader;
  
      private File m_root;
      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;
      private ServiceManager m_manager;
  
      
     /**
      * 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;space-sep-list-of-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 merlin.jar;avalon-framework.jar;logkit.jar 
      *     <strong>org.apache.excalibur.merlin.ServiceLoader</strong>
      *      &lt;space-sep-list-of-supporting-jar-files&gt; -target 
&lt;class-name&gt; 
      *   </pre>
      * </ul>
      * 
      * <p><table border="1" cellpadding="3" cellspacing="0" width="80%">
      * <tr bgcolor="#ccccff">
      * <td colspan="2"><b>Command Line Parameters and Arguments</b></td>
      * <tr><td width="30%"><b>Parameter</b></td><td 
width="60%"><b>Description</b></td></tr>
      * <tr>
      * <td 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 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 valign="top"><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 infomration is dependent on the level supplied 
under the 
      * <code>priority</code parameter.</p>
      * </td></tr>
      * <tr><td 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 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 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;
          Logger logger = null;
          try
          {
              CLI cli = new CLI( args );
              Hierarchy hierarchy = createBootstrapLogger( 
cli.getLoggingPriority() );
              logger = new LogKitLogger( hierarchy.getLoggerFor( "" ) );
              Logger merlin = logger.getChildLogger("merlin");
  
              merlin.info("starting");
  
              String target = cli.getTarget();
              if( target == null )
              {
                  merlin.warn(
                     "missing parameter: " + 
                     "-target <required-target-classname>" );
                  merlin.warn("cannot proceed");
                  return;
              }
  
  
              File path = cli.getConfigurationPath();
              Configuration config = null;
              if( path != null )
              {
                  config = getRuntimeConfiguration( path );
              }
              if( config == null ) 
              {
                  config = new DefaultConfiguration("profile", null );
              }
  
              pipeline = new ServiceLoader();
              pipeline.enableLogging( logger );
              pipeline.configure( config );
              pipeline.contextualize( cli.getContext() );
              pipeline.initialize();
  
              pipeline.pipeline( cli.getTarget(), cli.getDisposalPolicy() );
  
          }
          catch( IllegalParameterException ipe )
          {
              System.err.println( ipe.getMessage() );
          }        
          catch( PipelineException e )
          {
              logger.error( e.getMessage() + e.toString() );
              if( pipeline != null ) 
              {
                  pipeline.dispose();
              }
          }
          catch( PipelineRuntimeException e )
          {
              logger.error( e.getMessage() + e.toString() );
              if( pipeline != null ) 
              {
                  pipeline.dispose();
              }
          }
          catch( Throwable e )
          {
              e.printStackTrace();
              if( pipeline != null ) 
              {
                  pipeline.dispose();
              }
          }
      }
  
     /**
      * Returns the verbose mode.
      * @return boolean TRUE if verbose mode enabled
      */
      private boolean getVerbose()
      {
          return m_verbose;
      }
  
      //=======================================================================
      // Configurable
      //=======================================================================
  
     /**
      * Configuration of the pipeline.
      * @param config the configuration
      * @exception ConfigurationException if a configuration exception occurs
      */
      public void configure( Configuration config ) throws 
ConfigurationException
      {
          m_config = config;
      }
  
      //=======================================================================
      // Contextualizable
      //=======================================================================
  
     /**
      * Contextualization of the pipeline including the supply of command-line
      * arguments, include files, target class, and related execution policies.
      * @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.
      * @see ServiceLoaderContext
      */
      public void contextualize( Context context ) throws ContextException
      {
          if( context instanceof ServiceLoaderContext ) 
          {
              try
              { 
                  ServiceLoaderContext c = (ServiceLoaderContext) context;
                  m_includes = c.getIncludes();
                  m_verbose = c.getVerbose();
                  m_policy = c.getDisposalPolicy();
                  m_target = c.getTarget();
              }
              catch( Throwable e )
              {
                  final String error = "Unexpected error while resolving 
pipeline context.";
                  throw new ContextException( error, e );
              }
          }
          else
          {
              try
              {
                  m_includes = (File[]) context.get( 
                    ServiceLoaderContext.INCLUDES_KEY );
              }
              catch( ContextException e )
              {
                  m_includes = new File[0];
              }
  
              try
              {
                  m_verbose = ((Boolean)context.get( 
                    ServiceLoaderContext.VERBOSE_POLICY_KEY )).booleanValue();
              }
              catch( ContextException e )
              {
                  m_verbose = false;
              }
  
              try
              {
                  m_policy = ((Boolean)context.get( 
                     ServiceLoaderContext.DISPOSAL_POLICY_KEY )).booleanValue();
              }
              catch( ContextException e )
              {
                  m_policy = false;
              }
          }
      }
  
      //=======================================================================
      // Initializable
      //=======================================================================
  
     /**
      * Start the pipeline and handle any errors arrising from loader execution.
      * @exception PipelineException if a lifecycle error occurs
      */
      public void initialize() throws PipelineException
      {
          //if( m_target == null ) throw new PipelineException(
          //  "The pipeline task required attribute 'target' has not been not 
supplied.");
  
          //
          // setup the factory
          //
  
          try
          {
              if( m_classloader == null ) 
              {
                  m_classloader = createClassloader();
              }
              m_root = new File( System.getProperty("user.dir") );
              m_factory = new ServiceFactory( m_root, getVerbose() );
              m_factory.enableLogging( getLogger() );
              m_factory.configure( m_config );
              m_factory.initialize();
              enableLogging( getLogger().getChildLogger("loader") );
          }
          catch( Throwable e )
          {
              final String error = "Service loader validation error.";
              getLogger().error( error, e );
              return;
          }
  
          //
          // preprocess the components in the include list
          //
  
          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 );
          }
  
          try
          {
              load( stack );
          }
          catch( Throwable e )
          {
              final String error = "Include failure during initialization.";
              throw new PipelineException( error, e ); 
          }
  
          // build the registry of available services
  
          try
          {
              m_factory.register( list );
          }
          catch( Throwable e )
          {
              final String error = "Factory registration failure.";
              throw new PipelineException( error, e ); 
          }
      }
  
      //=======================================================================
      // PipelineService
      //=======================================================================
  
     /**
      * Initates execution of the loading of supporting services derived from a 
      * target.
      * @param target the name of the class to process
      * @return Object a fully prepared service instance
      * @exception PipelineException if a lifecycle error occurs
      */
      public Object pipeline( String target ) throws PipelineException
      {
  
          //
          // create an instance of the target and verify that dependencies are 
resolvable
          //
  
          UnitInfo info;
          try
          {
              info = new UnitInfo( target.replace('.','/'), m_config, m_root );
              if( getVerbose() && getLogger().isDebugEnabled() ) 
              {
                  getLogger().debug( "validating target");
              }
              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
          {
              return m_factory.pipeline( info );
          }
          catch( Throwable e )
          {
              final String error = "Service loader exception encounter during 
target execution.";
              throw new PipelineException( error, e ); 
          }
      }
  
      //=======================================================================
      // ServiceLoader
      //=======================================================================
  
     /**
      * Handles association of a shutdown hook prior to execution of a normal 
      * pipeline process.
      * @param target the name of the component class
      * @param policy if TRUE then terminate following initialization 
      * @exception PipelineException if a component execution error occurs
      */
      private void pipeline( String target, boolean policy ) throws 
PipelineException
      {
          if( getVerbose() && (getLogger() != null) && 
getLogger().isDebugEnabled() ) 
          {
              getLogger().debug("pipelining: " + target );
          }
  
          final Object object = pipeline( target );
  
          //
          // add a shutdown hook so we can stop services and target and invoke 
disposal
          //
  
          Runtime.getRuntime().addShutdownHook( 
            new Thread()
            {
                public void run()
                {
                    if( getVerbose() )
                    {
                        if( getLogger() != null)
                        {
                            if( getLogger().isDebugEnabled() ) 
                            {
                                getLogger().debug("shutdown initiated");
                            }
                        }
                    }
                    terminate( object );
                    dispose();
                }
            }
          );
  
          if( policy )
          {
              if( object != null )
              {
                  terminate( object );
                  dispose();
                  return;
              }
          }
          else
          {
              getLogger().info( "target established: " + 
object.getClass().getName());
          }
      }
  
     /**
      * Run the termination lifecycle actions on the primary object.
      * @param object the object to terminate
      */
      private void terminate( Object object )
      {
          if( m_terminated ) 
          {
              return;
          }
          m_terminated = true;
          if( object == null ) 
          {
              return;
          }
  
          if( getVerbose() && getLogger().isDebugEnabled() ) 
          {
              getLogger().debug( 
               "terminating " + object.getClass().getName() );
          }
  
          if( object instanceof Startable )
          {
              try
              {
                  ((Startable)object).stop();
              }
              catch( Throwable e )
              {
                  final String warning = "Ignoring error while stopping 
target.";
                  if( getLogger().isWarnEnabled() ) 
                  {
                      getLogger().warn( warning, e );
                  }
              }
          }
  
          if( object instanceof Disposable )
          {
              try
              {
                  ((Disposable)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;
          }
          m_disposed = true;
          if( getVerbose() && 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>Vector</code> containing a sequence of jar files
      *   to be added to the classloader.
      */
      private void load( Vector stack )
      {
          int size = stack.size();
          if( getVerbose() ) 
          {
              getLogger().debug( "Loading stack: " + stack.size() );
          }
          Hashtable errors = new Hashtable();
          Enumeration enum = stack.elements();
          while( enum.hasMoreElements() )
          {
              File file = (File) enum.nextElement();
              if( getVerbose() ) 
              {
                  getLogger().debug( "Loading resource: " + file );
              }
              try
              {
                  m_classloader.addURL( file.toURL() );
                  stack.remove( file );
              }
              catch( Throwable error )
              {
                  if( getVerbose() ) 
                  {
                      getLogger().warn( 
                        "Encountered error while loading resource: " + file, 
error );
                  }
                  errors.put( file, 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 from file: " 
+ file;
              throw new CascadingRuntimeException( error, e ); 
          }
      }
  
      //==========================================================
      // logging
      //==========================================================
  
      private static Hierarchy createBootstrapLogger( Priority priority )
      {
          try
          {
              Hierarchy hierarchy = Hierarchy.getDefaultHierarchy();
              hierarchy.setDefaultLogTarget( 
                 new StreamTarget( c_out, new AvalonFormatter( DEFAULT_FORMAT ) 
) );
              hierarchy.setDefaultPriority( priority );
              return hierarchy;
          }
          catch( Throwable e )
          {
              final String error = "Unexpected exception while creating 
bootstrap logger.";
              throw new CascadingRuntimeException( error, e );
          }
      }
      //==========================================================
      // command-line
      //==========================================================
  
     /**
      * Exception thorwn by the command line handler.
      */
      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 );
          }
      }
  
     /**
      * Command line handler.
      */
      private static class CLI
      {
          private String[] m_args = new String[0];
          private Priority m_priority = Priority.INFO;
          private String m_target = null;
          private boolean m_policy = true;
          private boolean m_verbose = false;
          private File[] m_files = new File[0];
          private File m_path = null;
  
         /**
          * Creation of a new command line handler.
          * @param String[] args the command line arguments to parse
          */
          public CLI( String[] args ) throws IllegalParameterException
          {
              m_args = args;
              Vector vector = new Vector();
              String arg = null;
              for( int i=0; i < m_args.length; i++ )
              {
  
                  arg = m_args[i].toLowerCase();
  
                  if( arg.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( arg.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( arg.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( arg.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( arg.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( arg.startsWith("-") )
                  {
                      final String error = "Unrecognized parameter: " + arg;
                      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] );
          }
  
         /**
          * Returns the target service class name.
          * @return String the name of the target service class
          */
          public String getTarget()
          {
               return m_target;
          }
  
         /**
          * Returns a service loader context.
          * @return ServiceLoaderContext the service loader context
          */
          public ServiceLoaderContext getContext()
          {
               return new ServiceLoaderContext( m_args, m_target, m_files, 
m_policy, m_verbose );
          }
  
         /**
          * Returns the configuration file path
          * @return File the configuration file path
          */
          public File getConfigurationPath()
          {
               return m_path;
          }
  
         /**
          * Returns the logging priority.
          * @return Priority the logging priority to apply.
          */
          public Priority getLoggingPriority()
          {
              return m_priority;
          }
  
         /**
          * Returns the disposal policy.
          * @return boolean the disposal policy.
          */
          public boolean getDisposalPolicy()
          {
              return m_policy;
          }
      }
  }
  
  
  
  
  1.1                  
jakarta-avalon-excalibur/merlin/src/java/org/apache/excalibur/merlin/ServiceLoader.xinfo
  
  Index: ServiceLoader.xinfo
  ===================================================================
  <?xml version="1.0"?>
  
  <blockinfo>
  
    <block name="merlin">
      <version>1.0</version>
    </block>
  
    <services>
        <service name="org.apache.excalibur.merlin.PipelineService" 
version="1.0" />
    </services>
  
    <dependencies/>
  
    <configuration/>
  
    <implementation policy="SINGLETON"/>
  
  </blockinfo>
  
  
  
  
  1.1                  
jakarta-avalon-excalibur/merlin/src/java/org/apache/excalibur/merlin/ServiceLoaderContext.java
  
  Index: ServiceLoaderContext.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software License
   * version 1.1, a copy of which has been included with this distribution in
   * the LICENSE.TXT file.
   *
   * Original contribution by OSM SARL, http://www.osm.net
   */
  
  package org.apache.excalibur.merlin;
  
  import java.io.File;
  import org.apache.avalon.framework.context.DefaultContext;
  import org.apache.avalon.framework.context.ContextException;
  
  /**
   * <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:[EMAIL PROTECTED]">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 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 verbose policy concerning display of loader debug messages
      */
      public ServiceLoaderContext( 
        final String[] args, final String target, final File[] includes, 
        final boolean disposal, 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 ));
      }
  
     /**
      * 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 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/merlin/src/java/org/apache/excalibur/merlin/ServiceProvider.java
  
  Index: ServiceProvider.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software License
   * version 1.1, a copy of which has been included with this distribution in
   * the LICENSE.TXT file.
   *
   * Original contribution by OSM SARL, http://www.osm.net
   */
  
  package org.apache.excalibur.merlin;
  
  import org.apache.avalon.framework.activity.Disposable;
  
  /**
   * <code>ServiceProvider</code> is an abstract base class to services 
   * factories. 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.
   * @author <a href="mailto:[EMAIL PROTECTED]">Stephen McConnell</a>
   */
  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/merlin/src/java/org/apache/excalibur/merlin/ServiceRegistry.java
  
  Index: ServiceRegistry.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software License
   * version 1.1, a copy of which has been included with this distribution in
   * the LICENSE.TXT file.
   *
   * Original contribution by OSM SARL, http://www.osm.net
   */
  
  package org.apache.excalibur.merlin;
  
  import java.io.File;
  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 org.apache.avalon.framework.logger.AbstractLogEnabled;
  import org.apache.avalon.framework.CascadingRuntimeException;
  import org.apache.avalon.framework.CascadingException;
  import org.apache.avalon.framework.configuration.Configurable;
  import org.apache.avalon.framework.configuration.Configuration;
  
  /**
   * Implementation class that provides support for the registration of 
   * meta information about available service implementations.
   */
  class ServiceRegistry extends AbstractLogEnabled implements Configurable
  {
  
      private Configuration m_config; 
      private Vector m_repository = new Vector();
      private UnitInfo[] m_blockInfoSet;
      private Hashtable m_table;
      private Hashtable m_lookup;
      private boolean m_verbose = false;
      private File m_root;
  
     /**
      * Creation of a new <code>ServiceRegistry</code>
      * @param verbose if TRUE, enable DEBUG message priority logging
      */
      public ServiceRegistry( File root, boolean verbose )
      {
          m_verbose = verbose;
          m_root = root;
      }
  
      public void configure( Configuration config )
      {
          m_config = config;
      }
  
     /**
      * Initialize the registry.
      */
      public void initialize() throws Exception
      {
         if( getLogger() == null ) 
         {
             throw new IllegalStateException(
               "Factory logging has not been enabled.");
         }
         if( m_config == null )
         {
             throw new IllegalStateException(
               "Factory has not been configured.");
         }
      }
  
     /**
      * 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();
              register( target );
          }
      }
  
     /**
      * Register a jar file with the registry.
      * @param file the jar file to register
      */
      public void 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 );
          }
      }
  
     /**
      * Lookup the meta info for an implementation based 
      * on a supplied service requirement.
      * @param info meta info describing the required implemenation info
          (return null if no implementation info matches the request)
      * @return UnitInfo meta information about an available implementation
      */
      public UnitInfo lookup( DependencyInfo info )
      {
          Enumeration enum = m_repository.elements();
          while( enum.hasMoreElements() )
          {
              UnitInfo blockInfo = (UnitInfo) enum.nextElement();
              if( blockInfo.provides( info.getService() ) ) 
              {
                  Configuration config = info.getConfiguration();
                  return new UnitInfo( blockInfo, config );
              }
          }
          return null;
      }
  
     /**
      * Returns an array of block infos provided by a supplied jar file.
      * @param file a 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++ )
              {
                  final String path = blocks[i];
                  try
                  {
                      vector.add( new UnitInfo( path, m_root ) );
                  }
                  catch( Throwable e )
                  {
                      if( m_verbose )
                      {
                          getLogger().debug( "bypassing block: " + path, e );
                      }
                      else
                      {
                          getLogger().debug( "bypassing block: " + path );
                      }
                  }
              }
          }
          catch( Throwable e )
          {
              throw new CascadingRuntimeException(
                "Unexpected error while attempting to load file: " + file, e );
          }
          return (UnitInfo[]) vector.toArray( new UnitInfo[0] );
      }
  
  
      
//===============================================================================
      // 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
      * @exception CascadingException if a general exception occurs
      */
      private String[] getBlocks( File file )
      throws CascadingException
      {
          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] );
          }
      }
  }
  
  
  
  
  1.1                  
jakarta-avalon-excalibur/merlin/src/java/org/apache/excalibur/merlin/SingletonProvider.java
  
  Index: SingletonProvider.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software License
   * version 1.1, a copy of which has been included with this distribution in
   * the LICENSE.TXT file.
   *
   * Original contribution by OSM SARL, http://www.osm.net
   */
  
  package org.apache.excalibur.merlin;
  
  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.
   * @author <a href="mailto:[EMAIL PROTECTED]">Stephen McConnell</a>
   */
  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/merlin/src/java/org/apache/excalibur/merlin/TransientProvider.java
  
  Index: TransientProvider.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software License
   * version 1.1, a copy of which has been included with this distribution in
   * the LICENSE.TXT file.
   *
   * Original contribution by OSM SARL, http://www.osm.net
   */
  
  package org.apache.excalibur.merlin;
  
  import org.apache.avalon.framework.CascadingRuntimeException;
  import org.apache.avalon.framework.configuration.Configuration;
  
  /**
   * 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.
   * @author <a href="mailto:[EMAIL PROTECTED]">Stephen McConnell</a>
   */
  class TransientProvider extends ServiceProvider
  {
      private ServiceFactory m_factory;
      private UnitInfo m_info;
      private boolean m_disposed;
      private Configuration m_config;
  
     /**
      * Creation of a new TransientProvider.
      * @param factory the object factory
      * @param info service meta info
      * @param role service role
      */
      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/merlin/src/java/org/apache/excalibur/merlin/UnitInfo.java
  
  Index: UnitInfo.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software License
   * version 1.1, a copy of which has been included with this distribution in
   * the LICENSE.TXT file.
   *
   * Original contribution by OSM SARL, http://www.osm.net
   */
  
  package org.apache.excalibur.merlin;
  
  import java.io.File;
  import java.io.InputStream;
  import java.util.Vector;
  
  import org.apache.avalon.framework.CascadingException;
  import org.apache.avalon.framework.configuration.DefaultConfiguration;
  import org.apache.avalon.framework.configuration.Configuration;
  import org.apache.avalon.framework.configuration.ConfigurationException;
  import org.apache.avalon.framework.configuration.DefaultConfigurationBuilder;
  import org.apache.avalon.framework.context.Context;
  
  import org.apache.excalibur.configuration.ConfigurationUtil;
  import org.apache.excalibur.configuration.CascadingConfiguration;
  import org.apache.excalibur.context.ContextUtility;
  
  /**
   * Meta information about a <code>Serviceable</code> component.  
   * @author <a href="mailto:[EMAIL PROTECTED]">Stephen McConnell</a>
   */
  public class UnitInfo
  {
  
     /**
      * A singleton service.
      */
      public static final int SINGLETON_LIFETIME_POLICY = 0;
  
     /**
      * A transient service.
      */
      public static final int TRANSIENT_LIFETIME_POLICY = 2;
  
     /**
      * A singleton service (pending).
      */
      //public static final int POOLED_LIFETIME_POLICY = 1;
  
      private Class m_block;
      private Configuration m_config;
      private Context m_context;
      private ServiceInfo[] m_services;
      private DependencyInfo[] m_dependencies;
      private int m_policy = SINGLETON_LIFETIME_POLICY;
      private String m_name;
  
     /**
      * 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 xinfo the xinfo meta-information in the form of a Configuration
      * @exception Exception if an internal error occurs
      */
      public UnitInfo( Class block, Configuration xinfo ) throws Exception
      {
          this( block, xinfo, new DefaultConfiguration("configuration",null) );
      }
  
     /**
      * Creation of a new UnitInfo.
      * @param block the implementation class
      * @param xinfo the xinfo meta-information in the form of a Configuration
      * @param conf supplimentary configuration
      * @exception Exception if an internal error occurs
      */
      public UnitInfo( Class block, Configuration xinfo, Configuration conf ) 
      throws Exception
      {
          this( block, xinfo, conf, new File( System.getProperty("user.dir") ) 
);
      }
  
     /**
      * Creation of a new UnitInfo.
      * @param block the implementation class
      * @param xinfo the xinfo meta-information in the form of a Configuration
      * @param conf supplimentary configuration
      * @param root base directory
      * @exception Exception if an internal error occurs
      */
      public UnitInfo( Class block, Configuration xinfo, Configuration conf, 
        File root ) 
      throws Exception
      {
          m_block = block;
          
          // create the list of service provided by block implementation
  
          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 );
          }
  
          // create the list of computational dependecies
  
          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 );
          }
  
          // resolve the implementation policy
  
          String policy = xinfo.getChild("implementation").getAttribute(
            "policy","SINGLETON");
          if( policy.equalsIgnoreCase( "SINGLETON" ) )
          {
              m_policy = SINGLETON_LIFETIME_POLICY;
          }
          else if( policy.equalsIgnoreCase( "TRANSIENT" ) )
          {
              m_policy = TRANSIENT_LIFETIME_POLICY;
          }
          else
          {
              throw new ConfigurationException("Unsupported policy: " + policy 
);
              // Pool support currently disabled (pending fortress finalization)
              //if( Pool.class.isAssignableFrom( block ) )
              //{
              //    m_policy = POOLED_LIFETIME_POLICY;
              //}
              //else
              //{
              //    m_policy = TRANSIENT_LIFETIME_POLICY;
              //}
          }
  
          // get the default configuration
  
          Configuration configuration = xinfo.getChild("configuration");
          String base = configuration.getAttribute("extends", null );
          if( base != null )
          {
              configuration = new CascadingConfiguration( 
                configuration, loadConfiguration( base ) );
          }
          m_config = new CascadingConfiguration( conf, configuration );
  
          // get the default name
  
          m_name = xinfo.getChild("block").getAttribute("name", getClassName() 
);
  
          // get the default context
  
          Context context = new ServiceContext( new String[0], root, getName() 
);
          Configuration contextConfig = xinfo.getChild("context",false);
          if( contextConfig != null )
          {
              m_context = ContextUtility.createContextFromConfiguration( 
                context, contextConfig );
          }
          else
          {
              m_context = context;
          }
      }
  
     /**
      * Creation of a new <code>UnitInfo</code> based on an existing 
      * info and supplimentary configuration.  The implementation will
      * assigns the supplied configuration as the primary configuration
      * backed by the info current configuration.
      * @param info the primary <code>UnitInfo</code>
      * @param config a configuration to assign as the primary 
      *   configuration for the created info
      */
      public UnitInfo( UnitInfo info, Configuration config )
      {
          m_block = info.getBaseClass();
          m_config = new CascadingConfiguration( config, 
info.getConfiguration() );
          m_services = info.getServices();
          m_dependencies = info.getDependencies();
          m_policy = info.getPolicy();
          m_name = info.getName();
          m_context = info.getContext();
      }
  
     /**
      * Creation of a new <code>UnitInfo</code> from a .xinfo resource.
      * @param path the path to the .xinfo resource
      * @exception Exception if an error occurs
      */
      public UnitInfo( String path ) throws Exception
      {
          this( loadClass( path ), loadConfiguration( path + ".xinfo" ) );
      }
  
     /**
      * Creation of a new <code>UnitInfo</code> form configuration given a 
supplied
      * path and base directory.
      * @param path the path to the configuration file
      * @param root the base directory
      * @exception Exception if an error occurs
      */
      public UnitInfo( String path, File root ) throws Exception
      {
          this( path, new DefaultConfiguration("configuration",null), root );
      }
  
     /**
      * Creation of a new <code>UnitInfo</code> form configuration given a 
supplied
      * path, base directory and default configuration.
      * @param path the path to the configuration file
      * @param config the default configuration
      * @param root the base directory
      * @exception Exception if an error occurs
      */
      public UnitInfo( String path, Configuration config, File root ) 
      throws Exception
      {
          this( loadClass( path ), loadConfiguration( 
            path + ".xinfo" ), config, root );
      }
  
     /**
      * Returns the name of the class implementing 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 ServiceInfo 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, or TRANSIENT_LIFETIME_POLICY.
      * @return implementation policy
      */
      public int getPolicy()
      {
          return m_policy;
      }
  
     /**
      * The component implementation class.
      * @return Class the component implementation class
      */
      public Class getBaseClass()
      {
          return m_block;
      }
  
     /**
      * Returns the default configuration.
      * @return Configuration the default configuration
      */
      public Configuration getConfiguration()
      {
          return m_config;
      }
  
     /**
      * Returns the default service context.
      * @return Context the default service context
      */
      public Context getContext()
      {
          return m_context;
      }
  
     /**
      * Returns the block name.
      * @return String the block name
      */
      public String getName()
      {
          return m_name;
      }
  
     /**
      * Returns a string representation of the descriptor.
      * @return String stringified representation
      */
      public String toString()
      {
          final StringBuffer buffer = new StringBuffer();
          buffer.append( "  name: " + getName() );
          buffer.append( "\n  class: " + 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  dependency: " 
                + "role: " + dependencies[i].getRole() 
                + ", service: " + 
dependencies[i].getService().getInterface().getName() 
                + ", version: " + dependencies[i].getService().getVersion() );
          }
          buffer.append("\n  configuration\n");
          buffer.append( ConfigurationUtil.list( this.getConfiguration() ));
          return buffer.toString();
      }
  
     /**
      * Returns a configuration resource form a jar file. 
      * @param path the package path to the resource e.g. net/osm/xinfo.xml
      * @exception ConfigurationException if there is a configuration load error
      */
      private static Configuration loadConfiguration( String path ) 
      throws ConfigurationException 
      {
          try
          {
              DefaultConfigurationBuilder builder = 
                new DefaultConfigurationBuilder( );
              InputStream is = 
                Thread.currentThread().getContextClassLoader().
                  getResourceAsStream( path );
              if( is != null ) 
              {
                  return builder.build( is );
              }
              throw new ConfigurationException( 
                "Could not locate configuration from path: " + path );
          }
          catch( Throwable e )
          {
              final String error = 
                "Unexpected exception while attempting to load .xinfo from 
path: ";
              throw new ConfigurationException( error + path, e ); 
          } 
      }
  
     /**
      * Loads a class given a path in the form <code>org/xyz/MyClass</code>.
      * @param path the resource path
      * @return Class the class loaded from the path
      * @exception Exception if there is a class loading error
      */
      private static Class loadClass( final String path ) throws Exception
      {
          return Thread.currentThread().getContextClassLoader().loadClass( 
path.replace('/','.'));
      }
  }
  
  
  
  
  1.1                  
jakarta-avalon-excalibur/merlin/src/java/org/apache/excalibur/merlin/package.html
  
  Index: package.html
  ===================================================================
  <body>
  <p>Resource supporting the management of components using dynamic service 
composition.</p>
  </body>
  
  
  1.1                  
jakarta-avalon-excalibur/merlin/src/java/org/apache/excalibur/merlin/ant/Load.java
  
  Index: Load.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software License
   * version 1.1, a copy of which has been included with this distribution in
   * the LICENSE.TXT file.
   *
   * Original contribution by OSM SARL, http://www.osm.net
   */
  
  package org.apache.excalibur.merlin.ant;
  
  import java.io.File;
  import java.util.Vector;
  
  import org.apache.tools.ant.BuildException;
  import org.apache.tools.ant.types.FileSet;
  import org.apache.tools.ant.DirectoryScanner;
  import org.apache.tools.ant.Task;
  import org.apache.tools.ant.taskdefs.Execute;
  import org.apache.tools.ant.taskdefs.PumpStreamHandler;
  import org.apache.tools.ant.types.Commandline;
  import org.apache.tools.ant.types.Path;
  
  /**
   * A service loader task.  Loads a series a blocks as supporting services, 
   * supporting libraries, and runs a target component.</p>
   * @author Stephen McConnell <[EMAIL PROTECTED]>
   */
  public class Load extends Task
  {
      private String[] m_args;
  
      private Vector m_filesets = new Vector();
      private Vector m_sysProperties = new Vector();
      private String m_target;
      private String m_priority;
      private String m_policy = "true";
      private String m_verbose = "false";
      private String m_config;
  
      private Commandline m_cmd = new Commandline();
      private Execute m_exe = new Execute(new PumpStreamHandler(System.out, 
System.err));
      private Path m_classpath;
  
      /**
       * Adds a set of files (nested fileset attribute).
       * @param set the file set
       */
      public void addFileset(FileSet set) 
      {
          m_filesets.addElement(set);
      }
  
      /**
       * Creates a nested arg element.
       * @return Commandline.Argument a new command line argument
       */
      public Commandline.Argument createArg() 
      {
          return m_cmd.createArgument();
      }
  
      /**
       * Sets the classpath to the supplied path.
       * @param path the classpath
       */
      public void setClasspath(Path path) 
      {
          if (m_classpath == null) 
          {
              m_classpath = path;
          }
          else 
          {
              m_classpath.append(path);
          }
      }
  
      /**
       * Creates a new classpath.
       * @return the classpath path
       */
      public Path createClasspath() 
      {
          if (m_classpath == null) 
          {
              m_classpath = new Path(project);
          }
          return m_classpath.createPath();
      }
  
      /**
       * Sets the target class.
       * @param target the name of the target service implementation class
       */
      public void setTarget( String target ) 
      {
          m_target = target;
      }
  
      /**
       * Set the log priority.
       * @param level the logging level corresponding to one of INFO, ERROR, 
WARN, 
       *   or DEBUG
       */
      public void setPriority( String level ) 
      {
          m_priority = level;
      }
  
      /**
       * Set the disposal policy.
       * @param policy a value of TRUE or FALSE defining the disposal policy 
       */
      public void setDisposal( String policy ) 
      {
          m_policy = policy;
      }
  
      /**
       * Set the verbose policy.
       * @param value String boolean equivalent 
       */
      public void setVerbose( String value ) 
      {
          m_verbose = value;
      }
  
      /**
       * Set the configuration file.
       * @param value the path to a configuration file 
       */
      public void setConfiguration( String value ) 
      {
          m_config = value;
      }
  
  
      /**
       * Performs execution as an Ant target.
       * @exception BuildException indicates a build faliure
       */
      public void execute() throws BuildException 
      {
  
          // 
          // add the classpath
          //
  
          if (m_classpath == null)
          {
              m_classpath = Path.systemClasspath;
          }
          else
          {
              m_classpath = m_classpath.concatSystemClasspath("ignore");
          }
  
          m_cmd.createArgument().setValue("-classpath");
          m_cmd.createArgument().setPath(m_classpath);
          Commandline toExecute = (Commandline)m_cmd.clone();
          toExecute.setExecutable("java");
  
          // 
          // declare the service loader class
          //
  
          
toExecute.createArgument().setValue("org.apache.excalibur.merlin.ServiceLoader");
  
          //
          // preprocess the fileset into a vector of file arguments
          //
  
          for (int i=0; i<m_filesets.size(); i++) 
          {
              final FileSet fs = (FileSet) m_filesets.elementAt(i);
              final File base = fs.getDir( project );
              final DirectoryScanner ds = fs.getDirectoryScanner(project);
              final String[] files = ds.getIncludedFiles();
              for( int j=0; j<files.length; j++ )
              {
                  File target = new File( base, files[j] );
                  toExecute.createArgument().setValue( target.toString() );
              }
          }
  
  
          // add the target parameter
      
          toExecute.createArgument().setValue( "-target" );
          toExecute.createArgument().setValue( m_target );
          
          // add the priority parameter
      
          toExecute.createArgument().setValue( "-priority");
          toExecute.createArgument().setValue( m_priority );
          
          // add the policy parameter
      
          toExecute.createArgument().setValue( "-disposal");
          toExecute.createArgument().setValue( m_policy );
          
          // add the verbose parameter
      
          toExecute.createArgument().setValue( "-verbose");
          toExecute.createArgument().setValue( m_verbose );
  
          // add the config parameter
      
          if( m_config != null )
          {
              toExecute.createArgument().setValue( "-configuration");
              toExecute.createArgument().setValue( m_config );
          }
  
          try
          {
              m_exe.setAntRun(project);
              m_exe.setWorkingDirectory( new 
File(System.getProperty("user.dir")));
  
              m_exe.setCommandline(toExecute.getCommandline());
              int ret = m_exe.execute();
          }
          catch( Throwable e )
          {
              e.printStackTrace();
              throw new BuildException( e.getMessage() );
          }
      }
  }
  
  
  
  
  1.1                  
jakarta-avalon-excalibur/merlin/src/java/org/apache/excalibur/merlin/ant/package.html
  
  Index: package.html
  ===================================================================
  <body>
  <p>Ant task supporting service execution.</p>
  </body>
  
  

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

Reply via email to