From f42a96f3046b6a665f9755123c9f7939e53737ba Mon Sep 17 00:00:00 2001 From: adammurdoch Date: Sun, 24 Feb 2002 07:43:38 +0000 Subject: [PATCH] Removed AntServiceManager: * 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-ffa450edef68 --- .../configurer/DefaultConfigurer.java | 147 ++++++------ .../configurer/DefaultObjectConfigurer.java | 35 +-- .../configurer/NoSuchPropertyException.java | 13 +- .../configurer/ObjectConfigurer.java | 25 +- .../configurer/PropertyConfigurer.java | 5 +- .../ReportableConfigurationException.java | 39 +++ .../configurer/Resources.properties | 12 +- .../components/deployer/DefaultDeployer.java | 15 +- .../components/embeddor/DefaultEmbeddor.java | 89 +++---- .../service/DefaultAntServiceManager.java | 151 ------------ .../service/InstantiatingServiceManager.java | 222 ++++++++++++++++++ .../components/service/Resources.properties | 6 +- .../workspace/DefaultTaskContext.java | 18 +- .../workspace/DefaultWorkspace.java | 14 +- .../workspace/ServiceManagerAdaptor.java | 54 ----- .../interfaces/service/AntServiceManager.java | 37 --- .../service/MultiSourceServiceManager.java | 41 ++-- .../interfaces/service/ServiceFactory.java | 2 +- .../apache/myrmidon/AbstractMyrmidonTest.java | 27 ++- .../components/AbstractComponentTest.java | 6 - .../configurer/DefaultConfigurerTest.java | 52 ++-- .../InstantiatingServiceManagerTest.java | 147 ++++++++++++ .../service/LifecycleValidator.java | 67 ++++++ .../components/service/TestService.java | 19 ++ .../service/TestServiceFactory1.java | 30 +++ .../service/TestServiceFactory2.java | 33 +++ .../components/service/TestServiceImpl1.java | 22 ++ .../components/service/TestServiceImpl2.java | 24 ++ .../apache/myrmidon/AbstractMyrmidonTest.java | 27 ++- .../components/AbstractComponentTest.java | 6 - .../configurer/DefaultConfigurerTest.java | 52 ++-- .../InstantiatingServiceManagerTest.java | 147 ++++++++++++ .../service/LifecycleValidator.java | 67 ++++++ .../components/service/TestService.java | 19 ++ .../service/TestServiceFactory1.java | 30 +++ .../service/TestServiceFactory2.java | 33 +++ .../components/service/TestServiceImpl1.java | 22 ++ .../components/service/TestServiceImpl2.java | 24 ++ 38 files changed, 1248 insertions(+), 531 deletions(-) create mode 100644 proposal/myrmidon/src/java/org/apache/myrmidon/components/configurer/ReportableConfigurationException.java delete mode 100644 proposal/myrmidon/src/java/org/apache/myrmidon/components/service/DefaultAntServiceManager.java create mode 100644 proposal/myrmidon/src/java/org/apache/myrmidon/components/service/InstantiatingServiceManager.java delete mode 100644 proposal/myrmidon/src/java/org/apache/myrmidon/components/workspace/ServiceManagerAdaptor.java delete mode 100644 proposal/myrmidon/src/java/org/apache/myrmidon/interfaces/service/AntServiceManager.java create mode 100644 proposal/myrmidon/src/test/org/apache/myrmidon/components/service/InstantiatingServiceManagerTest.java create mode 100644 proposal/myrmidon/src/test/org/apache/myrmidon/components/service/LifecycleValidator.java create mode 100644 proposal/myrmidon/src/test/org/apache/myrmidon/components/service/TestService.java create mode 100644 proposal/myrmidon/src/test/org/apache/myrmidon/components/service/TestServiceFactory1.java create mode 100644 proposal/myrmidon/src/test/org/apache/myrmidon/components/service/TestServiceFactory2.java create mode 100644 proposal/myrmidon/src/test/org/apache/myrmidon/components/service/TestServiceImpl1.java create mode 100644 proposal/myrmidon/src/test/org/apache/myrmidon/components/service/TestServiceImpl2.java create mode 100644 proposal/myrmidon/src/testcases/org/apache/myrmidon/components/service/InstantiatingServiceManagerTest.java create mode 100644 proposal/myrmidon/src/testcases/org/apache/myrmidon/components/service/LifecycleValidator.java create mode 100644 proposal/myrmidon/src/testcases/org/apache/myrmidon/components/service/TestService.java create mode 100644 proposal/myrmidon/src/testcases/org/apache/myrmidon/components/service/TestServiceFactory1.java create mode 100644 proposal/myrmidon/src/testcases/org/apache/myrmidon/components/service/TestServiceFactory2.java create mode 100644 proposal/myrmidon/src/testcases/org/apache/myrmidon/components/service/TestServiceImpl1.java create mode 100644 proposal/myrmidon/src/testcases/org/apache/myrmidon/components/service/TestServiceImpl2.java diff --git a/proposal/myrmidon/src/java/org/apache/myrmidon/components/configurer/DefaultConfigurer.java b/proposal/myrmidon/src/java/org/apache/myrmidon/components/configurer/DefaultConfigurer.java index ff9dbdb02..bbadf49c8 100644 --- a/proposal/myrmidon/src/java/org/apache/myrmidon/components/configurer/DefaultConfigurer.java +++ b/proposal/myrmidon/src/java/org/apache/myrmidon/components/configurer/DefaultConfigurer.java @@ -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 ); - } - } } diff --git a/proposal/myrmidon/src/java/org/apache/myrmidon/components/configurer/DefaultObjectConfigurer.java b/proposal/myrmidon/src/java/org/apache/myrmidon/components/configurer/DefaultObjectConfigurer.java index b3c94695e..d490a0094 100644 --- a/proposal/myrmidon/src/java/org/apache/myrmidon/components/configurer/DefaultObjectConfigurer.java +++ b/proposal/myrmidon/src/java/org/apache/myrmidon/components/configurer/DefaultObjectConfigurer.java @@ -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; } /** diff --git a/proposal/myrmidon/src/java/org/apache/myrmidon/components/configurer/NoSuchPropertyException.java b/proposal/myrmidon/src/java/org/apache/myrmidon/components/configurer/NoSuchPropertyException.java index 758ff659e..f3162a5f8 100644 --- a/proposal/myrmidon/src/java/org/apache/myrmidon/components/configurer/NoSuchPropertyException.java +++ b/proposal/myrmidon/src/java/org/apache/myrmidon/components/configurer/NoSuchPropertyException.java @@ -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 ); - } } diff --git a/proposal/myrmidon/src/java/org/apache/myrmidon/components/configurer/ObjectConfigurer.java b/proposal/myrmidon/src/java/org/apache/myrmidon/components/configurer/ObjectConfigurer.java index 760374e7a..a50c34376 100644 --- a/proposal/myrmidon/src/java/org/apache/myrmidon/components/configurer/ObjectConfigurer.java +++ b/proposal/myrmidon/src/java/org/apache/myrmidon/components/configurer/ObjectConfigurer.java @@ -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(); } diff --git a/proposal/myrmidon/src/java/org/apache/myrmidon/components/configurer/PropertyConfigurer.java b/proposal/myrmidon/src/java/org/apache/myrmidon/components/configurer/PropertyConfigurer.java index 0ca8f43eb..bf9941e27 100644 --- a/proposal/myrmidon/src/java/org/apache/myrmidon/components/configurer/PropertyConfigurer.java +++ b/proposal/myrmidon/src/java/org/apache/myrmidon/components/configurer/PropertyConfigurer.java @@ -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 Adam Murdoch * @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 diff --git a/proposal/myrmidon/src/java/org/apache/myrmidon/components/configurer/ReportableConfigurationException.java b/proposal/myrmidon/src/java/org/apache/myrmidon/components/configurer/ReportableConfigurationException.java new file mode 100644 index 000000000..27b19672d --- /dev/null +++ b/proposal/myrmidon/src/java/org/apache/myrmidon/components/configurer/ReportableConfigurationException.java @@ -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 Adam Murdoch + * @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; + } +} diff --git a/proposal/myrmidon/src/java/org/apache/myrmidon/components/configurer/Resources.properties b/proposal/myrmidon/src/java/org/apache/myrmidon/components/configurer/Resources.properties index c3e748a2a..9e239fc44 100644 --- a/proposal/myrmidon/src/java/org/apache/myrmidon/components/configurer/Resources.properties +++ b/proposal/myrmidon/src/java/org/apache/myrmidon/components/configurer/Resources.properties @@ -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. \ No newline at end of file +prop.missing-value.error=Unable to find "{0}" to expand during property resolution. diff --git a/proposal/myrmidon/src/java/org/apache/myrmidon/components/deployer/DefaultDeployer.java b/proposal/myrmidon/src/java/org/apache/myrmidon/components/deployer/DefaultDeployer.java index 0f2d0aef4..861580d11 100644 --- a/proposal/myrmidon/src/java/org/apache/myrmidon/components/deployer/DefaultDeployer.java +++ b/proposal/myrmidon/src/java/org/apache/myrmidon/components/deployer/DefaultDeployer.java @@ -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; } } diff --git a/proposal/myrmidon/src/java/org/apache/myrmidon/components/embeddor/DefaultEmbeddor.java b/proposal/myrmidon/src/java/org/apache/myrmidon/components/embeddor/DefaultEmbeddor.java index 9555fa0d4..b6929f6e1 100644 --- a/proposal/myrmidon/src/java/org/apache/myrmidon/components/embeddor/DefaultEmbeddor.java +++ b/proposal/myrmidon/src/java/org/apache/myrmidon/components/embeddor/DefaultEmbeddor.java @@ -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 ) diff --git a/proposal/myrmidon/src/java/org/apache/myrmidon/components/service/DefaultAntServiceManager.java b/proposal/myrmidon/src/java/org/apache/myrmidon/components/service/DefaultAntServiceManager.java deleted file mode 100644 index 7d2f063e3..000000000 --- a/proposal/myrmidon/src/java/org/apache/myrmidon/components/service/DefaultAntServiceManager.java +++ /dev/null @@ -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. - * - *

This implementation uses a TypeManager to locate the service factories. - * - * @author Adam Murdoch - * @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 ServiceManager to the servicable. - * The Servicable implementation should use the specified - * ServiceManager to acquire the components it needs for - * execution. - * - * @param manager The ServiceManager which this - * Servicable 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 ); - } - } -} diff --git a/proposal/myrmidon/src/java/org/apache/myrmidon/components/service/InstantiatingServiceManager.java b/proposal/myrmidon/src/java/org/apache/myrmidon/components/service/InstantiatingServiceManager.java new file mode 100644 index 000000000..fa86d726b --- /dev/null +++ b/proposal/myrmidon/src/java/org/apache/myrmidon/components/service/InstantiatingServiceManager.java @@ -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. + * + *

This manager creates service instances, using a {@link ServiceFactory}, + * and running the service instances through the service lifecycle: + *

+ * + * @author Adam Murdoch + * @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 ServiceManager to the servicable. + * The Servicable implementation should use the specified + * ServiceManager to acquire the components it needs for + * execution. + * + * @param manager The ServiceManager which this + * Servicable 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 ); + } +} diff --git a/proposal/myrmidon/src/java/org/apache/myrmidon/components/service/Resources.properties b/proposal/myrmidon/src/java/org/apache/myrmidon/components/service/Resources.properties index 09d9d6492..fdc7b03bd 100644 --- a/proposal/myrmidon/src/java/org/apache/myrmidon/components/service/Resources.properties +++ b/proposal/myrmidon/src/java/org/apache/myrmidon/components/service/Resources.properties @@ -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}. \ No newline at end of file +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}". \ No newline at end of file diff --git a/proposal/myrmidon/src/java/org/apache/myrmidon/components/workspace/DefaultTaskContext.java b/proposal/myrmidon/src/java/org/apache/myrmidon/components/workspace/DefaultTaskContext.java index 12eafb7b8..4d64598db 100644 --- a/proposal/myrmidon/src/java/org/apache/myrmidon/components/workspace/DefaultTaskContext.java +++ b/proposal/myrmidon/src/java/org/apache/myrmidon/components/workspace/DefaultTaskContext.java @@ -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 ); } diff --git a/proposal/myrmidon/src/java/org/apache/myrmidon/components/workspace/DefaultWorkspace.java b/proposal/myrmidon/src/java/org/apache/myrmidon/components/workspace/DefaultWorkspace.java index 8d0f92cca..935d88504 100644 --- a/proposal/myrmidon/src/java/org/apache/myrmidon/components/workspace/DefaultWorkspace.java +++ b/proposal/myrmidon/src/java/org/apache/myrmidon/components/workspace/DefaultWorkspace.java @@ -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 diff --git a/proposal/myrmidon/src/java/org/apache/myrmidon/components/workspace/ServiceManagerAdaptor.java b/proposal/myrmidon/src/java/org/apache/myrmidon/components/workspace/ServiceManagerAdaptor.java deleted file mode 100644 index c5f6a7507..000000000 --- a/proposal/myrmidon/src/java/org/apache/myrmidon/components/workspace/ServiceManagerAdaptor.java +++ /dev/null @@ -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 Adam Murdoch - * @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 ); - } - } -} diff --git a/proposal/myrmidon/src/java/org/apache/myrmidon/interfaces/service/AntServiceManager.java b/proposal/myrmidon/src/java/org/apache/myrmidon/interfaces/service/AntServiceManager.java deleted file mode 100644 index ea138ef75..000000000 --- a/proposal/myrmidon/src/java/org/apache/myrmidon/interfaces/service/AntServiceManager.java +++ /dev/null @@ -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 Adam Murdoch - * @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; -} diff --git a/proposal/myrmidon/src/java/org/apache/myrmidon/interfaces/service/MultiSourceServiceManager.java b/proposal/myrmidon/src/java/org/apache/myrmidon/interfaces/service/MultiSourceServiceManager.java index 5968b99b4..54d1f08f0 100644 --- a/proposal/myrmidon/src/java/org/apache/myrmidon/interfaces/service/MultiSourceServiceManager.java +++ b/proposal/myrmidon/src/java/org/apache/myrmidon/interfaces/service/MultiSourceServiceManager.java @@ -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 Adam Murdoch * @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 ) + { } } diff --git a/proposal/myrmidon/src/java/org/apache/myrmidon/interfaces/service/ServiceFactory.java b/proposal/myrmidon/src/java/org/apache/myrmidon/interfaces/service/ServiceFactory.java index 72b938fda..a704e9c71 100644 --- a/proposal/myrmidon/src/java/org/apache/myrmidon/interfaces/service/ServiceFactory.java +++ b/proposal/myrmidon/src/java/org/apache/myrmidon/interfaces/service/ServiceFactory.java @@ -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. */ diff --git a/proposal/myrmidon/src/test/org/apache/myrmidon/AbstractMyrmidonTest.java b/proposal/myrmidon/src/test/org/apache/myrmidon/AbstractMyrmidonTest.java index 7820722de..1627e7a7a 100644 --- a/proposal/myrmidon/src/test/org/apache/myrmidon/AbstractMyrmidonTest.java +++ b/proposal/myrmidon/src/test/org/apache/myrmidon/AbstractMyrmidonTest.java @@ -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 ) { diff --git a/proposal/myrmidon/src/test/org/apache/myrmidon/components/AbstractComponentTest.java b/proposal/myrmidon/src/test/org/apache/myrmidon/components/AbstractComponentTest.java index d48facb27..8c37267db 100644 --- a/proposal/myrmidon/src/test/org/apache/myrmidon/components/AbstractComponentTest.java +++ b/proposal/myrmidon/src/test/org/apache/myrmidon/components/AbstractComponentTest.java @@ -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(); ) { diff --git a/proposal/myrmidon/src/test/org/apache/myrmidon/components/configurer/DefaultConfigurerTest.java b/proposal/myrmidon/src/test/org/apache/myrmidon/components/configurer/DefaultConfigurerTest.java index 0fb598d61..074489d65 100644 --- a/proposal/myrmidon/src/test/org/apache/myrmidon/components/configurer/DefaultConfigurerTest.java +++ b/proposal/myrmidon/src/test/org/apache/myrmidon/components/configurer/DefaultConfigurerTest.java @@ -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 ); } } diff --git a/proposal/myrmidon/src/test/org/apache/myrmidon/components/service/InstantiatingServiceManagerTest.java b/proposal/myrmidon/src/test/org/apache/myrmidon/components/service/InstantiatingServiceManagerTest.java new file mode 100644 index 000000000..75dc65aa4 --- /dev/null +++ b/proposal/myrmidon/src/test/org/apache/myrmidon/components/service/InstantiatingServiceManagerTest.java @@ -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 Adam Murdoch + * @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 ); + } +} diff --git a/proposal/myrmidon/src/test/org/apache/myrmidon/components/service/LifecycleValidator.java b/proposal/myrmidon/src/test/org/apache/myrmidon/components/service/LifecycleValidator.java new file mode 100644 index 000000000..916f268cd --- /dev/null +++ b/proposal/myrmidon/src/test/org/apache/myrmidon/components/service/LifecycleValidator.java @@ -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 Adam Murdoch + * @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 ); + } +} diff --git a/proposal/myrmidon/src/test/org/apache/myrmidon/components/service/TestService.java b/proposal/myrmidon/src/test/org/apache/myrmidon/components/service/TestService.java new file mode 100644 index 000000000..4c0485a52 --- /dev/null +++ b/proposal/myrmidon/src/test/org/apache/myrmidon/components/service/TestService.java @@ -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 Adam Murdoch + * @version $Revision$ $Date$ + */ +public interface TestService +{ + void doWork(); +} diff --git a/proposal/myrmidon/src/test/org/apache/myrmidon/components/service/TestServiceFactory1.java b/proposal/myrmidon/src/test/org/apache/myrmidon/components/service/TestServiceFactory1.java new file mode 100644 index 000000000..bccf1dd98 --- /dev/null +++ b/proposal/myrmidon/src/test/org/apache/myrmidon/components/service/TestServiceFactory1.java @@ -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 Adam Murdoch + * @version $Revision$ $Date$ + */ +public class TestServiceFactory1 + implements ServiceFactory +{ + /** + * Create a service that coresponds to this factory. + */ + public Object createService() + throws AntServiceException + { + return new TestServiceImpl1(); + } +} diff --git a/proposal/myrmidon/src/test/org/apache/myrmidon/components/service/TestServiceFactory2.java b/proposal/myrmidon/src/test/org/apache/myrmidon/components/service/TestServiceFactory2.java new file mode 100644 index 000000000..8cae19da6 --- /dev/null +++ b/proposal/myrmidon/src/test/org/apache/myrmidon/components/service/TestServiceFactory2.java @@ -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 Adam Murdoch + * @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(); + } +} diff --git a/proposal/myrmidon/src/test/org/apache/myrmidon/components/service/TestServiceImpl1.java b/proposal/myrmidon/src/test/org/apache/myrmidon/components/service/TestServiceImpl1.java new file mode 100644 index 000000000..69c393ab1 --- /dev/null +++ b/proposal/myrmidon/src/test/org/apache/myrmidon/components/service/TestServiceImpl1.java @@ -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 Adam Murdoch + * @version $Revision$ $Date$ + */ +public class TestServiceImpl1 + implements TestService +{ + public void doWork() + { + } +} diff --git a/proposal/myrmidon/src/test/org/apache/myrmidon/components/service/TestServiceImpl2.java b/proposal/myrmidon/src/test/org/apache/myrmidon/components/service/TestServiceImpl2.java new file mode 100644 index 000000000..d715cf6dc --- /dev/null +++ b/proposal/myrmidon/src/test/org/apache/myrmidon/components/service/TestServiceImpl2.java @@ -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 Adam Murdoch + * @version $Revision$ $Date$ + */ +public class TestServiceImpl2 + extends LifecycleValidator + implements TestService +{ + public void doWork() + { + assertSetup(); + } +} diff --git a/proposal/myrmidon/src/testcases/org/apache/myrmidon/AbstractMyrmidonTest.java b/proposal/myrmidon/src/testcases/org/apache/myrmidon/AbstractMyrmidonTest.java index 7820722de..1627e7a7a 100644 --- a/proposal/myrmidon/src/testcases/org/apache/myrmidon/AbstractMyrmidonTest.java +++ b/proposal/myrmidon/src/testcases/org/apache/myrmidon/AbstractMyrmidonTest.java @@ -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 ) { diff --git a/proposal/myrmidon/src/testcases/org/apache/myrmidon/components/AbstractComponentTest.java b/proposal/myrmidon/src/testcases/org/apache/myrmidon/components/AbstractComponentTest.java index d48facb27..8c37267db 100644 --- a/proposal/myrmidon/src/testcases/org/apache/myrmidon/components/AbstractComponentTest.java +++ b/proposal/myrmidon/src/testcases/org/apache/myrmidon/components/AbstractComponentTest.java @@ -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(); ) { diff --git a/proposal/myrmidon/src/testcases/org/apache/myrmidon/components/configurer/DefaultConfigurerTest.java b/proposal/myrmidon/src/testcases/org/apache/myrmidon/components/configurer/DefaultConfigurerTest.java index 0fb598d61..074489d65 100644 --- a/proposal/myrmidon/src/testcases/org/apache/myrmidon/components/configurer/DefaultConfigurerTest.java +++ b/proposal/myrmidon/src/testcases/org/apache/myrmidon/components/configurer/DefaultConfigurerTest.java @@ -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 ); } } diff --git a/proposal/myrmidon/src/testcases/org/apache/myrmidon/components/service/InstantiatingServiceManagerTest.java b/proposal/myrmidon/src/testcases/org/apache/myrmidon/components/service/InstantiatingServiceManagerTest.java new file mode 100644 index 000000000..75dc65aa4 --- /dev/null +++ b/proposal/myrmidon/src/testcases/org/apache/myrmidon/components/service/InstantiatingServiceManagerTest.java @@ -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 Adam Murdoch + * @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 ); + } +} diff --git a/proposal/myrmidon/src/testcases/org/apache/myrmidon/components/service/LifecycleValidator.java b/proposal/myrmidon/src/testcases/org/apache/myrmidon/components/service/LifecycleValidator.java new file mode 100644 index 000000000..916f268cd --- /dev/null +++ b/proposal/myrmidon/src/testcases/org/apache/myrmidon/components/service/LifecycleValidator.java @@ -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 Adam Murdoch + * @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 ); + } +} diff --git a/proposal/myrmidon/src/testcases/org/apache/myrmidon/components/service/TestService.java b/proposal/myrmidon/src/testcases/org/apache/myrmidon/components/service/TestService.java new file mode 100644 index 000000000..4c0485a52 --- /dev/null +++ b/proposal/myrmidon/src/testcases/org/apache/myrmidon/components/service/TestService.java @@ -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 Adam Murdoch + * @version $Revision$ $Date$ + */ +public interface TestService +{ + void doWork(); +} diff --git a/proposal/myrmidon/src/testcases/org/apache/myrmidon/components/service/TestServiceFactory1.java b/proposal/myrmidon/src/testcases/org/apache/myrmidon/components/service/TestServiceFactory1.java new file mode 100644 index 000000000..bccf1dd98 --- /dev/null +++ b/proposal/myrmidon/src/testcases/org/apache/myrmidon/components/service/TestServiceFactory1.java @@ -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 Adam Murdoch + * @version $Revision$ $Date$ + */ +public class TestServiceFactory1 + implements ServiceFactory +{ + /** + * Create a service that coresponds to this factory. + */ + public Object createService() + throws AntServiceException + { + return new TestServiceImpl1(); + } +} diff --git a/proposal/myrmidon/src/testcases/org/apache/myrmidon/components/service/TestServiceFactory2.java b/proposal/myrmidon/src/testcases/org/apache/myrmidon/components/service/TestServiceFactory2.java new file mode 100644 index 000000000..8cae19da6 --- /dev/null +++ b/proposal/myrmidon/src/testcases/org/apache/myrmidon/components/service/TestServiceFactory2.java @@ -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 Adam Murdoch + * @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(); + } +} diff --git a/proposal/myrmidon/src/testcases/org/apache/myrmidon/components/service/TestServiceImpl1.java b/proposal/myrmidon/src/testcases/org/apache/myrmidon/components/service/TestServiceImpl1.java new file mode 100644 index 000000000..69c393ab1 --- /dev/null +++ b/proposal/myrmidon/src/testcases/org/apache/myrmidon/components/service/TestServiceImpl1.java @@ -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 Adam Murdoch + * @version $Revision$ $Date$ + */ +public class TestServiceImpl1 + implements TestService +{ + public void doWork() + { + } +} diff --git a/proposal/myrmidon/src/testcases/org/apache/myrmidon/components/service/TestServiceImpl2.java b/proposal/myrmidon/src/testcases/org/apache/myrmidon/components/service/TestServiceImpl2.java new file mode 100644 index 000000000..d715cf6dc --- /dev/null +++ b/proposal/myrmidon/src/testcases/org/apache/myrmidon/components/service/TestServiceImpl2.java @@ -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 Adam Murdoch + * @version $Revision$ $Date$ + */ +public class TestServiceImpl2 + extends LifecycleValidator + implements TestService +{ + public void doWork() + { + assertSetup(); + } +}