* 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(); | |||
| } | |||
| } | |||