From 7a5c30f33c46dec3fb201dac6878a09c4cfcaf2c Mon Sep 17 00:00:00 2001 From: adammurdoch Date: Fri, 8 Feb 2002 22:20:00 +0000 Subject: [PATCH] Changes to DefaultConfigurer: * Uses the DataType role when creating instances for interface properties, rather than using the interface itself as the role. * Added ObjectConfigurer.getTypedProperty(). This replaces the implicit behaviour in DefaultObjectConfigurer.getProperty() where the typed property was returned for an unknown property name. * Typed properties are set using attributes and references, with the property's interface role shorthand name. Previously, the DefaultConfigurer would attempt to set the typed property for any unknown attribute or reference name. * Can have a set() method for a typed property, rather than an add() method. Same semantics as setX() and addX() methods. * Added a several more test cases. git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@271227 13f79535-47bb-0310-9956-ffa450edef68 --- .../configurer/DefaultConfigurer.java | 98 +++++++++--- .../configurer/DefaultObjectConfigurer.java | 87 ++++++----- .../configurer/ObjectConfigurer.java | 10 ++ .../configurer/Resources.properties | 8 +- .../components/AbstractComponentTest.java | 18 +++ .../components/configurer/ConfigTest10.java | 46 ++++++ .../configurer/DefaultConfigurerTest.java | 142 ++++++++++++++++-- .../components/configurer/MyRole1.java | 4 + .../configurer/StringToMyRole1Converter.java | 32 ++++ .../components/AbstractComponentTest.java | 18 +++ .../components/configurer/ConfigTest10.java | 46 ++++++ .../configurer/DefaultConfigurerTest.java | 142 ++++++++++++++++-- .../components/configurer/MyRole1.java | 4 + .../configurer/StringToMyRole1Converter.java | 32 ++++ 14 files changed, 603 insertions(+), 84 deletions(-) create mode 100644 proposal/myrmidon/src/test/org/apache/myrmidon/components/configurer/ConfigTest10.java create mode 100644 proposal/myrmidon/src/test/org/apache/myrmidon/components/configurer/StringToMyRole1Converter.java create mode 100644 proposal/myrmidon/src/testcases/org/apache/myrmidon/components/configurer/ConfigTest10.java create mode 100644 proposal/myrmidon/src/testcases/org/apache/myrmidon/components/configurer/StringToMyRole1Converter.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 a3775f8f6..f5f71b9e3 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 @@ -28,6 +28,8 @@ import org.apache.myrmidon.interfaces.converter.MasterConverter; import org.apache.myrmidon.interfaces.type.TypeException; import org.apache.myrmidon.interfaces.type.TypeFactory; import org.apache.myrmidon.interfaces.type.TypeManager; +import org.apache.myrmidon.interfaces.role.RoleManager; +import org.apache.myrmidon.framework.DataType; /** * Class used to configure tasks. @@ -48,6 +50,9 @@ public class DefaultConfigurer //TypeManager to use to create types in typed adders private TypeManager m_typeManager; + //RoleManager to use to map from type names -> role shorthand + private RoleManager m_roleManager; + ///Cached object configurers. This is a map from Class to the ///ObjectConfigurer for that class. private Map m_configurerCache = new HashMap(); @@ -57,6 +62,7 @@ public class DefaultConfigurer { m_converter = (MasterConverter)componentManager.lookup( MasterConverter.ROLE ); m_typeManager = (TypeManager)componentManager.lookup( TypeManager.ROLE ); + m_roleManager = (RoleManager)componentManager.lookup( RoleManager.ROLE ); } /** @@ -122,7 +128,6 @@ public class DefaultConfigurer } catch( final ConfigurationException ce ) { - ce.fillInStackTrace(); throw ce; } catch( final CascadingException ce ) @@ -151,7 +156,6 @@ public class DefaultConfigurer } catch( final ConfigurationException ce ) { - ce.fillInStackTrace(); throw ce; } catch( final CascadingException ce ) @@ -180,13 +184,12 @@ public class DefaultConfigurer } catch( final ConfigurationException ce ) { - ce.fillInStackTrace(); throw ce; } catch( final CascadingException ce ) { final String message = - REZ.getString( "bad-set-element.error", name ); + REZ.getString( "bad-set-element.error", elemName, name ); throw new ConfigurationException( message, ce ); } } @@ -269,8 +272,8 @@ public class DefaultConfigurer final String name = element.getName(); // Locate the configurer for the child element - final PropertyConfigurer childConfigurer = - state.getConfigurer().getProperty( name ); + final PropertyConfigurer childConfigurer + = getConfigurerFromName( state.getConfigurer(), name, true ); // Create & configure the child element final Object child = @@ -288,9 +291,6 @@ public class DefaultConfigurer final Context context ) throws CascadingException { - // Adjust the name - final String elementName = element.getName(); - final String name = elementName.substring( 0, elementName.length() - 4 ); // Extract the id final String id = element.getAttribute( "id" ); @@ -302,6 +302,7 @@ public class DefaultConfigurer } // Set the property + final String name = element.getName(); setReference( state, name, id, context ); } @@ -309,13 +310,17 @@ public class DefaultConfigurer * Sets a property using a reference. */ private void setReference( final ConfigurationState state, - final String name, + final String refName, final String unresolvedId, final Context context ) throws CascadingException { - // Locate the configurer for the child element - final PropertyConfigurer childConfigurer = state.getConfigurer().getProperty( name ); + // Adjust the name + final String name = refName.substring( 0, refName.length() - 4 ); + + // Locate the configurer for the property + final PropertyConfigurer childConfigurer + = getConfigurerFromName( state.getConfigurer(), name, false ); // Resolve any props in the id Object id = PropertyUtil.resolveProperty( unresolvedId, context, false ); @@ -356,14 +361,13 @@ public class DefaultConfigurer if( name.toLowerCase().endsWith( "-ref" ) ) { // A reference - final String refName = name.substring( 0, name.length() - 4 ); - setReference( state, refName, value, context ); + setReference( state, name, value, context ); } else { // Set the value - final PropertyConfigurer propConfigurer = - state.getConfigurer().getProperty( name ); + PropertyConfigurer propConfigurer + = getConfigurerFromName( state.getConfigurer(), name, false ); setValue( propConfigurer, state, value, context ); } } @@ -424,7 +428,7 @@ public class DefaultConfigurer } else if( null == child ) { - // Create an instance using the default constructor + // Create an instance if( type.isInterface() ) { child = createdTypedObject( name, type ); @@ -439,18 +443,62 @@ public class DefaultConfigurer return child; } + /** + * Determines the property configurer to use for a particular element + * or attribute. If the supplied name matches a property of the + * class being configured, that property configurer is returned. If + * the supplied name matches the role shorthand for the class' typed + * property, then the typed property configurer is used. + * + * @param configurer The configurer for the class being configured. + * @param name The attribute/element name. + */ + private PropertyConfigurer getConfigurerFromName( final ObjectConfigurer configurer, + final String name, + boolean ignoreRoleName ) + throws NoSuchPropertyException + { + // Try a named property + final NoSuchPropertyException exc; + try + { + return configurer.getProperty( name ); + } + catch( NoSuchPropertyException e ) + { + // Keep for later + exc = e; + } + + // Try a typed property + final PropertyConfigurer propertyConfigurer = configurer.getTypedProperty(); + if( ! ignoreRoleName ) + { + final String roleShorthand = m_roleManager.getNameForRole( propertyConfigurer.getType().getName() ); + if( ! name.equalsIgnoreCase(roleShorthand) ) + { + // Rethrow the original exception + throw exc; + } + } + + return propertyConfigurer; + } + /** * Utility method to create an instance of the - * specified type that satisfied supplied interface. + * specified type that satisfies supplied interface. */ private Object createdTypedObject( final String name, final Class type ) throws ConfigurationException { - final TypeFactory factory = getTypeFactory( type ); + // Attempt to create the object + final Object obj; try { - return factory.create( name ); + final TypeFactory factory = getTypeFactory( DataType.class ); + obj = factory.create( name ); } catch( final Exception e ) { @@ -460,6 +508,16 @@ public class DefaultConfigurer type.getName() ); throw new ConfigurationException( message, e ); } + + // Check the types + if( ! type.isInstance( obj ) ) + { + final String message = + REZ.getString( "mismatched-typed-object.error", name, type.getName() ); + throw new ConfigurationException( message ); + } + + return obj; } /** 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 00d836eb4..fe4ab3ddc 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 @@ -46,6 +46,11 @@ class DefaultObjectConfigurer */ private final List m_allProps = new ArrayList(); + /** + * The typed property configurer. + */ + private PropertyConfigurer m_typedPropConfigurer; + /** * Content configurer. */ @@ -67,15 +72,15 @@ class DefaultObjectConfigurer public void enableAll() throws ConfigurationException { - // TODO - get rid of creators, and either setter or adders - enableAdders(); + // TODO - get rid of creators + enableProperties(); enableContent(); } /** * Enables all creators + adders. */ - public void enableAdders() + private void enableProperties() throws ConfigurationException { final Map creators = findCreators(); @@ -119,6 +124,16 @@ class DefaultObjectConfigurer type = addMethod.getParameterTypes()[ 0 ]; } + final boolean isTypedProp = (propName.length() == 0); + if( isTypedProp && !type.isInterface() ) + { + final String message = + REZ.getString( "typed-adder-non-interface.error", + m_class.getName(), + type.getName() ); + throw new ConfigurationException( message ); + } + // Determine the max count for the property int maxCount = Integer.MAX_VALUE; if( addMethod != null && addMethod.getName().startsWith( "set" ) ) @@ -132,8 +147,15 @@ class DefaultObjectConfigurer createMethod, addMethod, maxCount ); - m_props.put( propName, configurer ); m_allProps.add( configurer ); + if( isTypedProp ) + { + m_typedPropConfigurer = configurer; + } + else + { + m_props.put( propName, configurer ); + } } } @@ -160,19 +182,7 @@ class DefaultObjectConfigurer continue; } - final boolean isTypedAdder = methodName.equals( "add" ); - - final Class paramType = method.getParameterTypes()[ 0 ]; - if( isTypedAdder && !paramType.isInterface() ) - { - final String message = - REZ.getString( "typed-adder-non-interface.error", - m_class.getName(), - paramType.getName() ); - throw new ConfigurationException( message ); - } - - // TODO - un-hard-code this + // Skip the text content method if( methodName.equals( "addContent" ) ) { continue; @@ -180,8 +190,7 @@ class DefaultObjectConfigurer // Extract property name final String propName = extractName( 3, methodName ); - - final Class type = paramType; + final Class type = method.getParameterTypes()[0]; // Add to the adders map if( adders.containsKey( propName ) ) @@ -190,15 +199,7 @@ class DefaultObjectConfigurer final Class currentType = candidate.getParameterTypes()[ 0 ]; // Ditch the string version, if any - if( isTypedAdder ) - { - // Both are string, or both are not string - final String message = - REZ.getString( "multiple-typed-adder-methods-for-element.error", - m_class.getName() ); - throw new ConfigurationException( message ); - } - else if( currentType != String.class && type == String.class ) + if( currentType != String.class && type == String.class ) { // New type is string, and current type is not. Ignore // the new method @@ -217,6 +218,7 @@ class DefaultObjectConfigurer // Else, current type is string, and new type is not, so // continue below, and overwrite the current method } + adders.put( propName, method ); } return adders; @@ -253,7 +255,7 @@ class DefaultObjectConfigurer final String message = REZ.getString( "multiple-creator-methods-for-element.error", m_class.getName(), - elemName ); + methodName ); throw new ConfigurationException( message ); } creators.put( elemName, method ); @@ -264,9 +266,13 @@ class DefaultObjectConfigurer /** * Enables content. */ - public void enableContent() + private void enableContent() throws ConfigurationException { + // TODO - should be using 'setContent', rather than 'addContent', + // to better match the call-at-most-once semantics of the other + // setter methods + // Locate any 'addContent' methods, which return void, and take // a single parameter. final Method[] methods = m_class.getMethods(); @@ -355,16 +361,25 @@ class DefaultObjectConfigurer return configurer; } - //Maybe there is a typed adder?? - configurer = (PropertyConfigurer)m_props.get( "" ); - if( null != configurer ) + // Unknown property + final String message = REZ.getString( "unknown-property.error", m_class.getName(), name ); + throw new NoSuchPropertyException( message ); + } + + /** + * Returns a configurer for the typed property of this class. + */ + public PropertyConfigurer getTypedProperty() + throws NoSuchPropertyException + { + if( null != m_typedPropConfigurer ) { - return configurer; + return m_typedPropConfigurer; } else { - // Unknown property - final String message = REZ.getString( "unknown-property.error", m_class.getName(), name ); + // No typed property + final String message = REZ.getString( "no-typed-property.error", m_class.getName() ); throw new NoSuchPropertyException( 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 de2db8a75..760374e7a 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 @@ -58,4 +58,14 @@ interface ObjectConfigurer */ PropertyConfigurer getContentConfigurer() throws NoSuchPropertyException; + + /** + * 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. + */ + PropertyConfigurer getTypedProperty() + throws NoSuchPropertyException; } 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 a26083651..e5a78ffd7 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 @@ -3,9 +3,8 @@ extra-config-for-ref.error=A reference element can only include an "id" attribut 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 adder/setter methods found in class {0} for property "{1}". -multiple-typed-adder-methods-for-element.error=Multiple typed add() methods found in class {0}. -multiple-creator-methods-for-element.error=Multiple creator 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. @@ -22,4 +21,5 @@ no-content.error=Text content is not allowed for 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 newline at end of file +create-typed-object.error=Could not create an object of type "{0}" of class {1}. +typed-property-not-supported.error=Class {0} does not have a typed property. \ No newline at end of file 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 baf96177d..378c19dde 100644 --- a/proposal/myrmidon/src/test/org/apache/myrmidon/components/AbstractComponentTest.java +++ b/proposal/myrmidon/src/test/org/apache/myrmidon/components/AbstractComponentTest.java @@ -38,6 +38,9 @@ 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.type.TypeManager; +import org.apache.myrmidon.interfaces.type.TypeException; +import org.apache.myrmidon.interfaces.type.DefaultTypeFactory; +import org.apache.myrmidon.converter.Converter; /** * A base class for tests for the default components. @@ -145,6 +148,21 @@ public abstract class AbstractComponentTest } } + /** + * Utility method to register a Converter. + */ + protected void registerConverter( final Class converterClass, + final Class sourceClass, + final Class destClass ) + throws ComponentException, TypeException + { + ConverterRegistry converterRegistry = (ConverterRegistry)getComponentManager().lookup( ConverterRegistry.ROLE ); + converterRegistry.registerConverter( converterClass.getName(), sourceClass.getName(), destClass.getName() ); + DefaultTypeFactory factory = new DefaultTypeFactory( getClass().getClassLoader() ); + factory.addNameClassMapping( converterClass.getName(), converterClass.getName() ); + getTypeManager().registerType( Converter.class, converterClass.getName(), factory ); + } + /** * Asserts that an exception contains the expected message. * diff --git a/proposal/myrmidon/src/test/org/apache/myrmidon/components/configurer/ConfigTest10.java b/proposal/myrmidon/src/test/org/apache/myrmidon/components/configurer/ConfigTest10.java new file mode 100644 index 000000000..e7a67f032 --- /dev/null +++ b/proposal/myrmidon/src/test/org/apache/myrmidon/components/configurer/ConfigTest10.java @@ -0,0 +1,46 @@ +/* + * 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.myrmidon.components.AbstractComponentTest; + +/** + * A class for testing conversion. + * + * @author Adam Murdoch + */ +public class ConfigTest10 +{ + private int m_intProp; + private Integer m_integerProp; + + public void setIntProp( int intProp ) + { + m_intProp = intProp; + } + + public void setIntegerProp( Integer integerProp ) + { + m_integerProp = integerProp; + } + + public boolean equals( Object obj ) + { + ConfigTest10 test = (ConfigTest10)obj; + if( m_intProp != test.m_intProp ) + { + return false; + } + if ( !AbstractComponentTest.equals( m_integerProp, test.m_integerProp ) ) + { + return false; + } + + return true; + } +} 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 9eaf6224e..416ada497 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 @@ -8,7 +8,7 @@ package org.apache.myrmidon.components.configurer; import java.io.File; -import junit.framework.AssertionFailedError; +import org.apache.antlib.core.StringToIntegerConverter; import org.apache.avalon.excalibur.i18n.ResourceManager; import org.apache.avalon.excalibur.i18n.Resources; import org.apache.avalon.framework.configuration.ConfigurationException; @@ -16,7 +16,9 @@ import org.apache.avalon.framework.configuration.DefaultConfiguration; import org.apache.myrmidon.api.TaskContext; import org.apache.myrmidon.components.AbstractComponentTest; 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.role.RoleManager; import org.apache.myrmidon.interfaces.type.DefaultTypeFactory; /** @@ -80,6 +82,35 @@ public class DefaultConfigurerTest assertEquals( expected, test ); } + /** + * Tests attribute conversion. + */ + public void testAttributeConvert() + throws Exception + { + // Setup test data + final DefaultConfiguration config = new DefaultConfiguration( "test", "test" ); + config.setAttribute( "int-prop", "90" ); + config.setAttribute( "integer-prop", "-401" ); + + // Register the converter + final Class converterClass = StringToIntegerConverter.class; + final Class sourceClass = String.class; + final Class destClass = Integer.class; + registerConverter( converterClass, sourceClass, destClass ); + + final ConfigTest10 test = new ConfigTest10(); + + // Configure the object + m_configurer.configure( test, config, m_context ); + + // Check result + final ConfigTest10 expected = new ConfigTest10(); + expected.setIntProp( 90 ); + expected.setIntegerProp( new Integer(-401) ); + assertEquals( expected, test ); + } + /** * Tests setting an unknown attribute. */ @@ -96,7 +127,7 @@ public class DefaultConfigurerTest try { m_configurer.configure( test, config, m_context ); - throw new AssertionFailedError(); + fail(); } catch( final ConfigurationException ce ) { @@ -155,7 +186,7 @@ public class DefaultConfigurerTest try { m_configurer.configure( test, config, m_context ); - throw new AssertionFailedError(); + fail(); } catch( final ConfigurationException ce ) { @@ -202,7 +233,7 @@ public class DefaultConfigurerTest try { m_configurer.configure( test, config, m_context ); - throw new AssertionFailedError(); + fail(); } catch( final ConfigurationException ce ) { @@ -280,6 +311,34 @@ public class DefaultConfigurerTest assertEquals( expected, test ); } + /** + * Tests that extra content is not allowed in a reference element. + */ + public void testReferenceElementExtra() + throws Exception + { + // Setup test data + final DefaultConfiguration config = new DefaultConfiguration( "test", "test" ); + final DefaultConfiguration elem = new DefaultConfiguration( "some-prop-ref", "test" ); + elem.setAttribute( "id", "prop-a" ); + elem.setAttribute( "extra-attr", "some value" ); + config.addChild( elem ); + + final ConfigTest1 test = new ConfigTest1(); + + try + { + // Configure the object + m_configurer.configure( test, config, m_context ); + fail(); + } + catch( ConfigurationException e ) + { + final String message = REZ.getString( "extra-config-for-ref.error" ); + assertSameMessage( message, e ); + } + } + /** * Tests whether an object with a non-iterface typed adder causes an * exception. @@ -326,8 +385,9 @@ public class DefaultConfigurerTest } catch( final ConfigurationException ce ) { - final String message = REZ.getString( "multiple-typed-adder-methods-for-element.error", - ConfigTest5.class.getName() ); + final String message = REZ.getString( "multiple-adder-methods-for-element.error", + ConfigTest5.class.getName(), + ""); assertSameMessage( message, ce ); } } @@ -349,8 +409,8 @@ public class DefaultConfigurerTest final DefaultTypeFactory factory = new DefaultTypeFactory( loader ); factory.addNameClassMapping( "my-type1", MyType1.class.getName() ); factory.addNameClassMapping( "my-type2", MyType2.class.getName() ); - getTypeManager().registerType( MyRole1.class, "my-type1", factory ); - getTypeManager().registerType( MyRole1.class, "my-type2", factory ); + getTypeManager().registerType( DataType.class, "my-type1", factory ); + getTypeManager().registerType( DataType.class, "my-type2", factory ); final ConfigTest6 test = new ConfigTest6(); @@ -363,6 +423,32 @@ public class DefaultConfigurerTest assertEquals( expected, test ); } + /** + * Tests to see if typed adder can be used via an attribute. + */ + public void testTypedAdderAttribute() + throws Exception + { + // Setup test data + final DefaultConfiguration config = new DefaultConfiguration( "test", "test" ); + config.setAttribute( "my-role1", "some value" ); + + // Set up the converter and role + RoleManager roleMgr = (RoleManager)getComponentManager().lookup( RoleManager.ROLE ); + roleMgr.addNameRoleMapping( "my-role1", MyRole1.ROLE ); + registerConverter( StringToMyRole1Converter.class, String.class, MyRole1.class ); + + final ConfigTest6 test = new ConfigTest6(); + + // Configure the object + m_configurer.configure( test, config, m_context ); + + // Check result + final ConfigTest6 expected = new ConfigTest6(); + expected.add( new MyType1() ); + assertEquals( expected, test ); + } + /** * Tests to see if typed adder works, with Configuration type. */ @@ -388,7 +474,7 @@ public class DefaultConfigurerTest } /** - * Tests to see if typed adder works, with Configuration objects. + * Tests to see if adder works, with Configuration objects. */ public void testConfigAdder() throws Exception @@ -470,7 +556,7 @@ public class DefaultConfigurerTest try { m_configurer.configure( test, config, m_context ); - throw new AssertionFailedError(); + fail(); } catch( ConfigurationException e ) { @@ -498,7 +584,7 @@ public class DefaultConfigurerTest try { m_configurer.configure( test, config, m_context ); - throw new AssertionFailedError(); + fail(); } catch( ConfigurationException e ) { @@ -510,6 +596,38 @@ public class DefaultConfigurerTest } } + /** + * Tests using a reference with a typed adder. Tests using an attribute + * and a nested element. + */ + public void testTypedAdderReference() + throws Exception + { + // Setup test data + final DefaultConfiguration config = new DefaultConfiguration( "test", "test" ); + config.setAttribute( "my-role1-ref", "id" ); + final DefaultConfiguration child = new DefaultConfiguration( "my-role1-ref", "test" ); + child.setAttribute( "id", "id2" ); + config.addChild( child ); + + // Add role mapping, and add to reference to context + final RoleManager roleMgr = (RoleManager)getComponentManager().lookup( RoleManager.ROLE ); + roleMgr.addNameRoleMapping( "my-role1", MyRole1.class.getName() ); + m_context.setProperty( "id", new MyType1() ); + m_context.setProperty( "id2", new MyType2() ); + + final ConfigTest6 test = new ConfigTest6(); + + // Configure the object + m_configurer.configure( test, config, m_context ); + + // Compare against expected value + final ConfigTest6 expected = new ConfigTest6(); + expected.add( new MyType1() ); + expected.add( new MyType2() ); + assertEquals( expected, test ); + } + /** * Tests reporting of nested errors. */ @@ -527,7 +645,7 @@ public class DefaultConfigurerTest { // Configure the object m_configurer.configure( test, config, m_context ); - throw new AssertionFailedError(); + fail(); } catch( ConfigurationException e ) { diff --git a/proposal/myrmidon/src/test/org/apache/myrmidon/components/configurer/MyRole1.java b/proposal/myrmidon/src/test/org/apache/myrmidon/components/configurer/MyRole1.java index 4e524204d..f62943b3c 100644 --- a/proposal/myrmidon/src/test/org/apache/myrmidon/components/configurer/MyRole1.java +++ b/proposal/myrmidon/src/test/org/apache/myrmidon/components/configurer/MyRole1.java @@ -7,6 +7,8 @@ */ package org.apache.myrmidon.components.configurer; +import org.apache.myrmidon.framework.DataType; + /** * A basic interface to test configurer. * @@ -14,5 +16,7 @@ package org.apache.myrmidon.components.configurer; * @version $Revision$ $Date$ */ public interface MyRole1 + extends DataType { + String ROLE = MyRole1.class.getName(); } diff --git a/proposal/myrmidon/src/test/org/apache/myrmidon/components/configurer/StringToMyRole1Converter.java b/proposal/myrmidon/src/test/org/apache/myrmidon/components/configurer/StringToMyRole1Converter.java new file mode 100644 index 000000000..7d2dfd641 --- /dev/null +++ b/proposal/myrmidon/src/test/org/apache/myrmidon/components/configurer/StringToMyRole1Converter.java @@ -0,0 +1,32 @@ +/* + * 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.myrmidon.converter.AbstractConverter; +import org.apache.myrmidon.converter.ConverterException; +import org.apache.avalon.framework.context.Context; + +/** + * Converts from a string to a {@link MyRole1} implementation. + * + * @author Adam Murdoch + */ +public class StringToMyRole1Converter + extends AbstractConverter +{ + public StringToMyRole1Converter() + { + super( String.class, MyRole1.class ); + } + + protected Object convert( Object original, Context context ) + throws ConverterException + { + return new MyType1(); + } +} 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 baf96177d..378c19dde 100644 --- a/proposal/myrmidon/src/testcases/org/apache/myrmidon/components/AbstractComponentTest.java +++ b/proposal/myrmidon/src/testcases/org/apache/myrmidon/components/AbstractComponentTest.java @@ -38,6 +38,9 @@ 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.type.TypeManager; +import org.apache.myrmidon.interfaces.type.TypeException; +import org.apache.myrmidon.interfaces.type.DefaultTypeFactory; +import org.apache.myrmidon.converter.Converter; /** * A base class for tests for the default components. @@ -145,6 +148,21 @@ public abstract class AbstractComponentTest } } + /** + * Utility method to register a Converter. + */ + protected void registerConverter( final Class converterClass, + final Class sourceClass, + final Class destClass ) + throws ComponentException, TypeException + { + ConverterRegistry converterRegistry = (ConverterRegistry)getComponentManager().lookup( ConverterRegistry.ROLE ); + converterRegistry.registerConverter( converterClass.getName(), sourceClass.getName(), destClass.getName() ); + DefaultTypeFactory factory = new DefaultTypeFactory( getClass().getClassLoader() ); + factory.addNameClassMapping( converterClass.getName(), converterClass.getName() ); + getTypeManager().registerType( Converter.class, converterClass.getName(), factory ); + } + /** * Asserts that an exception contains the expected message. * diff --git a/proposal/myrmidon/src/testcases/org/apache/myrmidon/components/configurer/ConfigTest10.java b/proposal/myrmidon/src/testcases/org/apache/myrmidon/components/configurer/ConfigTest10.java new file mode 100644 index 000000000..e7a67f032 --- /dev/null +++ b/proposal/myrmidon/src/testcases/org/apache/myrmidon/components/configurer/ConfigTest10.java @@ -0,0 +1,46 @@ +/* + * 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.myrmidon.components.AbstractComponentTest; + +/** + * A class for testing conversion. + * + * @author Adam Murdoch + */ +public class ConfigTest10 +{ + private int m_intProp; + private Integer m_integerProp; + + public void setIntProp( int intProp ) + { + m_intProp = intProp; + } + + public void setIntegerProp( Integer integerProp ) + { + m_integerProp = integerProp; + } + + public boolean equals( Object obj ) + { + ConfigTest10 test = (ConfigTest10)obj; + if( m_intProp != test.m_intProp ) + { + return false; + } + if ( !AbstractComponentTest.equals( m_integerProp, test.m_integerProp ) ) + { + return false; + } + + return true; + } +} 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 9eaf6224e..416ada497 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 @@ -8,7 +8,7 @@ package org.apache.myrmidon.components.configurer; import java.io.File; -import junit.framework.AssertionFailedError; +import org.apache.antlib.core.StringToIntegerConverter; import org.apache.avalon.excalibur.i18n.ResourceManager; import org.apache.avalon.excalibur.i18n.Resources; import org.apache.avalon.framework.configuration.ConfigurationException; @@ -16,7 +16,9 @@ import org.apache.avalon.framework.configuration.DefaultConfiguration; import org.apache.myrmidon.api.TaskContext; import org.apache.myrmidon.components.AbstractComponentTest; 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.role.RoleManager; import org.apache.myrmidon.interfaces.type.DefaultTypeFactory; /** @@ -80,6 +82,35 @@ public class DefaultConfigurerTest assertEquals( expected, test ); } + /** + * Tests attribute conversion. + */ + public void testAttributeConvert() + throws Exception + { + // Setup test data + final DefaultConfiguration config = new DefaultConfiguration( "test", "test" ); + config.setAttribute( "int-prop", "90" ); + config.setAttribute( "integer-prop", "-401" ); + + // Register the converter + final Class converterClass = StringToIntegerConverter.class; + final Class sourceClass = String.class; + final Class destClass = Integer.class; + registerConverter( converterClass, sourceClass, destClass ); + + final ConfigTest10 test = new ConfigTest10(); + + // Configure the object + m_configurer.configure( test, config, m_context ); + + // Check result + final ConfigTest10 expected = new ConfigTest10(); + expected.setIntProp( 90 ); + expected.setIntegerProp( new Integer(-401) ); + assertEquals( expected, test ); + } + /** * Tests setting an unknown attribute. */ @@ -96,7 +127,7 @@ public class DefaultConfigurerTest try { m_configurer.configure( test, config, m_context ); - throw new AssertionFailedError(); + fail(); } catch( final ConfigurationException ce ) { @@ -155,7 +186,7 @@ public class DefaultConfigurerTest try { m_configurer.configure( test, config, m_context ); - throw new AssertionFailedError(); + fail(); } catch( final ConfigurationException ce ) { @@ -202,7 +233,7 @@ public class DefaultConfigurerTest try { m_configurer.configure( test, config, m_context ); - throw new AssertionFailedError(); + fail(); } catch( final ConfigurationException ce ) { @@ -280,6 +311,34 @@ public class DefaultConfigurerTest assertEquals( expected, test ); } + /** + * Tests that extra content is not allowed in a reference element. + */ + public void testReferenceElementExtra() + throws Exception + { + // Setup test data + final DefaultConfiguration config = new DefaultConfiguration( "test", "test" ); + final DefaultConfiguration elem = new DefaultConfiguration( "some-prop-ref", "test" ); + elem.setAttribute( "id", "prop-a" ); + elem.setAttribute( "extra-attr", "some value" ); + config.addChild( elem ); + + final ConfigTest1 test = new ConfigTest1(); + + try + { + // Configure the object + m_configurer.configure( test, config, m_context ); + fail(); + } + catch( ConfigurationException e ) + { + final String message = REZ.getString( "extra-config-for-ref.error" ); + assertSameMessage( message, e ); + } + } + /** * Tests whether an object with a non-iterface typed adder causes an * exception. @@ -326,8 +385,9 @@ public class DefaultConfigurerTest } catch( final ConfigurationException ce ) { - final String message = REZ.getString( "multiple-typed-adder-methods-for-element.error", - ConfigTest5.class.getName() ); + final String message = REZ.getString( "multiple-adder-methods-for-element.error", + ConfigTest5.class.getName(), + ""); assertSameMessage( message, ce ); } } @@ -349,8 +409,8 @@ public class DefaultConfigurerTest final DefaultTypeFactory factory = new DefaultTypeFactory( loader ); factory.addNameClassMapping( "my-type1", MyType1.class.getName() ); factory.addNameClassMapping( "my-type2", MyType2.class.getName() ); - getTypeManager().registerType( MyRole1.class, "my-type1", factory ); - getTypeManager().registerType( MyRole1.class, "my-type2", factory ); + getTypeManager().registerType( DataType.class, "my-type1", factory ); + getTypeManager().registerType( DataType.class, "my-type2", factory ); final ConfigTest6 test = new ConfigTest6(); @@ -363,6 +423,32 @@ public class DefaultConfigurerTest assertEquals( expected, test ); } + /** + * Tests to see if typed adder can be used via an attribute. + */ + public void testTypedAdderAttribute() + throws Exception + { + // Setup test data + final DefaultConfiguration config = new DefaultConfiguration( "test", "test" ); + config.setAttribute( "my-role1", "some value" ); + + // Set up the converter and role + RoleManager roleMgr = (RoleManager)getComponentManager().lookup( RoleManager.ROLE ); + roleMgr.addNameRoleMapping( "my-role1", MyRole1.ROLE ); + registerConverter( StringToMyRole1Converter.class, String.class, MyRole1.class ); + + final ConfigTest6 test = new ConfigTest6(); + + // Configure the object + m_configurer.configure( test, config, m_context ); + + // Check result + final ConfigTest6 expected = new ConfigTest6(); + expected.add( new MyType1() ); + assertEquals( expected, test ); + } + /** * Tests to see if typed adder works, with Configuration type. */ @@ -388,7 +474,7 @@ public class DefaultConfigurerTest } /** - * Tests to see if typed adder works, with Configuration objects. + * Tests to see if adder works, with Configuration objects. */ public void testConfigAdder() throws Exception @@ -470,7 +556,7 @@ public class DefaultConfigurerTest try { m_configurer.configure( test, config, m_context ); - throw new AssertionFailedError(); + fail(); } catch( ConfigurationException e ) { @@ -498,7 +584,7 @@ public class DefaultConfigurerTest try { m_configurer.configure( test, config, m_context ); - throw new AssertionFailedError(); + fail(); } catch( ConfigurationException e ) { @@ -510,6 +596,38 @@ public class DefaultConfigurerTest } } + /** + * Tests using a reference with a typed adder. Tests using an attribute + * and a nested element. + */ + public void testTypedAdderReference() + throws Exception + { + // Setup test data + final DefaultConfiguration config = new DefaultConfiguration( "test", "test" ); + config.setAttribute( "my-role1-ref", "id" ); + final DefaultConfiguration child = new DefaultConfiguration( "my-role1-ref", "test" ); + child.setAttribute( "id", "id2" ); + config.addChild( child ); + + // Add role mapping, and add to reference to context + final RoleManager roleMgr = (RoleManager)getComponentManager().lookup( RoleManager.ROLE ); + roleMgr.addNameRoleMapping( "my-role1", MyRole1.class.getName() ); + m_context.setProperty( "id", new MyType1() ); + m_context.setProperty( "id2", new MyType2() ); + + final ConfigTest6 test = new ConfigTest6(); + + // Configure the object + m_configurer.configure( test, config, m_context ); + + // Compare against expected value + final ConfigTest6 expected = new ConfigTest6(); + expected.add( new MyType1() ); + expected.add( new MyType2() ); + assertEquals( expected, test ); + } + /** * Tests reporting of nested errors. */ @@ -527,7 +645,7 @@ public class DefaultConfigurerTest { // Configure the object m_configurer.configure( test, config, m_context ); - throw new AssertionFailedError(); + fail(); } catch( ConfigurationException e ) { diff --git a/proposal/myrmidon/src/testcases/org/apache/myrmidon/components/configurer/MyRole1.java b/proposal/myrmidon/src/testcases/org/apache/myrmidon/components/configurer/MyRole1.java index 4e524204d..f62943b3c 100644 --- a/proposal/myrmidon/src/testcases/org/apache/myrmidon/components/configurer/MyRole1.java +++ b/proposal/myrmidon/src/testcases/org/apache/myrmidon/components/configurer/MyRole1.java @@ -7,6 +7,8 @@ */ package org.apache.myrmidon.components.configurer; +import org.apache.myrmidon.framework.DataType; + /** * A basic interface to test configurer. * @@ -14,5 +16,7 @@ package org.apache.myrmidon.components.configurer; * @version $Revision$ $Date$ */ public interface MyRole1 + extends DataType { + String ROLE = MyRole1.class.getName(); } diff --git a/proposal/myrmidon/src/testcases/org/apache/myrmidon/components/configurer/StringToMyRole1Converter.java b/proposal/myrmidon/src/testcases/org/apache/myrmidon/components/configurer/StringToMyRole1Converter.java new file mode 100644 index 000000000..7d2dfd641 --- /dev/null +++ b/proposal/myrmidon/src/testcases/org/apache/myrmidon/components/configurer/StringToMyRole1Converter.java @@ -0,0 +1,32 @@ +/* + * 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.myrmidon.converter.AbstractConverter; +import org.apache.myrmidon.converter.ConverterException; +import org.apache.avalon.framework.context.Context; + +/** + * Converts from a string to a {@link MyRole1} implementation. + * + * @author Adam Murdoch + */ +public class StringToMyRole1Converter + extends AbstractConverter +{ + public StringToMyRole1Converter() + { + super( String.class, MyRole1.class ); + } + + protected Object convert( Object original, Context context ) + throws ConverterException + { + return new MyType1(); + } +}