* Renamed DefaultAntServiceManager to InstantiatingServiceManager. This implementation now sets-up the service factories and service instances (log enable, service, parameterise, initialise). * Rearranged the service heirarchy, so that services deployed from a service descriptor are visible in the root context (passed to workspaces and project builders). * Service factories are registered using the role name, not the role class name. * Added unit tests for InstantiatingServiceManager. Changes to DefaultConfigurer error messages: * All exceptions thrown by DefaultConfigurer indicate which configuration element the error happened in. * Updated DefaultConfigurer test cases, to check nested error messages where appropriate. git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@271529 13f79535-47bb-0310-9956-ffa450edef68master
@@ -27,7 +27,6 @@ import org.apache.myrmidon.interfaces.configurer.Configurer; | |||
import org.apache.myrmidon.interfaces.converter.MasterConverter; | |||
import org.apache.myrmidon.interfaces.role.RoleInfo; | |||
import org.apache.myrmidon.interfaces.role.RoleManager; | |||
import org.apache.myrmidon.interfaces.type.TypeException; | |||
import org.apache.myrmidon.interfaces.type.TypeFactory; | |||
import org.apache.myrmidon.interfaces.type.TypeManager; | |||
@@ -83,16 +82,36 @@ public class DefaultConfigurer | |||
final Context context ) | |||
throws ConfigurationException | |||
{ | |||
configureObject( object, configuration, context ); | |||
try | |||
{ | |||
// Configure the object | |||
configureObject( object, configuration, context ); | |||
} | |||
catch( final ReportableConfigurationException e ) | |||
{ | |||
// Already have a reasonable error message - so rethrow | |||
throw e.getCause(); | |||
} | |||
catch( final Exception e ) | |||
{ | |||
// Wrap all other errors with general purpose error message | |||
final String message = REZ.getString( "bad-configure-element.error", configuration.getName() ); | |||
throw new ConfigurationException( message, e ); | |||
} | |||
} | |||
/** | |||
* Does the work of configuring an object. | |||
* | |||
* @throws ReportableConfigurationException On error. This exception | |||
* indicates that the error has been wrapped with an appropriate | |||
* error message. | |||
* @throws Exception On error | |||
*/ | |||
private void configureObject( final Object object, | |||
final Configuration configuration, | |||
final Context context ) | |||
throws ConfigurationException | |||
throws Exception | |||
{ | |||
if( object instanceof Configurable ) | |||
{ | |||
@@ -101,12 +120,9 @@ public class DefaultConfigurer | |||
} | |||
else | |||
{ | |||
// Start configuration of the object | |||
final String elemName = configuration.getName(); | |||
// Locate the configurer for this object | |||
final ObjectConfigurer configurer = getConfigurer( object.getClass() ); | |||
// Start configuring this object | |||
final ConfigurationState state = configurer.startConfiguration( object ); | |||
// Set each of the attributes | |||
@@ -124,17 +140,13 @@ public class DefaultConfigurer | |||
{ | |||
final String message = | |||
REZ.getString( "no-such-attribute.error", elemName, name ); | |||
throw new ConfigurationException( message, nspe ); | |||
} | |||
catch( final ConfigurationException ce ) | |||
{ | |||
throw ce; | |||
throw new ReportableConfigurationException( message, nspe ); | |||
} | |||
catch( final Exception ce ) | |||
{ | |||
final String message = | |||
REZ.getString( "bad-set-attribute.error", elemName, name ); | |||
throw new ConfigurationException( message, ce ); | |||
throw new ReportableConfigurationException( message, ce ); | |||
} | |||
} | |||
@@ -145,24 +157,19 @@ public class DefaultConfigurer | |||
try | |||
{ | |||
// Set the content | |||
final PropertyConfigurer contentConfigurer = state.getConfigurer().getContentConfigurer(); | |||
setValue( contentConfigurer, state, content, context ); | |||
setContent( state, content, context ); | |||
} | |||
catch( final NoSuchPropertyException nspe ) | |||
{ | |||
final String message = | |||
REZ.getString( "no-content.error", elemName ); | |||
throw new ConfigurationException( message, nspe ); | |||
} | |||
catch( final ConfigurationException ce ) | |||
{ | |||
throw ce; | |||
throw new ReportableConfigurationException( message ); | |||
} | |||
catch( final Exception ce ) | |||
{ | |||
final String message = | |||
REZ.getString( "bad-set-content.error", elemName ); | |||
throw new ConfigurationException( message, ce ); | |||
throw new ReportableConfigurationException( message, ce ); | |||
} | |||
} | |||
@@ -180,17 +187,17 @@ public class DefaultConfigurer | |||
{ | |||
final String message = | |||
REZ.getString( "no-such-element.error", elemName, name ); | |||
throw new ConfigurationException( message, nspe ); | |||
throw new ReportableConfigurationException( message, nspe ); | |||
} | |||
catch( final ConfigurationException ce ) | |||
catch( final ReportableConfigurationException ce ) | |||
{ | |||
throw ce; | |||
} | |||
catch( final Exception ce ) | |||
{ | |||
final String message = | |||
REZ.getString( "bad-set-element.error", elemName, name ); | |||
throw new ConfigurationException( message, ce ); | |||
REZ.getString( "bad-configure-element.error", name ); | |||
throw new ReportableConfigurationException( message, ce ); | |||
} | |||
} | |||
@@ -240,6 +247,25 @@ public class DefaultConfigurer | |||
configurer.finishConfiguration( state ); | |||
} | |||
/** | |||
* Sets the text content for the element. | |||
*/ | |||
private void setContent( final ConfigurationState state, | |||
final String content, | |||
final Context context ) | |||
throws Exception | |||
{ | |||
// Locate the content configurer | |||
final PropertyConfigurer contentConfigurer = state.getConfigurer().getContentConfigurer(); | |||
if( contentConfigurer == null ) | |||
{ | |||
throw new NoSuchPropertyException(); | |||
} | |||
// Set the content | |||
setValue( contentConfigurer, state, content, context ); | |||
} | |||
/** | |||
* Configures a property from a nested element. | |||
*/ | |||
@@ -323,7 +349,7 @@ public class DefaultConfigurer | |||
= getConfigurerFromName( state.getConfigurer(), name, false ); | |||
// Resolve any props in the id | |||
Object id = resolveProperty( unresolvedId, context ); | |||
Object id = PropertyUtil.resolveProperty( unresolvedId, context, false ); | |||
// Locate the referenced object | |||
Object ref = null; | |||
@@ -331,10 +357,10 @@ public class DefaultConfigurer | |||
{ | |||
ref = context.get( id ); | |||
} | |||
catch( final ContextException exc ) | |||
catch( final ContextException e ) | |||
{ | |||
final String message = REZ.getString( "get-ref.error", id ); | |||
throw new ConfigurationException( message, exc ); | |||
throw new ConfigurationException( message, e ); | |||
} | |||
// Check the types | |||
@@ -349,13 +375,6 @@ public class DefaultConfigurer | |||
childConfigurer.addValue( state, ref ); | |||
} | |||
private Object resolveProperty( final String unresolvedId, | |||
final Context context ) | |||
throws Exception | |||
{ | |||
return PropertyUtil.resolveProperty( unresolvedId, context, false ); | |||
} | |||
/** | |||
* Sets an attribute value. | |||
*/ | |||
@@ -428,7 +447,7 @@ public class DefaultConfigurer | |||
final Configuration element, | |||
final Context context, | |||
final PropertyConfigurer childConfigurer ) | |||
throws ConfigurationException | |||
throws Exception | |||
{ | |||
final String name = element.getName(); | |||
final Class type = childConfigurer.getType(); | |||
@@ -472,30 +491,33 @@ public class DefaultConfigurer | |||
throws Exception | |||
{ | |||
// Try a named property | |||
final NoSuchPropertyException exc; | |||
try | |||
PropertyConfigurer propertyConfigurer = configurer.getProperty( name ); | |||
if( propertyConfigurer != null ) | |||
{ | |||
return configurer.getProperty( name ); | |||
} | |||
catch( NoSuchPropertyException e ) | |||
{ | |||
// Keep for later | |||
exc = e; | |||
return propertyConfigurer; | |||
} | |||
// Try a typed property | |||
final PropertyConfigurer propertyConfigurer = configurer.getTypedProperty(); | |||
if( !ignoreRoleName ) | |||
propertyConfigurer = configurer.getTypedProperty(); | |||
if( propertyConfigurer != null ) | |||
{ | |||
final RoleInfo roleInfo = m_roleManager.getRoleByType( propertyConfigurer.getType() ); | |||
if( roleInfo == null || !name.equalsIgnoreCase( roleInfo.getShorthand() ) ) | |||
if( ignoreRoleName ) | |||
{ | |||
// Rethrow the original exception | |||
throw exc; | |||
return propertyConfigurer; | |||
} | |||
else | |||
{ | |||
// Check the role name | |||
final RoleInfo roleInfo = m_roleManager.getRoleByType( propertyConfigurer.getType() ); | |||
if( roleInfo != null && name.equalsIgnoreCase( roleInfo.getShorthand() ) ) | |||
{ | |||
return propertyConfigurer; | |||
} | |||
} | |||
} | |||
return propertyConfigurer; | |||
// Unknown prop | |||
throw new NoSuchPropertyException(); | |||
} | |||
/** | |||
@@ -504,13 +526,13 @@ public class DefaultConfigurer | |||
*/ | |||
private Object createdTypedObject( final String name, | |||
final Class type ) | |||
throws ConfigurationException | |||
throws Exception | |||
{ | |||
// Attempt to create the object | |||
final Object obj; | |||
try | |||
{ | |||
final TypeFactory factory = getTypeFactory( DataType.class ); | |||
final TypeFactory factory = m_typeManager.getFactory( DataType.class ); | |||
obj = factory.create( name ); | |||
} | |||
catch( final Exception e ) | |||
@@ -537,7 +559,7 @@ public class DefaultConfigurer | |||
* Utility method to instantiate an instance of the specified class. | |||
*/ | |||
private Object createObject( final Class type ) | |||
throws ConfigurationException | |||
throws Exception | |||
{ | |||
try | |||
{ | |||
@@ -551,21 +573,4 @@ public class DefaultConfigurer | |||
throw new ConfigurationException( message, e ); | |||
} | |||
} | |||
/** | |||
* Locates a type factory. | |||
*/ | |||
protected final TypeFactory getTypeFactory( final Class role ) | |||
throws ConfigurationException | |||
{ | |||
try | |||
{ | |||
return m_typeManager.getFactory( role ); | |||
} | |||
catch( final TypeException te ) | |||
{ | |||
final String message = REZ.getString( "no-factory-for-role.error", role.getName() ); | |||
throw new ConfigurationException( message, te ); | |||
} | |||
} | |||
} |
@@ -353,53 +353,24 @@ class DefaultObjectConfigurer | |||
* Returns a configurer for an element of this class. | |||
*/ | |||
public PropertyConfigurer getProperty( final String name ) | |||
throws NoSuchPropertyException | |||
{ | |||
PropertyConfigurer configurer = (PropertyConfigurer)m_props.get( name ); | |||
if( null != configurer ) | |||
{ | |||
return configurer; | |||
} | |||
// Unknown property | |||
final String message = REZ.getString( "unknown-property.error", m_class.getName(), name ); | |||
throw new NoSuchPropertyException( message ); | |||
return (PropertyConfigurer)m_props.get( name ); | |||
} | |||
/** | |||
* Returns a configurer for the typed property of this class. | |||
*/ | |||
public PropertyConfigurer getTypedProperty() | |||
throws NoSuchPropertyException | |||
{ | |||
if( null != m_typedPropConfigurer ) | |||
{ | |||
return m_typedPropConfigurer; | |||
} | |||
else | |||
{ | |||
// No typed property | |||
final String message = REZ.getString( "no-typed-property.error", m_class.getName() ); | |||
throw new NoSuchPropertyException( message ); | |||
} | |||
return m_typedPropConfigurer; | |||
} | |||
/** | |||
* Returns a configurer for the content of this class. | |||
*/ | |||
public PropertyConfigurer getContentConfigurer() | |||
throws NoSuchPropertyException | |||
{ | |||
if( null != m_contentConfigurer ) | |||
{ | |||
return m_contentConfigurer; | |||
} | |||
else | |||
{ | |||
// Does not handle content | |||
final String message = REZ.getString( "content-unsupported.error", m_class.getName() ); | |||
throw new NoSuchPropertyException( message ); | |||
} | |||
return m_contentConfigurer; | |||
} | |||
/** | |||
@@ -7,22 +7,15 @@ | |||
*/ | |||
package org.apache.myrmidon.components.configurer; | |||
import org.apache.avalon.framework.CascadingException; | |||
/** | |||
* An exception thrown when an unknown property is encountered. | |||
* | |||
* TODO - this should extend ConfigurationException, however | |||
* ConfigurationException is final. | |||
* A marker exception that is thrown when an unknown property is encountered. | |||
* | |||
* @author Adam Murdoch | |||
* @version $Revision$ $Date$ | |||
*/ | |||
class NoSuchPropertyException | |||
extends CascadingException | |||
extends Exception | |||
{ | |||
public NoSuchPropertyException( String message ) | |||
{ | |||
super( message ); | |||
} | |||
} |
@@ -43,29 +43,24 @@ interface ObjectConfigurer | |||
* Returns a configurer for a property of this class. | |||
* | |||
* @param name The element name. Property names are case-insensitive. | |||
* @return A configurer for the property. | |||
* @throws NoSuchPropertyException If the property is not valid for this | |||
* class | |||
* @return A configurer for the property, or null if the property is not | |||
* valid for this class. | |||
*/ | |||
PropertyConfigurer getProperty( String name ) | |||
throws NoSuchPropertyException; | |||
PropertyConfigurer getProperty( String name ); | |||
/** | |||
* Returns a configurer for the content of this class. | |||
* Returns a configurer for the text content of this class. | |||
* | |||
* @return A configurer for the content. | |||
* @throws NoSuchPropertyException If the class does not handle content. | |||
* @return A configurer for the text content, or null if the class does not | |||
* support text content. | |||
*/ | |||
PropertyConfigurer getContentConfigurer() | |||
throws NoSuchPropertyException; | |||
PropertyConfigurer getContentConfigurer(); | |||
/** | |||
* Returns a configurer for the typed property of this class. | |||
* | |||
* @return A configurer for the typed property. | |||
* @throws NoSuchPropertyException If the class does not have a typed | |||
* property. | |||
* @return A configurer for the typed property, or null if the class | |||
* does not have a typed property. | |||
*/ | |||
PropertyConfigurer getTypedProperty() | |||
throws NoSuchPropertyException; | |||
PropertyConfigurer getTypedProperty(); | |||
} |
@@ -11,7 +11,7 @@ import org.apache.avalon.framework.configuration.ConfigurationException; | |||
/** | |||
* Configures a property of an object. | |||
* TODO - axe useCreator() and createValue(). | |||
* TODO - axe createValue(). | |||
* | |||
* @author <a href="mailto:adammurdoch_ml@yahoo.com">Adam Murdoch</a> | |||
* @version $Revision$ $Date$ | |||
@@ -25,8 +25,7 @@ interface PropertyConfigurer | |||
/** | |||
* Creates a default value for this property. This value must be configured, | |||
* and then attached to the object using {@link #setValue}. This | |||
* method must be called if {@link #useCreator} returns true. | |||
* and then attached to the object using {@link #addValue}. | |||
* | |||
* @param state The state object, representing the object being configured. | |||
* @return An object which is assignable to the type returned by | |||
@@ -0,0 +1,39 @@ | |||
/* | |||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||
* | |||
* This software is published under the terms of the Apache Software License | |||
* version 1.1, a copy of which has been included with this distribution in | |||
* the LICENSE.txt file. | |||
*/ | |||
package org.apache.myrmidon.components.configurer; | |||
import org.apache.avalon.framework.configuration.ConfigurationException; | |||
/** | |||
* A marker exception. | |||
* | |||
* TODO - this should extend ConfigurationException, except it is final. | |||
* | |||
* @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a> | |||
* @version $Revision$ $Date$ | |||
*/ | |||
class ReportableConfigurationException | |||
extends Exception | |||
{ | |||
private ConfigurationException m_cause; | |||
public ReportableConfigurationException( String s ) | |||
{ | |||
m_cause = new ConfigurationException( s ); | |||
} | |||
public ReportableConfigurationException( String s, Throwable throwable ) | |||
{ | |||
m_cause = new ConfigurationException( s, throwable ); | |||
} | |||
public ConfigurationException getCause() | |||
{ | |||
return m_cause; | |||
} | |||
} |
@@ -1,14 +1,11 @@ | |||
create-object.error=Could not create an object of class {0}. | |||
extra-config-for-ref.error=A reference element can only include an "id" attribute. | |||
get-ref.error=Could not locate reference "{0}". | |||
mismatch-ref-types.error=Mismatched type for reference "{0}". Was expecting an object of type {1}, instead found an object of type {2}. | |||
incompatible-element-types.error=Incompatible creator and adder/setter methods found in class {0} for property "{1}". | |||
multiple-adder-methods-for-element.error=Multiple add{1}() or set{1}() methods found in class {0}. | |||
multiple-creator-methods-for-element.error=Multiple {1}() methods found in class {0}. | |||
multiple-content-setter-methods.error=Multiple content setter methods found in class {0}. | |||
pending-property-value.error=An object created using the creator method has not been set using the adder/setter method. | |||
unknown-property.error=Class {0} does not have a "{1}" property. | |||
content-not-supported.error=Class {0} does not support text content. | |||
must-be-element.error=This property must be configured using a nested element. | |||
too-many-values.error=Too many values for this property. | |||
no-complex-type.error=Can not get complex type for non-primitive type {0}. | |||
@@ -16,13 +13,12 @@ no-such-attribute.error=Attribute "{1}" is not allowed for element <{0}>. | |||
bad-set-attribute.error=Could not set attribute "{1}" for element <{0}>. | |||
bad-set-class-attribute.error=Could not set attribute "{0}" for object of class {1}. | |||
no-such-element.error=Nested <{1}> elements are not allowed for element <{0}>. | |||
bad-set-element.error=Could not handle element <{1}>, nested in element <{0}>. | |||
no-content.error=Text content is not allowed for element <{0}>. | |||
no-content.error=Text content is not allowed in element <{0}>. | |||
bad-set-content.error=Could not set text content for element <{0}>. | |||
typed-adder-non-interface.error=The typed adder for class "{0}" must have a single parameter that is an interface rather than {1} which defines a class. | |||
no-factory-for-role.error=Unable to locate type factory for role "{0}" | |||
create-typed-object.error=Could not create an object of type "{0}" of class {1}. | |||
no-typed-property.error=Class {0} does not have a typed property. | |||
unknown-reference.error=Could not find referenced object "{0}". | |||
bad-configure-element.error=Could not configure element <{0}>. | |||
prop.mismatched-braces.error=Malformed property with mismatched }'s. | |||
prop.missing-value.error=Unable to find "{0}" to expand during property resolution. | |||
prop.missing-value.error=Unable to find "{0}" to expand during property resolution. |
@@ -26,7 +26,6 @@ import org.apache.myrmidon.interfaces.deployer.TypeDefinition; | |||
import org.apache.myrmidon.interfaces.deployer.TypeDeployer; | |||
import org.apache.myrmidon.interfaces.role.RoleInfo; | |||
import org.apache.myrmidon.interfaces.role.RoleManager; | |||
import org.apache.myrmidon.interfaces.service.AntServiceManager; | |||
import org.apache.myrmidon.interfaces.service.ServiceFactory; | |||
import org.apache.myrmidon.interfaces.type.DefaultTypeFactory; | |||
import org.apache.myrmidon.interfaces.type.TypeManager; | |||
@@ -53,7 +52,6 @@ public class DefaultDeployer | |||
/** Map from ClassLoader to the deployer for that class loader. */ | |||
private final Map m_classLoaderDeployers = new HashMap(); | |||
private AntServiceManager m_serviceManager; | |||
/** | |||
* Retrieve relevent services needed to deploy. | |||
@@ -68,7 +66,6 @@ public class DefaultDeployer | |||
m_typeManager = (TypeManager)serviceManager.lookup( TypeManager.ROLE ); | |||
m_roleManager = (RoleManager)serviceManager.lookup( RoleManager.ROLE ); | |||
m_classLoaderManager = (ClassLoaderManager)serviceManager.lookup( ClassLoaderManager.ROLE ); | |||
m_serviceManager = (AntServiceManager)serviceManager.lookup( AntServiceManager.ROLE ); | |||
} | |||
/** | |||
@@ -148,9 +145,9 @@ public class DefaultDeployer | |||
throws Exception | |||
{ | |||
final String roleShorthand = definition.getRoleShorthand(); | |||
final Class serviceType = getRoleType( roleShorthand ); | |||
final String roleName = getRole( roleShorthand ).getName(); | |||
final String factoryClassName = definition.getFactoryClass(); | |||
handleType( deployment, ServiceFactory.class, serviceType.getName(), factoryClassName ); | |||
handleType( deployment, ServiceFactory.class, roleName, factoryClassName ); | |||
} | |||
/** | |||
@@ -205,7 +202,7 @@ public class DefaultDeployer | |||
} | |||
// Deploy general-purpose type | |||
final Class roleType = getRoleType( roleShorthand ); | |||
final Class roleType = getRole( roleShorthand ).getType(); | |||
handleType( deployment, roleType, typeName, className ); | |||
if( getLogger().isDebugEnabled() ) | |||
@@ -275,9 +272,9 @@ public class DefaultDeployer | |||
} | |||
/** | |||
* Determines the type for a role, from its shorthand. | |||
* Locates a role, from its shorthand. | |||
*/ | |||
private Class getRoleType( final String roleShorthand ) | |||
private RoleInfo getRole( final String roleShorthand ) | |||
throws DeploymentException | |||
{ | |||
final RoleInfo roleInfo = m_roleManager.getRoleByShorthandName( roleShorthand ); | |||
@@ -286,6 +283,6 @@ public class DefaultDeployer | |||
final String message = REZ.getString( "unknown-role4name.error", roleShorthand ); | |||
throw new DeploymentException( message ); | |||
} | |||
return roleInfo.getType(); | |||
return roleInfo; | |||
} | |||
} |
@@ -22,6 +22,7 @@ import org.apache.avalon.framework.logger.AbstractLogEnabled; | |||
import org.apache.avalon.framework.parameters.Parameterizable; | |||
import org.apache.avalon.framework.parameters.Parameters; | |||
import org.apache.avalon.framework.service.DefaultServiceManager; | |||
import org.apache.avalon.framework.service.ServiceManager; | |||
import org.apache.avalon.framework.service.Serviceable; | |||
import org.apache.myrmidon.components.deployer.ClassLoaderManager; | |||
import org.apache.myrmidon.interfaces.aspect.AspectManager; | |||
@@ -37,7 +38,7 @@ import org.apache.myrmidon.interfaces.executor.Executor; | |||
import org.apache.myrmidon.interfaces.extensions.ExtensionManager; | |||
import org.apache.myrmidon.interfaces.model.Project; | |||
import org.apache.myrmidon.interfaces.role.RoleManager; | |||
import org.apache.myrmidon.interfaces.service.AntServiceManager; | |||
import org.apache.myrmidon.interfaces.service.MultiSourceServiceManager; | |||
import org.apache.myrmidon.interfaces.type.TypeFactory; | |||
import org.apache.myrmidon.interfaces.type.TypeManager; | |||
import org.apache.myrmidon.interfaces.workspace.Workspace; | |||
@@ -62,6 +63,7 @@ public class DefaultEmbeddor | |||
private Deployer m_deployer; | |||
private TypeManager m_typeManager; | |||
private MultiSourceServiceManager m_workspaceServiceManager; | |||
private List m_components = new ArrayList(); | |||
private DefaultServiceManager m_serviceManager = new DefaultServiceManager(); | |||
@@ -110,7 +112,7 @@ public class DefaultEmbeddor | |||
final TypeFactory factory = m_typeManager.getFactory( ProjectBuilder.class ); | |||
final ProjectBuilder builder = (ProjectBuilder)factory.create( type ); | |||
setupObject( builder, parameters ); | |||
setupObject( builder, m_workspaceServiceManager, parameters ); | |||
return builder; | |||
} | |||
@@ -120,10 +122,9 @@ public class DefaultEmbeddor | |||
public Workspace createWorkspace( final Parameters parameters ) | |||
throws Exception | |||
{ | |||
final String component = getParameter( Workspace.ROLE ); | |||
final Workspace workspace = | |||
(Workspace)createService( component, Workspace.class ); | |||
setupObject( workspace, parameters ); | |||
(Workspace)createService( Workspace.class, PREFIX + "workspace.DefaultWorkspace" ); | |||
setupObject( workspace, m_workspaceServiceManager, parameters ); | |||
return workspace; | |||
} | |||
@@ -148,18 +149,27 @@ public class DefaultEmbeddor | |||
public void initialize() | |||
throws Exception | |||
{ | |||
//setup default properties | |||
// setup default properties | |||
m_defaults = createDefaultParameters(); | |||
//create all the components | |||
createComponents(); | |||
//setup the components | |||
// setup the root components | |||
setupComponents(); | |||
// locate the components we need | |||
m_deployer = (Deployer)m_serviceManager.lookup( Deployer.ROLE ); | |||
m_typeManager = (TypeManager)m_serviceManager.lookup( TypeManager.ROLE ); | |||
// setup a service manager that creates the project services | |||
final ServiceManager projServiceManager | |||
= (ServiceManager)createService( ServiceManager.class, PREFIX + "service.InstantiatingServiceManager" ); | |||
setupObject( projServiceManager, m_serviceManager, m_parameters ); | |||
// setup a service manager to be used by workspaces | |||
m_workspaceServiceManager = new MultiSourceServiceManager(); | |||
m_workspaceServiceManager.add( projServiceManager ); | |||
m_workspaceServiceManager.add( m_serviceManager ); | |||
// setup | |||
setupFiles(); | |||
} | |||
@@ -224,18 +234,16 @@ public class DefaultEmbeddor | |||
defaults.setParameter( "myrmidon.bin.path", "bin" ); | |||
defaults.setParameter( "myrmidon.lib.path", "lib" ); | |||
// Default workspace implementation | |||
defaults.setParameter( Workspace.ROLE, PREFIX + "workspace.DefaultWorkspace" ); | |||
return defaults; | |||
} | |||
/** | |||
* Create all required components. | |||
*/ | |||
private void createComponents() | |||
private void setupComponents() | |||
throws Exception | |||
{ | |||
// Create the components | |||
createComponent( ConverterRegistry.class, PREFIX + "converter.DefaultConverterRegistry" ); | |||
createComponent( ExtensionManager.class, PREFIX + "extensions.DefaultExtensionManager" ); | |||
createComponent( MasterConverter.class, PREFIX + "converter.DefaultMasterConverter" ); | |||
@@ -246,7 +254,13 @@ public class DefaultEmbeddor | |||
createComponent( Deployer.class, PREFIX + "deployer.DefaultDeployer" ); | |||
createComponent( ClassLoaderManager.class, PREFIX + "deployer.DefaultClassLoaderManager" ); | |||
createComponent( Executor.class, PREFIX + "executor.AspectAwareExecutor" ); | |||
createComponent( AntServiceManager.class, PREFIX + "service.DefaultAntServiceManager" ); | |||
// Setup the components | |||
for( Iterator iterator = m_components.iterator(); iterator.hasNext(); ) | |||
{ | |||
final Object component = iterator.next(); | |||
setupObject( component, m_serviceManager, m_parameters ); | |||
} | |||
} | |||
/** | |||
@@ -255,28 +269,11 @@ public class DefaultEmbeddor | |||
private void createComponent( Class roleType, String defaultImpl ) | |||
throws Exception | |||
{ | |||
final String role = roleType.getName(); | |||
final String className = m_parameters.getParameter( role, defaultImpl ); | |||
final Object component = createService( className, roleType ); | |||
m_serviceManager.put( role, component ); | |||
final Object component = createService( roleType, defaultImpl ); | |||
m_serviceManager.put( roleType.getName(), component ); | |||
m_components.add( component ); | |||
} | |||
/** | |||
* Setup all the components. (ir run all required lifecycle methods). | |||
* | |||
* @exception Exception if an error occurs | |||
*/ | |||
private void setupComponents() | |||
throws Exception | |||
{ | |||
for( Iterator iterator = m_components.iterator(); iterator.hasNext(); ) | |||
{ | |||
final Object component = iterator.next(); | |||
setupObject( component, m_parameters ); | |||
} | |||
} | |||
/** | |||
* Setup all the files attributes. | |||
*/ | |||
@@ -354,21 +351,24 @@ public class DefaultEmbeddor | |||
/** | |||
* Create a component that implements an interface. | |||
* | |||
* @param component the name of the component | |||
* @param clazz the name of interface/type | |||
* @param roleType the name of interface/type | |||
* @param defaultImpl the classname of the default implementation | |||
* @return the created object | |||
* @exception Exception if an error occurs | |||
*/ | |||
private Object createService( final String component, final Class clazz ) | |||
private Object createService( final Class roleType, final String defaultImpl ) | |||
throws Exception | |||
{ | |||
final String role = roleType.getName(); | |||
final String className = m_parameters.getParameter( role, defaultImpl ); | |||
try | |||
{ | |||
final Object object = Class.forName( component ).newInstance(); | |||
final Object object = Class.forName( className ).newInstance(); | |||
if( !clazz.isInstance( object ) ) | |||
if( !roleType.isInstance( object ) ) | |||
{ | |||
final String message = REZ.getString( "bad-type.error", component, clazz.getName() ); | |||
final String message = REZ.getString( "bad-type.error", className, roleType.getName() ); | |||
throw new Exception( message ); | |||
} | |||
@@ -376,19 +376,19 @@ public class DefaultEmbeddor | |||
} | |||
catch( final IllegalAccessException iae ) | |||
{ | |||
final String message = REZ.getString( "bad-ctor.error", clazz.getName(), component ); | |||
final String message = REZ.getString( "bad-ctor.error", roleType.getName(), className ); | |||
throw new Exception( message ); | |||
} | |||
catch( final InstantiationException ie ) | |||
{ | |||
final String message = | |||
REZ.getString( "no-instantiate.error", clazz.getName(), component ); | |||
REZ.getString( "no-instantiate.error", roleType.getName(), className ); | |||
throw new Exception( message ); | |||
} | |||
catch( final ClassNotFoundException cnfe ) | |||
{ | |||
final String message = | |||
REZ.getString( "no-class.error", clazz.getName(), component ); | |||
REZ.getString( "no-class.error", roleType.getName(), className ); | |||
throw new Exception( message ); | |||
} | |||
} | |||
@@ -398,6 +398,7 @@ public class DefaultEmbeddor | |||
* parameterise and initialise lifecycle stages. | |||
*/ | |||
private void setupObject( final Object object, | |||
final ServiceManager serviceManager, | |||
final Parameters parameters ) | |||
throws Exception | |||
{ | |||
@@ -405,7 +406,7 @@ public class DefaultEmbeddor | |||
if( object instanceof Serviceable ) | |||
{ | |||
( (Serviceable)object ).service( m_serviceManager ); | |||
( (Serviceable)object ).service( serviceManager ); | |||
} | |||
if( object instanceof Parameterizable ) | |||
@@ -1,151 +0,0 @@ | |||
/* | |||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||
* | |||
* This software is published under the terms of the Apache Software License | |||
* version 1.1, a copy of which has been included with this distribution in | |||
* the LICENSE.txt file. | |||
*/ | |||
package org.apache.myrmidon.components.service; | |||
import java.util.HashMap; | |||
import java.util.Iterator; | |||
import java.util.Map; | |||
import org.apache.avalon.excalibur.i18n.ResourceManager; | |||
import org.apache.avalon.excalibur.i18n.Resources; | |||
import org.apache.avalon.framework.activity.Disposable; | |||
import org.apache.avalon.framework.service.ServiceException; | |||
import org.apache.avalon.framework.service.ServiceManager; | |||
import org.apache.avalon.framework.service.Serviceable; | |||
import org.apache.myrmidon.interfaces.service.AntServiceException; | |||
import org.apache.myrmidon.interfaces.service.AntServiceManager; | |||
import org.apache.myrmidon.interfaces.service.ServiceFactory; | |||
import org.apache.myrmidon.interfaces.type.TypeException; | |||
import org.apache.myrmidon.interfaces.type.TypeFactory; | |||
import org.apache.myrmidon.interfaces.type.TypeManager; | |||
/** | |||
* A service manager implementation. This implementation takes care of | |||
* creating service instances, using a {@link ServiceFactory}, and running the | |||
* service instances through the service lifecycle. Service creation happens | |||
* on demand. | |||
* | |||
* <p>This implementation uses a TypeManager to locate the service factories. | |||
* | |||
* @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a> | |||
* @version $Revision$ $Date$ | |||
*/ | |||
public class DefaultAntServiceManager | |||
implements AntServiceManager, Serviceable, Disposable | |||
{ | |||
private final static Resources REZ = | |||
ResourceManager.getPackageResources( DefaultAntServiceManager.class ); | |||
/** Map from service class -> service object. */ | |||
private Map m_services = new HashMap(); | |||
private TypeFactory m_typeFactory; | |||
/** | |||
* Pass the <code>ServiceManager</code> to the <code>servicable</code>. | |||
* The <code>Servicable</code> implementation should use the specified | |||
* <code>ServiceManager</code> to acquire the components it needs for | |||
* execution. | |||
* | |||
* @param manager The <code>ServiceManager</code> which this | |||
* <code>Servicable</code> uses. | |||
*/ | |||
public void service( ServiceManager manager ) | |||
throws ServiceException | |||
{ | |||
final TypeManager typeManager = (TypeManager)manager.lookup( TypeManager.ROLE ); | |||
try | |||
{ | |||
m_typeFactory = typeManager.getFactory( ServiceFactory.class ); | |||
} | |||
catch( final TypeException e ) | |||
{ | |||
throw new ServiceException( e.getMessage(), e ); | |||
} | |||
} | |||
/** | |||
* Disposes this service manager, and all services created by it. | |||
*/ | |||
public void dispose() | |||
{ | |||
// Dispose the services | |||
for( Iterator iterator = m_services.values().iterator(); iterator.hasNext(); ) | |||
{ | |||
final Object object = iterator.next(); | |||
if( object instanceof Disposable ) | |||
{ | |||
( (Disposable)object ).dispose(); | |||
} | |||
} | |||
// Ditch state | |||
m_services = null; | |||
m_typeFactory = null; | |||
} | |||
/** | |||
* Determines if this service manager contains a particular service. | |||
*/ | |||
public boolean hasService( Class serviceType ) | |||
{ | |||
// If we have already instantiated the service, or if we know how | |||
// to instantiate it, then return true | |||
if( m_services.containsKey( serviceType ) ) | |||
{ | |||
return true; | |||
} | |||
if( m_typeFactory.canCreate( serviceType.getName() ) ) | |||
{ | |||
return true; | |||
} | |||
return false; | |||
} | |||
/** | |||
* Locates a service instance. | |||
*/ | |||
public Object getService( Class serviceType ) | |||
throws AntServiceException | |||
{ | |||
Object service = m_services.get( serviceType ); | |||
if( service == null ) | |||
{ | |||
// Create the service | |||
service = createService( serviceType ); | |||
m_services.put( serviceType, service ); | |||
} | |||
return service; | |||
} | |||
/** | |||
* Creates the service object for a service class. | |||
*/ | |||
private Object createService( Class serviceType ) throws AntServiceException | |||
{ | |||
try | |||
{ | |||
final ServiceFactory factory = (ServiceFactory)m_typeFactory.create( serviceType.getName() ); | |||
// Create the service | |||
final Object service = factory.createService(); | |||
if( !serviceType.isInstance( service ) ) | |||
{ | |||
final String message = REZ.getString( "mismatched-service-type.error", serviceType.getName(), service.getClass().getName() ); | |||
throw new AntServiceException( message ); | |||
} | |||
return service; | |||
} | |||
catch( final Exception e ) | |||
{ | |||
final String message = REZ.getString( "create-service.error", serviceType.getName() ); | |||
throw new AntServiceException( message, e ); | |||
} | |||
} | |||
} |
@@ -0,0 +1,222 @@ | |||
/* | |||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||
* | |||
* This software is published under the terms of the Apache Software License | |||
* version 1.1, a copy of which has been included with this distribution in | |||
* the LICENSE.txt file. | |||
*/ | |||
package org.apache.myrmidon.components.service; | |||
import java.util.ArrayList; | |||
import java.util.HashMap; | |||
import java.util.Iterator; | |||
import java.util.List; | |||
import java.util.Map; | |||
import org.apache.avalon.excalibur.i18n.ResourceManager; | |||
import org.apache.avalon.excalibur.i18n.Resources; | |||
import org.apache.avalon.framework.activity.Disposable; | |||
import org.apache.avalon.framework.activity.Initializable; | |||
import org.apache.avalon.framework.logger.AbstractLogEnabled; | |||
import org.apache.avalon.framework.parameters.ParameterException; | |||
import org.apache.avalon.framework.parameters.Parameterizable; | |||
import org.apache.avalon.framework.parameters.Parameters; | |||
import org.apache.avalon.framework.service.ServiceException; | |||
import org.apache.avalon.framework.service.ServiceManager; | |||
import org.apache.avalon.framework.service.Serviceable; | |||
import org.apache.myrmidon.interfaces.role.RoleInfo; | |||
import org.apache.myrmidon.interfaces.role.RoleManager; | |||
import org.apache.myrmidon.interfaces.service.ServiceFactory; | |||
import org.apache.myrmidon.interfaces.type.TypeException; | |||
import org.apache.myrmidon.interfaces.type.TypeFactory; | |||
import org.apache.myrmidon.interfaces.type.TypeManager; | |||
/** | |||
* A service manager implementation, which creates service instances on demand. | |||
* | |||
* <p>This manager creates service instances, using a {@link ServiceFactory}, | |||
* and running the service instances through the service lifecycle: | |||
* <ul> | |||
* <li>log enable | |||
* <li>service | |||
* <li>parameterise | |||
* <li>initialise | |||
* </ul> | |||
* | |||
* @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a> | |||
* @version $Revision$ $Date$ | |||
*/ | |||
public class InstantiatingServiceManager | |||
extends AbstractLogEnabled | |||
implements ServiceManager, Parameterizable, Serviceable, Disposable | |||
{ | |||
private final static Resources REZ = | |||
ResourceManager.getPackageResources( InstantiatingServiceManager.class ); | |||
/** Map from service class -> service object. */ | |||
private Map m_services = new HashMap(); | |||
/** The objects (services and factories) that have been created by this mgr. */ | |||
private List m_objects = new ArrayList(); | |||
/** Other services used by this service manager. */ | |||
private TypeFactory m_typeFactory; | |||
private RoleManager m_roleManager; | |||
private ServiceManager m_serviceManager; | |||
private Parameters m_parameters; | |||
public void parameterize( Parameters parameters ) throws ParameterException | |||
{ | |||
m_parameters = parameters; | |||
} | |||
/** | |||
* Pass the <code>ServiceManager</code> to the <code>servicable</code>. | |||
* The <code>Servicable</code> implementation should use the specified | |||
* <code>ServiceManager</code> to acquire the components it needs for | |||
* execution. | |||
* | |||
* @param manager The <code>ServiceManager</code> which this | |||
* <code>Servicable</code> uses. | |||
*/ | |||
public void service( final ServiceManager manager ) | |||
throws ServiceException | |||
{ | |||
m_serviceManager = manager; | |||
m_roleManager = (RoleManager)manager.lookup( RoleManager.ROLE ); | |||
final TypeManager typeManager = (TypeManager)manager.lookup( TypeManager.ROLE ); | |||
try | |||
{ | |||
m_typeFactory = typeManager.getFactory( ServiceFactory.class ); | |||
} | |||
catch( final TypeException e ) | |||
{ | |||
throw new ServiceException( e.getMessage(), e ); | |||
} | |||
} | |||
/** | |||
* Disposes this service manager, and all services created by it. | |||
*/ | |||
public void dispose() | |||
{ | |||
// Dispose the services | |||
for( Iterator iterator = m_objects.iterator(); iterator.hasNext(); ) | |||
{ | |||
final Object object = iterator.next(); | |||
if( object instanceof Disposable ) | |||
{ | |||
( (Disposable)object ).dispose(); | |||
} | |||
} | |||
// Ditch state | |||
m_services = null; | |||
m_typeFactory = null; | |||
m_objects = null; | |||
m_parameters = null; | |||
m_roleManager = null; | |||
m_serviceManager = null; | |||
} | |||
/** | |||
* Determines if this service manager contains a particular service. | |||
*/ | |||
public boolean hasService( final String serviceRole ) | |||
{ | |||
// If we have already instantiated the service, or if we know how | |||
// to instantiate it, then return true | |||
if( m_services.containsKey( serviceRole ) ) | |||
{ | |||
return true; | |||
} | |||
if( m_typeFactory.canCreate( serviceRole ) ) | |||
{ | |||
return true; | |||
} | |||
return false; | |||
} | |||
/** | |||
* Locates a service instance. | |||
*/ | |||
public Object lookup( final String serviceRole ) | |||
throws ServiceException | |||
{ | |||
Object service = m_services.get( serviceRole ); | |||
if( service == null ) | |||
{ | |||
// Create the service | |||
service = createService( serviceRole ); | |||
m_services.put( serviceRole, service ); | |||
} | |||
return service; | |||
} | |||
/** | |||
* Releases a service. | |||
*/ | |||
public void release( final Object service ) | |||
{ | |||
} | |||
/** | |||
* Creates the service object for a service role. | |||
*/ | |||
private Object createService( final String serviceRole ) throws ServiceException | |||
{ | |||
try | |||
{ | |||
// Create the factory | |||
final ServiceFactory factory = (ServiceFactory)m_typeFactory.create( serviceRole ); | |||
setupObject( factory ); | |||
// Create the service | |||
final Object service = factory.createService(); | |||
// Check the service is assignable to the role type | |||
final RoleInfo roleInfo = m_roleManager.getRole( serviceRole ); | |||
final Class serviceType = roleInfo.getType(); | |||
if( serviceType != null && !serviceType.isInstance( service ) ) | |||
{ | |||
final String message = REZ.getString( "mismatched-service-type.error", serviceRole, service.getClass().getName() ); | |||
throw new ServiceException( message ); | |||
} | |||
setupObject( service ); | |||
return service; | |||
} | |||
catch( final Exception e ) | |||
{ | |||
final String message = REZ.getString( "create-service.error", serviceRole ); | |||
throw new ServiceException( message, e ); | |||
} | |||
} | |||
/** | |||
* Sets-up an object, taking it through the lifecycle steps. | |||
*/ | |||
private void setupObject( final Object object ) | |||
throws Exception | |||
{ | |||
setupLogger( object ); | |||
if( object instanceof Serviceable ) | |||
{ | |||
( (Serviceable)object ).service( m_serviceManager ); | |||
} | |||
if( object instanceof Parameterizable ) | |||
{ | |||
( (Parameterizable)object ).parameterize( m_parameters ); | |||
} | |||
if( object instanceof Initializable ) | |||
{ | |||
( (Initializable)object ).initialize(); | |||
} | |||
m_objects.add( object ); | |||
} | |||
} |
@@ -1,3 +1,3 @@ | |||
unknown-service-type.error=Unknown service type {0}. | |||
mismatched-service-type.error=Service factory for type {0} produced an object of unexpected type {1}. | |||
create-service.error=Could not create service {0}. | |||
unknown-service-type.error=Unknown service "{0}". | |||
mismatched-service-type.error=Service factory for service "{0}" produced an object of unexpected type {1}. | |||
create-service.error=Could not create service "{0}". |
@@ -14,13 +14,13 @@ import org.apache.avalon.excalibur.i18n.ResourceManager; | |||
import org.apache.avalon.excalibur.i18n.Resources; | |||
import org.apache.avalon.excalibur.io.FileUtil; | |||
import org.apache.avalon.framework.context.ContextException; | |||
import org.apache.avalon.framework.service.ServiceException; | |||
import org.apache.avalon.framework.service.ServiceManager; | |||
import org.apache.myrmidon.api.TaskContext; | |||
import org.apache.myrmidon.api.TaskException; | |||
import org.apache.myrmidon.components.configurer.PropertyUtil; | |||
import org.apache.myrmidon.components.configurer.PropertyException; | |||
import org.apache.myrmidon.components.configurer.PropertyUtil; | |||
import org.apache.myrmidon.interfaces.configurer.TaskContextAdapter; | |||
import org.apache.myrmidon.interfaces.service.AntServiceException; | |||
import org.apache.myrmidon.interfaces.service.AntServiceManager; | |||
/** | |||
* Default implementation of TaskContext. | |||
@@ -36,7 +36,7 @@ public class DefaultTaskContext | |||
private final Map m_contextData = new Hashtable(); | |||
private final TaskContext m_parent; | |||
private AntServiceManager m_serviceManager; | |||
private ServiceManager m_serviceManager; | |||
/** | |||
* Constructor for Context with no parent contexts. | |||
@@ -57,7 +57,7 @@ public class DefaultTaskContext | |||
/** | |||
* Constructor that specifies the service directory for context. | |||
*/ | |||
public DefaultTaskContext( final AntServiceManager serviceManager ) | |||
public DefaultTaskContext( final ServiceManager serviceManager ) | |||
{ | |||
this( null, serviceManager ); | |||
} | |||
@@ -66,7 +66,7 @@ public class DefaultTaskContext | |||
* Constructor that takes both parent context and a service directory. | |||
*/ | |||
public DefaultTaskContext( final TaskContext parent, | |||
final AntServiceManager serviceManager ) | |||
final ServiceManager serviceManager ) | |||
{ | |||
m_parent = parent; | |||
m_serviceManager = serviceManager; | |||
@@ -153,13 +153,13 @@ public class DefaultTaskContext | |||
{ | |||
// Try this context first | |||
final String name = serviceClass.getName(); | |||
if( m_serviceManager != null && m_serviceManager.hasService( serviceClass ) ) | |||
if( m_serviceManager != null && m_serviceManager.hasService( name ) ) | |||
{ | |||
try | |||
{ | |||
return m_serviceManager.getService( serviceClass ); | |||
return m_serviceManager.lookup( name ); | |||
} | |||
catch( final AntServiceException se ) | |||
catch( final ServiceException se ) | |||
{ | |||
throw new TaskException( se.getMessage(), se ); | |||
} | |||
@@ -21,10 +21,10 @@ import org.apache.avalon.framework.logger.Logger; | |||
import org.apache.avalon.framework.parameters.ParameterException; | |||
import org.apache.avalon.framework.parameters.Parameterizable; | |||
import org.apache.avalon.framework.parameters.Parameters; | |||
import org.apache.avalon.framework.service.DefaultServiceManager; | |||
import org.apache.avalon.framework.service.ServiceException; | |||
import org.apache.avalon.framework.service.ServiceManager; | |||
import org.apache.avalon.framework.service.Serviceable; | |||
import org.apache.avalon.framework.service.ServiceException; | |||
import org.apache.avalon.framework.service.DefaultServiceManager; | |||
import org.apache.log.Hierarchy; | |||
import org.apache.myrmidon.api.TaskContext; | |||
import org.apache.myrmidon.api.TaskException; | |||
@@ -37,8 +37,6 @@ import org.apache.myrmidon.interfaces.executor.Executor; | |||
import org.apache.myrmidon.interfaces.model.Project; | |||
import org.apache.myrmidon.interfaces.model.Target; | |||
import org.apache.myrmidon.interfaces.model.TypeLib; | |||
import org.apache.myrmidon.interfaces.service.MultiSourceServiceManager; | |||
import org.apache.myrmidon.interfaces.service.AntServiceManager; | |||
import org.apache.myrmidon.interfaces.type.TypeManager; | |||
import org.apache.myrmidon.interfaces.workspace.Workspace; | |||
import org.apache.myrmidon.listeners.ProjectListener; | |||
@@ -258,15 +256,9 @@ public class DefaultWorkspace | |||
serviceManager.put( Project.ROLE + "/" + name, other ); | |||
} | |||
// Create a service manager that aggregates the contents of the context's | |||
// component manager, and service manager | |||
final MultiSourceServiceManager msServiceManager = new MultiSourceServiceManager(); | |||
msServiceManager.add( (AntServiceManager)serviceManager.lookup( AntServiceManager.ROLE ) ); | |||
msServiceManager.add( new ServiceManagerAdaptor( serviceManager ) ); | |||
// Create and configure the context | |||
final DefaultTaskContext context = | |||
new DefaultTaskContext( m_baseContext, msServiceManager ); | |||
new DefaultTaskContext( m_baseContext, serviceManager ); | |||
context.setProperty( TaskContext.BASE_DIRECTORY, project.getBaseDirectory() ); | |||
// Create a logger | |||
@@ -1,54 +0,0 @@ | |||
/* | |||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||
* | |||
* This software is published under the terms of the Apache Software License | |||
* version 1.1, a copy of which has been included with this distribution in | |||
* the LICENSE.txt file. | |||
*/ | |||
package org.apache.myrmidon.components.workspace; | |||
import org.apache.myrmidon.interfaces.service.AntServiceException; | |||
import org.apache.myrmidon.interfaces.service.AntServiceManager; | |||
import org.apache.avalon.framework.service.ServiceManager; | |||
import org.apache.avalon.framework.service.ServiceException; | |||
/** | |||
* An adaptor from {@link ServiceManager} to {@link AntServiceManager}. | |||
* | |||
* @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a> | |||
* @version $Revision$ $Date$ | |||
*/ | |||
class ServiceManagerAdaptor | |||
implements AntServiceManager | |||
{ | |||
private final ServiceManager m_serviceManager; | |||
public ServiceManagerAdaptor( final ServiceManager componentManager ) | |||
{ | |||
m_serviceManager = componentManager; | |||
} | |||
/** | |||
* Determines if this service manager contains a particular service. | |||
*/ | |||
public boolean hasService( Class serviceType ) | |||
{ | |||
return m_serviceManager.hasService( serviceType.getName() ); | |||
} | |||
/** | |||
* Locates a service instance. | |||
*/ | |||
public Object getService( Class serviceType ) | |||
throws AntServiceException | |||
{ | |||
try | |||
{ | |||
return m_serviceManager.lookup( serviceType.getName() ); | |||
} | |||
catch( final ServiceException se ) | |||
{ | |||
throw new AntServiceException( se.getMessage(), se ); | |||
} | |||
} | |||
} |
@@ -1,37 +0,0 @@ | |||
/* | |||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||
* | |||
* This software is published under the terms of the Apache Software License | |||
* version 1.1, a copy of which has been included with this distribution in | |||
* the LICENSE.txt file. | |||
*/ | |||
package org.apache.myrmidon.interfaces.service; | |||
/** | |||
* Manages a set of services. | |||
* | |||
* @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a> | |||
* @version $Revision$ $Date$ | |||
*/ | |||
public interface AntServiceManager | |||
{ | |||
String ROLE = AntServiceManager.class.getName(); | |||
/** | |||
* Determines if this service manager contains a particular service. | |||
* | |||
* @param serviceType The service interface. | |||
*/ | |||
boolean hasService( Class serviceType ); | |||
/** | |||
* Locates a service instance. | |||
* | |||
* @param serviceType The service interface. | |||
* @return The service instance. The returned object is guaranteed to | |||
* implement the service interface. | |||
* @throws AntServiceException If the service does not exist. | |||
*/ | |||
Object getService( Class serviceType ) | |||
throws AntServiceException; | |||
} |
@@ -10,16 +10,18 @@ package org.apache.myrmidon.interfaces.service; | |||
import java.util.ArrayList; | |||
import org.apache.avalon.excalibur.i18n.ResourceManager; | |||
import org.apache.avalon.excalibur.i18n.Resources; | |||
import org.apache.avalon.framework.service.ServiceException; | |||
import org.apache.avalon.framework.service.ServiceManager; | |||
/** | |||
* A service manager that aggregates services from several | |||
* {@link AntServiceManager} objects. | |||
* {@link ServiceManager} objects. | |||
* | |||
* @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a> | |||
* @version $Revision$ $Date$ | |||
*/ | |||
public class MultiSourceServiceManager | |||
implements AntServiceManager | |||
implements ServiceManager | |||
{ | |||
private final static Resources REZ | |||
= ResourceManager.getPackageResources( MultiSourceServiceManager.class ); | |||
@@ -30,23 +32,21 @@ public class MultiSourceServiceManager | |||
/** | |||
* Adds a service manager to the end of the source list. | |||
*/ | |||
public void add( final AntServiceManager mgr ) | |||
public void add( final ServiceManager mgr ) | |||
{ | |||
m_sources.add( mgr ); | |||
} | |||
/** | |||
* Determines if this service manager contains a particular service. | |||
* | |||
* @param serviceType The service interface. | |||
*/ | |||
public boolean hasService( final Class serviceType ) | |||
public boolean hasService( final String serviceRole ) | |||
{ | |||
final int size = m_sources.size(); | |||
for( int i = 0; i < size; i++ ) | |||
{ | |||
final AntServiceManager serviceManager = (AntServiceManager)m_sources.get( i ); | |||
if( serviceManager.hasService( serviceType ) ) | |||
final ServiceManager serviceManager = (ServiceManager)m_sources.get( i ); | |||
if( serviceManager.hasService( serviceRole ) ) | |||
{ | |||
return true; | |||
} | |||
@@ -57,25 +57,32 @@ public class MultiSourceServiceManager | |||
/** | |||
* Locates a service instance. | |||
* | |||
* @param serviceType The service interface. | |||
* @param serviceRole The service interface. | |||
* @return The service instance. The returned object is guaranteed to | |||
* implement the service interface. | |||
* @throws AntServiceException If the service does not exist. | |||
* @throws ServiceException If the service does not exist. | |||
*/ | |||
public Object getService( final Class serviceType ) | |||
throws AntServiceException | |||
public Object lookup( final String serviceRole ) | |||
throws ServiceException | |||
{ | |||
final int size = m_sources.size(); | |||
for( int i = 0; i < size; i++ ) | |||
{ | |||
final AntServiceManager serviceManager = (AntServiceManager)m_sources.get( i ); | |||
if( serviceManager.hasService( serviceType ) ) | |||
final ServiceManager serviceManager = (ServiceManager)m_sources.get( i ); | |||
if( serviceManager.hasService( serviceRole ) ) | |||
{ | |||
return serviceManager.getService( serviceType ); | |||
return serviceManager.lookup( serviceRole ); | |||
} | |||
} | |||
final String message = REZ.getString( "unknown-service.error", serviceType.getName() ); | |||
throw new AntServiceException( message ); | |||
final String message = REZ.getString( "unknown-service.error", serviceRole ); | |||
throw new ServiceException( message ); | |||
} | |||
/** | |||
* Releases a service. | |||
*/ | |||
public void release( final Object service ) | |||
{ | |||
} | |||
} |
@@ -20,7 +20,7 @@ public interface ServiceFactory | |||
String ROLE = ServiceFactory.class.getName(); | |||
/** | |||
* Create a service that coresponds to this factory. | |||
* Create a service that corresponds to this factory. | |||
* This method is usually called after the factory has been | |||
* prepared and configured as appropriate. | |||
*/ | |||
@@ -10,6 +10,7 @@ package org.apache.myrmidon; | |||
import java.io.File; | |||
import java.io.IOException; | |||
import junit.framework.TestCase; | |||
import org.apache.avalon.framework.CascadingThrowable; | |||
import org.apache.avalon.framework.logger.LogKitLogger; | |||
import org.apache.avalon.framework.logger.Logger; | |||
import org.apache.log.Hierarchy; | |||
@@ -96,11 +97,31 @@ public abstract class AbstractMyrmidonTest | |||
return new LogKitLogger( targetLogger ); | |||
} | |||
/** | |||
* Asserts that an exception chain contains the expected messages. | |||
*/ | |||
protected void assertSameMessage( final String[] messages, final Throwable throwable ) | |||
{ | |||
Throwable current = throwable; | |||
for( int i = 0; i < messages.length; i++ ) | |||
{ | |||
String message = messages[ i ]; | |||
assertNotNull( current ); | |||
assertEquals( message, current.getMessage() ); | |||
if( current instanceof CascadingThrowable ) | |||
{ | |||
current = ( (CascadingThrowable)current ).getCause(); | |||
} | |||
else | |||
{ | |||
current = null; | |||
} | |||
} | |||
} | |||
/** | |||
* Asserts that an exception contains the expected message. | |||
* | |||
* TODO - should take the expected exception, rather than the message, | |||
* to check the entire cause chain. | |||
*/ | |||
protected void assertSameMessage( final String message, final Throwable throwable ) | |||
{ | |||
@@ -26,7 +26,6 @@ import org.apache.myrmidon.components.deployer.DefaultClassLoaderManager; | |||
import org.apache.myrmidon.components.deployer.DefaultDeployer; | |||
import org.apache.myrmidon.components.extensions.DefaultExtensionManager; | |||
import org.apache.myrmidon.components.role.DefaultRoleManager; | |||
import org.apache.myrmidon.components.service.DefaultAntServiceManager; | |||
import org.apache.myrmidon.components.type.DefaultTypeManager; | |||
import org.apache.myrmidon.interfaces.configurer.Configurer; | |||
import org.apache.myrmidon.interfaces.converter.ConverterRegistry; | |||
@@ -34,7 +33,6 @@ import org.apache.myrmidon.interfaces.converter.MasterConverter; | |||
import org.apache.myrmidon.interfaces.deployer.Deployer; | |||
import org.apache.myrmidon.interfaces.extensions.ExtensionManager; | |||
import org.apache.myrmidon.interfaces.role.RoleManager; | |||
import org.apache.myrmidon.interfaces.service.AntServiceManager; | |||
import org.apache.myrmidon.interfaces.type.DefaultTypeFactory; | |||
import org.apache.myrmidon.interfaces.type.TypeException; | |||
import org.apache.myrmidon.interfaces.type.TypeManager; | |||
@@ -117,10 +115,6 @@ public abstract class AbstractComponentTest | |||
m_serviceManager.put( RoleManager.ROLE, component ); | |||
components.add( component ); | |||
component = new DefaultAntServiceManager(); | |||
m_serviceManager.put( AntServiceManager.ROLE, component ); | |||
components.add( component ); | |||
// Log enable the components | |||
for( Iterator iterator = components.iterator(); iterator.hasNext(); ) | |||
{ | |||
@@ -20,8 +20,8 @@ import org.apache.myrmidon.components.workspace.DefaultTaskContext; | |||
import org.apache.myrmidon.framework.DataType; | |||
import org.apache.myrmidon.interfaces.configurer.Configurer; | |||
import org.apache.myrmidon.interfaces.configurer.TaskContextAdapter; | |||
import org.apache.myrmidon.interfaces.role.RoleManager; | |||
import org.apache.myrmidon.interfaces.role.RoleInfo; | |||
import org.apache.myrmidon.interfaces.role.RoleManager; | |||
import org.apache.myrmidon.interfaces.type.DefaultTypeFactory; | |||
/** | |||
@@ -339,8 +339,11 @@ public class DefaultConfigurerTest | |||
} | |||
catch( ConfigurationException e ) | |||
{ | |||
final String message = REZ.getString( "extra-config-for-ref.error" ); | |||
assertSameMessage( message, e ); | |||
final String[] messages = { | |||
REZ.getString( "bad-configure-element.error", "some-prop-ref" ), | |||
REZ.getString( "extra-config-for-ref.error" ) | |||
}; | |||
assertSameMessage( messages, e ); | |||
} | |||
} | |||
@@ -364,10 +367,13 @@ public class DefaultConfigurerTest | |||
} | |||
catch( final ConfigurationException ce ) | |||
{ | |||
final String message = REZ.getString( "typed-adder-non-interface.error", | |||
ConfigTest4.class.getName(), | |||
Integer.class.getName() ); | |||
assertSameMessage( message, ce ); | |||
final String[] messages = { | |||
REZ.getString( "bad-configure-element.error", "test" ), | |||
REZ.getString( "typed-adder-non-interface.error", | |||
ConfigTest4.class.getName(), | |||
Integer.class.getName() ) | |||
}; | |||
assertSameMessage( messages, ce ); | |||
} | |||
} | |||
@@ -390,10 +396,13 @@ public class DefaultConfigurerTest | |||
} | |||
catch( final ConfigurationException ce ) | |||
{ | |||
final String message = REZ.getString( "multiple-adder-methods-for-element.error", | |||
ConfigTest5.class.getName(), | |||
""); | |||
assertSameMessage( message, ce ); | |||
final String[] messages = { | |||
REZ.getString( "bad-configure-element.error", "test" ), | |||
REZ.getString( "multiple-adder-methods-for-element.error", | |||
ConfigTest5.class.getName(), | |||
"") | |||
}; | |||
assertSameMessage( messages, ce ); | |||
} | |||
} | |||
@@ -566,9 +575,11 @@ public class DefaultConfigurerTest | |||
} | |||
catch( ConfigurationException e ) | |||
{ | |||
final String message = REZ.getString( "get-ref.error", | |||
"unknown-prop" ); | |||
assertSameMessage( message, e ); | |||
final String[] messages = { | |||
REZ.getString( "bad-set-attribute.error", "test", "some-prop-ref" ), | |||
REZ.getString( "unknown-reference.error", "unknown-prop" ) | |||
}; | |||
assertSameMessage( messages, e ); | |||
} | |||
} | |||
@@ -594,11 +605,14 @@ public class DefaultConfigurerTest | |||
} | |||
catch( ConfigurationException e ) | |||
{ | |||
final String message = REZ.getString( "mismatch-ref-types.error", | |||
"prop-a", | |||
String.class.getName(), | |||
ConfigTest2.class.getName() ); | |||
assertSameMessage( message, e ); | |||
final String[] messages = { | |||
REZ.getString( "bad-set-attribute.error", "test", "some-prop-ref" ), | |||
REZ.getString( "mismatch-ref-types.error", | |||
"prop-a", | |||
String.class.getName(), | |||
ConfigTest2.class.getName() ) | |||
}; | |||
assertSameMessage( messages, e ); | |||
} | |||
} | |||
@@ -0,0 +1,147 @@ | |||
/* | |||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||
* | |||
* This software is published under the terms of the Apache Software License | |||
* version 1.1, a copy of which has been included with this distribution in | |||
* the LICENSE.txt file. | |||
*/ | |||
package org.apache.myrmidon.components.service; | |||
import org.apache.avalon.excalibur.i18n.ResourceManager; | |||
import org.apache.avalon.excalibur.i18n.Resources; | |||
import org.apache.avalon.framework.parameters.Parameters; | |||
import org.apache.avalon.framework.service.ServiceException; | |||
import org.apache.myrmidon.components.AbstractComponentTest; | |||
import org.apache.myrmidon.interfaces.role.RoleInfo; | |||
import org.apache.myrmidon.interfaces.role.RoleManager; | |||
import org.apache.myrmidon.interfaces.service.ServiceFactory; | |||
import org.apache.myrmidon.interfaces.type.DefaultTypeFactory; | |||
import org.apache.myrmidon.interfaces.type.TypeManager; | |||
/** | |||
* Test cases for the default service manager. | |||
* | |||
* @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a> | |||
* @version $Revision$ $Date$ | |||
*/ | |||
public class InstantiatingServiceManagerTest | |||
extends AbstractComponentTest | |||
{ | |||
private final static Resources REZ | |||
= ResourceManager.getPackageResources( InstantiatingServiceManagerTest.class ); | |||
private InstantiatingServiceManager m_serviceManager; | |||
private Parameters m_parameters = new Parameters(); | |||
public InstantiatingServiceManagerTest( final String name ) | |||
{ | |||
super( name ); | |||
} | |||
/** | |||
* Setup the test case - prepares the set of components. | |||
*/ | |||
protected void setUp() | |||
throws Exception | |||
{ | |||
super.setUp(); | |||
// Set-up the service manager | |||
m_serviceManager = new InstantiatingServiceManager(); | |||
m_serviceManager.enableLogging( createLogger() ); | |||
m_serviceManager.service( getServiceManager() ); | |||
m_serviceManager.parameterize( m_parameters ); | |||
} | |||
/** | |||
* Tests service instantiation. | |||
*/ | |||
public void testCreateService() throws Exception | |||
{ | |||
final String serviceRoleName = "test-service"; | |||
// Setup the test service | |||
registerFactory( serviceRoleName, TestService.class, TestServiceFactory1.class ); | |||
// Create the service | |||
Object service = m_serviceManager.lookup( serviceRoleName ); | |||
// Check service is of the expected class (don't use instanceof) | |||
assertTrue( service.getClass() == TestServiceImpl1.class ); | |||
} | |||
/** | |||
* Tests service lookup. | |||
*/ | |||
public void testLookup() throws Exception | |||
{ | |||
final String serviceRoleName = "test-service"; | |||
// Setup the test service | |||
registerFactory( serviceRoleName, TestService.class, TestServiceFactory1.class ); | |||
// Check whether the service can be instantiated | |||
boolean hasService = m_serviceManager.hasService( serviceRoleName ); | |||
assertTrue( hasService ); | |||
} | |||
/** | |||
* Tests that a service factory and service instance are taken through | |||
* the lifecycle steps. | |||
*/ | |||
public void testLifecycle() throws Exception | |||
{ | |||
final String serviceRoleName = "test-service"; | |||
// Setup the test service | |||
registerFactory( serviceRoleName, TestService.class, TestServiceFactory2.class ); | |||
// Create the service | |||
TestService service = (TestService)m_serviceManager.lookup( serviceRoleName ); | |||
// Check service is of the expected class (don't use instanceof) | |||
assertTrue( service.getClass() == TestServiceImpl2.class ); | |||
// Assert the service has been setup correctly | |||
service.doWork(); | |||
} | |||
/** | |||
* Tests looking up an unknown service. | |||
*/ | |||
public void testUnknownService() throws Exception | |||
{ | |||
// Make sure that hasService() works correctly | |||
final String serviceRole = "some-unknown-service"; | |||
assertTrue( ! m_serviceManager.hasService( serviceRole ) ); | |||
// Make sure that lookup() fails | |||
try | |||
{ | |||
m_serviceManager.lookup( serviceRole ); | |||
fail(); | |||
} | |||
catch( ServiceException e ) | |||
{ | |||
final String message = REZ.getString( "create-service.error", serviceRole ); | |||
assertSameMessage( message, e ); | |||
} | |||
} | |||
/** | |||
* Registers a service factory. | |||
*/ | |||
private void registerFactory( final String serviceRoleName, | |||
final Class serviceType, | |||
final Class factoryClass ) | |||
throws Exception | |||
{ | |||
// TODO - add stuff to TypeDeployer to do this instead | |||
final RoleManager roleManager = (RoleManager)getServiceManager().lookup( RoleManager.ROLE ); | |||
roleManager.addRole( new RoleInfo( serviceRoleName, null, serviceType ) ); | |||
final DefaultTypeFactory typeFactory = new DefaultTypeFactory( getClass().getClassLoader() ); | |||
typeFactory.addNameClassMapping( serviceRoleName, factoryClass.getName() ); | |||
final TypeManager typeManager = (TypeManager)getServiceManager().lookup( TypeManager.ROLE ); | |||
typeManager.registerType( ServiceFactory.class, serviceRoleName, typeFactory ); | |||
} | |||
} |
@@ -0,0 +1,67 @@ | |||
/* | |||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||
* | |||
* This software is published under the terms of the Apache Software License | |||
* version 1.1, a copy of which has been included with this distribution in | |||
* the LICENSE.txt file. | |||
*/ | |||
package org.apache.myrmidon.components.service; | |||
import junit.framework.Assert; | |||
import org.apache.avalon.framework.activity.Initializable; | |||
import org.apache.avalon.framework.logger.LogEnabled; | |||
import org.apache.avalon.framework.logger.Logger; | |||
import org.apache.avalon.framework.parameters.ParameterException; | |||
import org.apache.avalon.framework.parameters.Parameterizable; | |||
import org.apache.avalon.framework.parameters.Parameters; | |||
import org.apache.avalon.framework.service.ServiceException; | |||
import org.apache.avalon.framework.service.ServiceManager; | |||
import org.apache.avalon.framework.service.Serviceable; | |||
/** | |||
* A basic class that asserts that the object is correctly set-up. | |||
* | |||
* @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a> | |||
* @version $Revision$ $Date$ | |||
*/ | |||
public class LifecycleValidator | |||
extends Assert | |||
implements LogEnabled, Serviceable, Parameterizable, Initializable | |||
{ | |||
private String m_state = STATE_NOT_INIT; | |||
private final static String STATE_NOT_INIT = "not-prepared"; | |||
private final static String STATE_LOG_ENABLED = "log-enabled"; | |||
private final static String STATE_SERVICED = "serviced"; | |||
private final static String STATE_PARAMETERISED = "parameterised"; | |||
protected final static String STATE_INITIALISED = "initialised"; | |||
public void enableLogging( final Logger logger ) | |||
{ | |||
assertEquals( STATE_NOT_INIT, m_state ); | |||
m_state = STATE_LOG_ENABLED; | |||
} | |||
public void service( final ServiceManager serviceManager ) throws ServiceException | |||
{ | |||
assertEquals( STATE_LOG_ENABLED, m_state ); | |||
m_state = STATE_SERVICED; | |||
} | |||
public void parameterize( Parameters parameters ) throws ParameterException | |||
{ | |||
assertEquals( STATE_SERVICED, m_state ); | |||
m_state = STATE_PARAMETERISED; | |||
} | |||
public void initialize() throws Exception | |||
{ | |||
assertEquals( STATE_PARAMETERISED, m_state ); | |||
m_state = STATE_INITIALISED; | |||
} | |||
protected void assertSetup() | |||
{ | |||
assertEquals( STATE_INITIALISED, m_state ); | |||
} | |||
} |
@@ -0,0 +1,19 @@ | |||
/* | |||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||
* | |||
* This software is published under the terms of the Apache Software License | |||
* version 1.1, a copy of which has been included with this distribution in | |||
* the LICENSE.txt file. | |||
*/ | |||
package org.apache.myrmidon.components.service; | |||
/** | |||
* A service interface. | |||
* | |||
* @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a> | |||
* @version $Revision$ $Date$ | |||
*/ | |||
public interface TestService | |||
{ | |||
void doWork(); | |||
} |
@@ -0,0 +1,30 @@ | |||
/* | |||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||
* | |||
* This software is published under the terms of the Apache Software License | |||
* version 1.1, a copy of which has been included with this distribution in | |||
* the LICENSE.txt file. | |||
*/ | |||
package org.apache.myrmidon.components.service; | |||
import org.apache.myrmidon.interfaces.service.AntServiceException; | |||
import org.apache.myrmidon.interfaces.service.ServiceFactory; | |||
/** | |||
* A test service factory. | |||
* | |||
* @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a> | |||
* @version $Revision$ $Date$ | |||
*/ | |||
public class TestServiceFactory1 | |||
implements ServiceFactory | |||
{ | |||
/** | |||
* Create a service that coresponds to this factory. | |||
*/ | |||
public Object createService() | |||
throws AntServiceException | |||
{ | |||
return new TestServiceImpl1(); | |||
} | |||
} |
@@ -0,0 +1,33 @@ | |||
/* | |||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||
* | |||
* This software is published under the terms of the Apache Software License | |||
* version 1.1, a copy of which has been included with this distribution in | |||
* the LICENSE.txt file. | |||
*/ | |||
package org.apache.myrmidon.components.service; | |||
import org.apache.myrmidon.interfaces.service.AntServiceException; | |||
import org.apache.myrmidon.interfaces.service.ServiceFactory; | |||
/** | |||
* A test service factory, which asserts that the factory has been properly | |||
* set-up before it is used. | |||
* | |||
* @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a> | |||
* @version $Revision$ $Date$ | |||
*/ | |||
public class TestServiceFactory2 | |||
extends LifecycleValidator | |||
implements ServiceFactory | |||
{ | |||
/** | |||
* Create a service that corresponds to this factory. | |||
*/ | |||
public Object createService() | |||
throws AntServiceException | |||
{ | |||
assertSetup(); | |||
return new TestServiceImpl2(); | |||
} | |||
} |
@@ -0,0 +1,22 @@ | |||
/* | |||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||
* | |||
* This software is published under the terms of the Apache Software License | |||
* version 1.1, a copy of which has been included with this distribution in | |||
* the LICENSE.txt file. | |||
*/ | |||
package org.apache.myrmidon.components.service; | |||
/** | |||
* A test service implementation. | |||
* | |||
* @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a> | |||
* @version $Revision$ $Date$ | |||
*/ | |||
public class TestServiceImpl1 | |||
implements TestService | |||
{ | |||
public void doWork() | |||
{ | |||
} | |||
} |
@@ -0,0 +1,24 @@ | |||
/* | |||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||
* | |||
* This software is published under the terms of the Apache Software License | |||
* version 1.1, a copy of which has been included with this distribution in | |||
* the LICENSE.txt file. | |||
*/ | |||
package org.apache.myrmidon.components.service; | |||
/** | |||
* A test service that asserts it has been set-up correctly. | |||
* | |||
* @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a> | |||
* @version $Revision$ $Date$ | |||
*/ | |||
public class TestServiceImpl2 | |||
extends LifecycleValidator | |||
implements TestService | |||
{ | |||
public void doWork() | |||
{ | |||
assertSetup(); | |||
} | |||
} |
@@ -10,6 +10,7 @@ package org.apache.myrmidon; | |||
import java.io.File; | |||
import java.io.IOException; | |||
import junit.framework.TestCase; | |||
import org.apache.avalon.framework.CascadingThrowable; | |||
import org.apache.avalon.framework.logger.LogKitLogger; | |||
import org.apache.avalon.framework.logger.Logger; | |||
import org.apache.log.Hierarchy; | |||
@@ -96,11 +97,31 @@ public abstract class AbstractMyrmidonTest | |||
return new LogKitLogger( targetLogger ); | |||
} | |||
/** | |||
* Asserts that an exception chain contains the expected messages. | |||
*/ | |||
protected void assertSameMessage( final String[] messages, final Throwable throwable ) | |||
{ | |||
Throwable current = throwable; | |||
for( int i = 0; i < messages.length; i++ ) | |||
{ | |||
String message = messages[ i ]; | |||
assertNotNull( current ); | |||
assertEquals( message, current.getMessage() ); | |||
if( current instanceof CascadingThrowable ) | |||
{ | |||
current = ( (CascadingThrowable)current ).getCause(); | |||
} | |||
else | |||
{ | |||
current = null; | |||
} | |||
} | |||
} | |||
/** | |||
* Asserts that an exception contains the expected message. | |||
* | |||
* TODO - should take the expected exception, rather than the message, | |||
* to check the entire cause chain. | |||
*/ | |||
protected void assertSameMessage( final String message, final Throwable throwable ) | |||
{ | |||
@@ -26,7 +26,6 @@ import org.apache.myrmidon.components.deployer.DefaultClassLoaderManager; | |||
import org.apache.myrmidon.components.deployer.DefaultDeployer; | |||
import org.apache.myrmidon.components.extensions.DefaultExtensionManager; | |||
import org.apache.myrmidon.components.role.DefaultRoleManager; | |||
import org.apache.myrmidon.components.service.DefaultAntServiceManager; | |||
import org.apache.myrmidon.components.type.DefaultTypeManager; | |||
import org.apache.myrmidon.interfaces.configurer.Configurer; | |||
import org.apache.myrmidon.interfaces.converter.ConverterRegistry; | |||
@@ -34,7 +33,6 @@ import org.apache.myrmidon.interfaces.converter.MasterConverter; | |||
import org.apache.myrmidon.interfaces.deployer.Deployer; | |||
import org.apache.myrmidon.interfaces.extensions.ExtensionManager; | |||
import org.apache.myrmidon.interfaces.role.RoleManager; | |||
import org.apache.myrmidon.interfaces.service.AntServiceManager; | |||
import org.apache.myrmidon.interfaces.type.DefaultTypeFactory; | |||
import org.apache.myrmidon.interfaces.type.TypeException; | |||
import org.apache.myrmidon.interfaces.type.TypeManager; | |||
@@ -117,10 +115,6 @@ public abstract class AbstractComponentTest | |||
m_serviceManager.put( RoleManager.ROLE, component ); | |||
components.add( component ); | |||
component = new DefaultAntServiceManager(); | |||
m_serviceManager.put( AntServiceManager.ROLE, component ); | |||
components.add( component ); | |||
// Log enable the components | |||
for( Iterator iterator = components.iterator(); iterator.hasNext(); ) | |||
{ | |||
@@ -20,8 +20,8 @@ import org.apache.myrmidon.components.workspace.DefaultTaskContext; | |||
import org.apache.myrmidon.framework.DataType; | |||
import org.apache.myrmidon.interfaces.configurer.Configurer; | |||
import org.apache.myrmidon.interfaces.configurer.TaskContextAdapter; | |||
import org.apache.myrmidon.interfaces.role.RoleManager; | |||
import org.apache.myrmidon.interfaces.role.RoleInfo; | |||
import org.apache.myrmidon.interfaces.role.RoleManager; | |||
import org.apache.myrmidon.interfaces.type.DefaultTypeFactory; | |||
/** | |||
@@ -339,8 +339,11 @@ public class DefaultConfigurerTest | |||
} | |||
catch( ConfigurationException e ) | |||
{ | |||
final String message = REZ.getString( "extra-config-for-ref.error" ); | |||
assertSameMessage( message, e ); | |||
final String[] messages = { | |||
REZ.getString( "bad-configure-element.error", "some-prop-ref" ), | |||
REZ.getString( "extra-config-for-ref.error" ) | |||
}; | |||
assertSameMessage( messages, e ); | |||
} | |||
} | |||
@@ -364,10 +367,13 @@ public class DefaultConfigurerTest | |||
} | |||
catch( final ConfigurationException ce ) | |||
{ | |||
final String message = REZ.getString( "typed-adder-non-interface.error", | |||
ConfigTest4.class.getName(), | |||
Integer.class.getName() ); | |||
assertSameMessage( message, ce ); | |||
final String[] messages = { | |||
REZ.getString( "bad-configure-element.error", "test" ), | |||
REZ.getString( "typed-adder-non-interface.error", | |||
ConfigTest4.class.getName(), | |||
Integer.class.getName() ) | |||
}; | |||
assertSameMessage( messages, ce ); | |||
} | |||
} | |||
@@ -390,10 +396,13 @@ public class DefaultConfigurerTest | |||
} | |||
catch( final ConfigurationException ce ) | |||
{ | |||
final String message = REZ.getString( "multiple-adder-methods-for-element.error", | |||
ConfigTest5.class.getName(), | |||
""); | |||
assertSameMessage( message, ce ); | |||
final String[] messages = { | |||
REZ.getString( "bad-configure-element.error", "test" ), | |||
REZ.getString( "multiple-adder-methods-for-element.error", | |||
ConfigTest5.class.getName(), | |||
"") | |||
}; | |||
assertSameMessage( messages, ce ); | |||
} | |||
} | |||
@@ -566,9 +575,11 @@ public class DefaultConfigurerTest | |||
} | |||
catch( ConfigurationException e ) | |||
{ | |||
final String message = REZ.getString( "get-ref.error", | |||
"unknown-prop" ); | |||
assertSameMessage( message, e ); | |||
final String[] messages = { | |||
REZ.getString( "bad-set-attribute.error", "test", "some-prop-ref" ), | |||
REZ.getString( "unknown-reference.error", "unknown-prop" ) | |||
}; | |||
assertSameMessage( messages, e ); | |||
} | |||
} | |||
@@ -594,11 +605,14 @@ public class DefaultConfigurerTest | |||
} | |||
catch( ConfigurationException e ) | |||
{ | |||
final String message = REZ.getString( "mismatch-ref-types.error", | |||
"prop-a", | |||
String.class.getName(), | |||
ConfigTest2.class.getName() ); | |||
assertSameMessage( message, e ); | |||
final String[] messages = { | |||
REZ.getString( "bad-set-attribute.error", "test", "some-prop-ref" ), | |||
REZ.getString( "mismatch-ref-types.error", | |||
"prop-a", | |||
String.class.getName(), | |||
ConfigTest2.class.getName() ) | |||
}; | |||
assertSameMessage( messages, e ); | |||
} | |||
} | |||
@@ -0,0 +1,147 @@ | |||
/* | |||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||
* | |||
* This software is published under the terms of the Apache Software License | |||
* version 1.1, a copy of which has been included with this distribution in | |||
* the LICENSE.txt file. | |||
*/ | |||
package org.apache.myrmidon.components.service; | |||
import org.apache.avalon.excalibur.i18n.ResourceManager; | |||
import org.apache.avalon.excalibur.i18n.Resources; | |||
import org.apache.avalon.framework.parameters.Parameters; | |||
import org.apache.avalon.framework.service.ServiceException; | |||
import org.apache.myrmidon.components.AbstractComponentTest; | |||
import org.apache.myrmidon.interfaces.role.RoleInfo; | |||
import org.apache.myrmidon.interfaces.role.RoleManager; | |||
import org.apache.myrmidon.interfaces.service.ServiceFactory; | |||
import org.apache.myrmidon.interfaces.type.DefaultTypeFactory; | |||
import org.apache.myrmidon.interfaces.type.TypeManager; | |||
/** | |||
* Test cases for the default service manager. | |||
* | |||
* @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a> | |||
* @version $Revision$ $Date$ | |||
*/ | |||
public class InstantiatingServiceManagerTest | |||
extends AbstractComponentTest | |||
{ | |||
private final static Resources REZ | |||
= ResourceManager.getPackageResources( InstantiatingServiceManagerTest.class ); | |||
private InstantiatingServiceManager m_serviceManager; | |||
private Parameters m_parameters = new Parameters(); | |||
public InstantiatingServiceManagerTest( final String name ) | |||
{ | |||
super( name ); | |||
} | |||
/** | |||
* Setup the test case - prepares the set of components. | |||
*/ | |||
protected void setUp() | |||
throws Exception | |||
{ | |||
super.setUp(); | |||
// Set-up the service manager | |||
m_serviceManager = new InstantiatingServiceManager(); | |||
m_serviceManager.enableLogging( createLogger() ); | |||
m_serviceManager.service( getServiceManager() ); | |||
m_serviceManager.parameterize( m_parameters ); | |||
} | |||
/** | |||
* Tests service instantiation. | |||
*/ | |||
public void testCreateService() throws Exception | |||
{ | |||
final String serviceRoleName = "test-service"; | |||
// Setup the test service | |||
registerFactory( serviceRoleName, TestService.class, TestServiceFactory1.class ); | |||
// Create the service | |||
Object service = m_serviceManager.lookup( serviceRoleName ); | |||
// Check service is of the expected class (don't use instanceof) | |||
assertTrue( service.getClass() == TestServiceImpl1.class ); | |||
} | |||
/** | |||
* Tests service lookup. | |||
*/ | |||
public void testLookup() throws Exception | |||
{ | |||
final String serviceRoleName = "test-service"; | |||
// Setup the test service | |||
registerFactory( serviceRoleName, TestService.class, TestServiceFactory1.class ); | |||
// Check whether the service can be instantiated | |||
boolean hasService = m_serviceManager.hasService( serviceRoleName ); | |||
assertTrue( hasService ); | |||
} | |||
/** | |||
* Tests that a service factory and service instance are taken through | |||
* the lifecycle steps. | |||
*/ | |||
public void testLifecycle() throws Exception | |||
{ | |||
final String serviceRoleName = "test-service"; | |||
// Setup the test service | |||
registerFactory( serviceRoleName, TestService.class, TestServiceFactory2.class ); | |||
// Create the service | |||
TestService service = (TestService)m_serviceManager.lookup( serviceRoleName ); | |||
// Check service is of the expected class (don't use instanceof) | |||
assertTrue( service.getClass() == TestServiceImpl2.class ); | |||
// Assert the service has been setup correctly | |||
service.doWork(); | |||
} | |||
/** | |||
* Tests looking up an unknown service. | |||
*/ | |||
public void testUnknownService() throws Exception | |||
{ | |||
// Make sure that hasService() works correctly | |||
final String serviceRole = "some-unknown-service"; | |||
assertTrue( ! m_serviceManager.hasService( serviceRole ) ); | |||
// Make sure that lookup() fails | |||
try | |||
{ | |||
m_serviceManager.lookup( serviceRole ); | |||
fail(); | |||
} | |||
catch( ServiceException e ) | |||
{ | |||
final String message = REZ.getString( "create-service.error", serviceRole ); | |||
assertSameMessage( message, e ); | |||
} | |||
} | |||
/** | |||
* Registers a service factory. | |||
*/ | |||
private void registerFactory( final String serviceRoleName, | |||
final Class serviceType, | |||
final Class factoryClass ) | |||
throws Exception | |||
{ | |||
// TODO - add stuff to TypeDeployer to do this instead | |||
final RoleManager roleManager = (RoleManager)getServiceManager().lookup( RoleManager.ROLE ); | |||
roleManager.addRole( new RoleInfo( serviceRoleName, null, serviceType ) ); | |||
final DefaultTypeFactory typeFactory = new DefaultTypeFactory( getClass().getClassLoader() ); | |||
typeFactory.addNameClassMapping( serviceRoleName, factoryClass.getName() ); | |||
final TypeManager typeManager = (TypeManager)getServiceManager().lookup( TypeManager.ROLE ); | |||
typeManager.registerType( ServiceFactory.class, serviceRoleName, typeFactory ); | |||
} | |||
} |
@@ -0,0 +1,67 @@ | |||
/* | |||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||
* | |||
* This software is published under the terms of the Apache Software License | |||
* version 1.1, a copy of which has been included with this distribution in | |||
* the LICENSE.txt file. | |||
*/ | |||
package org.apache.myrmidon.components.service; | |||
import junit.framework.Assert; | |||
import org.apache.avalon.framework.activity.Initializable; | |||
import org.apache.avalon.framework.logger.LogEnabled; | |||
import org.apache.avalon.framework.logger.Logger; | |||
import org.apache.avalon.framework.parameters.ParameterException; | |||
import org.apache.avalon.framework.parameters.Parameterizable; | |||
import org.apache.avalon.framework.parameters.Parameters; | |||
import org.apache.avalon.framework.service.ServiceException; | |||
import org.apache.avalon.framework.service.ServiceManager; | |||
import org.apache.avalon.framework.service.Serviceable; | |||
/** | |||
* A basic class that asserts that the object is correctly set-up. | |||
* | |||
* @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a> | |||
* @version $Revision$ $Date$ | |||
*/ | |||
public class LifecycleValidator | |||
extends Assert | |||
implements LogEnabled, Serviceable, Parameterizable, Initializable | |||
{ | |||
private String m_state = STATE_NOT_INIT; | |||
private final static String STATE_NOT_INIT = "not-prepared"; | |||
private final static String STATE_LOG_ENABLED = "log-enabled"; | |||
private final static String STATE_SERVICED = "serviced"; | |||
private final static String STATE_PARAMETERISED = "parameterised"; | |||
protected final static String STATE_INITIALISED = "initialised"; | |||
public void enableLogging( final Logger logger ) | |||
{ | |||
assertEquals( STATE_NOT_INIT, m_state ); | |||
m_state = STATE_LOG_ENABLED; | |||
} | |||
public void service( final ServiceManager serviceManager ) throws ServiceException | |||
{ | |||
assertEquals( STATE_LOG_ENABLED, m_state ); | |||
m_state = STATE_SERVICED; | |||
} | |||
public void parameterize( Parameters parameters ) throws ParameterException | |||
{ | |||
assertEquals( STATE_SERVICED, m_state ); | |||
m_state = STATE_PARAMETERISED; | |||
} | |||
public void initialize() throws Exception | |||
{ | |||
assertEquals( STATE_PARAMETERISED, m_state ); | |||
m_state = STATE_INITIALISED; | |||
} | |||
protected void assertSetup() | |||
{ | |||
assertEquals( STATE_INITIALISED, m_state ); | |||
} | |||
} |
@@ -0,0 +1,19 @@ | |||
/* | |||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||
* | |||
* This software is published under the terms of the Apache Software License | |||
* version 1.1, a copy of which has been included with this distribution in | |||
* the LICENSE.txt file. | |||
*/ | |||
package org.apache.myrmidon.components.service; | |||
/** | |||
* A service interface. | |||
* | |||
* @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a> | |||
* @version $Revision$ $Date$ | |||
*/ | |||
public interface TestService | |||
{ | |||
void doWork(); | |||
} |
@@ -0,0 +1,30 @@ | |||
/* | |||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||
* | |||
* This software is published under the terms of the Apache Software License | |||
* version 1.1, a copy of which has been included with this distribution in | |||
* the LICENSE.txt file. | |||
*/ | |||
package org.apache.myrmidon.components.service; | |||
import org.apache.myrmidon.interfaces.service.AntServiceException; | |||
import org.apache.myrmidon.interfaces.service.ServiceFactory; | |||
/** | |||
* A test service factory. | |||
* | |||
* @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a> | |||
* @version $Revision$ $Date$ | |||
*/ | |||
public class TestServiceFactory1 | |||
implements ServiceFactory | |||
{ | |||
/** | |||
* Create a service that coresponds to this factory. | |||
*/ | |||
public Object createService() | |||
throws AntServiceException | |||
{ | |||
return new TestServiceImpl1(); | |||
} | |||
} |
@@ -0,0 +1,33 @@ | |||
/* | |||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||
* | |||
* This software is published under the terms of the Apache Software License | |||
* version 1.1, a copy of which has been included with this distribution in | |||
* the LICENSE.txt file. | |||
*/ | |||
package org.apache.myrmidon.components.service; | |||
import org.apache.myrmidon.interfaces.service.AntServiceException; | |||
import org.apache.myrmidon.interfaces.service.ServiceFactory; | |||
/** | |||
* A test service factory, which asserts that the factory has been properly | |||
* set-up before it is used. | |||
* | |||
* @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a> | |||
* @version $Revision$ $Date$ | |||
*/ | |||
public class TestServiceFactory2 | |||
extends LifecycleValidator | |||
implements ServiceFactory | |||
{ | |||
/** | |||
* Create a service that corresponds to this factory. | |||
*/ | |||
public Object createService() | |||
throws AntServiceException | |||
{ | |||
assertSetup(); | |||
return new TestServiceImpl2(); | |||
} | |||
} |
@@ -0,0 +1,22 @@ | |||
/* | |||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||
* | |||
* This software is published under the terms of the Apache Software License | |||
* version 1.1, a copy of which has been included with this distribution in | |||
* the LICENSE.txt file. | |||
*/ | |||
package org.apache.myrmidon.components.service; | |||
/** | |||
* A test service implementation. | |||
* | |||
* @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a> | |||
* @version $Revision$ $Date$ | |||
*/ | |||
public class TestServiceImpl1 | |||
implements TestService | |||
{ | |||
public void doWork() | |||
{ | |||
} | |||
} |
@@ -0,0 +1,24 @@ | |||
/* | |||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||
* | |||
* This software is published under the terms of the Apache Software License | |||
* version 1.1, a copy of which has been included with this distribution in | |||
* the LICENSE.txt file. | |||
*/ | |||
package org.apache.myrmidon.components.service; | |||
/** | |||
* A test service that asserts it has been set-up correctly. | |||
* | |||
* @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a> | |||
* @version $Revision$ $Date$ | |||
*/ | |||
public class TestServiceImpl2 | |||
extends LifecycleValidator | |||
implements TestService | |||
{ | |||
public void doWork() | |||
{ | |||
assertSetup(); | |||
} | |||
} |