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 <depends>
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>
* <config>
*
* <about>This is a sample entry in configuration.</about>
*
* </config>
* </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>
<space-sep-list-of-supporting-jar-files>
* -target <class-name>
* </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>
* <space-sep-list-of-supporting-jar-files> -target
<class-name>
* </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 <class-name></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><supporting-jar-files></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 <boolean></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 <priority></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 <boolean></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 <file-path></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>
* <blockinfo>
*
* <block>
* <version>1.0</version>
* </block>
*
* <!--
* services that are offered by this block
* -->
*
* <services>
* <service name="hello.Hello" version="1.0"/>
* </services>
*
* <!--
* 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
* -->
*
* <implementation policy="SINGLETON" />
*
* </blockinfo>
* </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]>