git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@271752 13f79535-47bb-0310-9956-ffa450edef68master
| @@ -39,7 +39,7 @@ public class Property | |||
| /** | |||
| * Sets the property value from a nested element. | |||
| */ | |||
| public void set( final DataType value ) | |||
| public void add( final DataType value ) | |||
| throws TaskException | |||
| { | |||
| setValue( value ); | |||
| @@ -21,8 +21,8 @@ class ConfigurationState | |||
| private final Object m_object; | |||
| public ConfigurationState( final ObjectConfigurer configurer, | |||
| final Object object, | |||
| final int propertyCount ) | |||
| final Object object, | |||
| final int propertyCount ) | |||
| { | |||
| m_configurer = configurer; | |||
| m_object = object; | |||
| @@ -140,7 +140,7 @@ public class DefaultConfigurer | |||
| { | |||
| final String message = | |||
| REZ.getString( "no-such-attribute.error", elemName, name ); | |||
| throw new ReportableConfigurationException( message ); | |||
| throw new ReportableConfigurationException( message ); | |||
| } | |||
| catch( final Exception ce ) | |||
| { | |||
| @@ -299,7 +299,7 @@ public class DefaultConfigurer | |||
| // Locate the configurer for the child element | |||
| final PropertyConfigurer childConfigurer = | |||
| getConfigurerFromName( state.getConfigurer(), name, true ); | |||
| getConfigurerFromName( state.getConfigurer(), name, true, true ); | |||
| // Create & configure the child element | |||
| final Object child = | |||
| @@ -317,7 +317,6 @@ public class DefaultConfigurer | |||
| final TaskContext context ) | |||
| throws Exception | |||
| { | |||
| // Extract the id | |||
| final String id = element.getAttribute( "id" ); | |||
| if( 1 != element.getAttributeNames().length || | |||
| @@ -329,7 +328,7 @@ public class DefaultConfigurer | |||
| // Set the property | |||
| final String name = element.getName(); | |||
| setReference( state, name, id, context ); | |||
| setReference( state, name, id, context, true ); | |||
| } | |||
| /** | |||
| @@ -338,29 +337,30 @@ public class DefaultConfigurer | |||
| private void setReference( final ConfigurationState state, | |||
| final String refName, | |||
| final String unresolvedId, | |||
| final TaskContext context ) | |||
| final TaskContext context, | |||
| final boolean isAdder ) | |||
| throws Exception | |||
| { | |||
| // 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 ); | |||
| final PropertyConfigurer configurer = | |||
| getConfigurerFromName( state.getConfigurer(), name, false, isAdder ); | |||
| // Resolve any props in the id | |||
| String id = context.resolveValue( unresolvedId ).toString(); | |||
| // Locate the referenced object | |||
| Object ref = context.getProperty( id ); | |||
| if( ref == null ) | |||
| if( null == ref ) | |||
| { | |||
| final String message = REZ.getString( "unknown-reference.error", id ); | |||
| throw new ConfigurationException( message ); | |||
| } | |||
| // Convert the object, if necessary | |||
| final Class type = childConfigurer.getType(); | |||
| final Class type = configurer.getType(); | |||
| if( !type.isInstance( ref ) ) | |||
| { | |||
| try | |||
| @@ -375,7 +375,7 @@ public class DefaultConfigurer | |||
| } | |||
| // Set the child element | |||
| childConfigurer.addValue( state, ref ); | |||
| configurer.addValue( state, ref ); | |||
| } | |||
| /** | |||
| @@ -390,13 +390,12 @@ public class DefaultConfigurer | |||
| if( name.toLowerCase().endsWith( "-ref" ) ) | |||
| { | |||
| // A reference | |||
| setReference( state, name, value, context ); | |||
| setReference( state, name, value, context, false ); | |||
| } | |||
| else | |||
| { | |||
| // Set the value | |||
| PropertyConfigurer propConfigurer | |||
| = getConfigurerFromName( state.getConfigurer(), name, false ); | |||
| PropertyConfigurer propConfigurer = getConfigurerFromName( state.getConfigurer(), name, false, false ); | |||
| setValue( propConfigurer, state, value, context ); | |||
| } | |||
| } | |||
| @@ -495,35 +494,46 @@ public class DefaultConfigurer | |||
| */ | |||
| private PropertyConfigurer getConfigurerFromName( final ObjectConfigurer configurer, | |||
| final String name, | |||
| boolean ignoreRoleName ) | |||
| boolean ignoreRoleName, | |||
| final boolean isAdder ) | |||
| throws Exception | |||
| { | |||
| // Try a named property | |||
| PropertyConfigurer propertyConfigurer = configurer.getProperty( name ); | |||
| if( propertyConfigurer != null ) | |||
| if( !isAdder ) | |||
| { | |||
| return propertyConfigurer; | |||
| PropertyConfigurer propertyConfigurer = configurer.getSetter( name ); | |||
| if( propertyConfigurer != null ) | |||
| { | |||
| return propertyConfigurer; | |||
| } | |||
| } | |||
| // Try a typed property | |||
| propertyConfigurer = configurer.getTypedProperty(); | |||
| if( propertyConfigurer != null ) | |||
| else | |||
| { | |||
| if( ignoreRoleName ) | |||
| PropertyConfigurer propertyConfigurer = configurer.getAdder( name ); | |||
| if( propertyConfigurer != null ) | |||
| { | |||
| return propertyConfigurer; | |||
| } | |||
| else | |||
| // Try a typed property | |||
| propertyConfigurer = configurer.getTypedProperty(); | |||
| if( propertyConfigurer != null ) | |||
| { | |||
| // Check the role name | |||
| final RoleInfo roleInfo = m_roleManager.getRoleByType( propertyConfigurer.getType() ); | |||
| if( roleInfo != null && name.equalsIgnoreCase( roleInfo.getShorthand() ) ) | |||
| if( ignoreRoleName ) | |||
| { | |||
| return propertyConfigurer; | |||
| } | |||
| else | |||
| { | |||
| // Check the role name | |||
| final RoleInfo roleInfo = m_roleManager.getRoleByType( propertyConfigurer.getType() ); | |||
| if( roleInfo != null && name.equalsIgnoreCase( roleInfo.getShorthand() ) ) | |||
| { | |||
| return propertyConfigurer; | |||
| } | |||
| } | |||
| } | |||
| } | |||
| // Unknown prop | |||
| throw new NoSuchPropertyException(); | |||
| } | |||
| @@ -35,19 +35,19 @@ class DefaultObjectConfigurer | |||
| private final Class m_class; | |||
| /** | |||
| * Map from lowercase property name -> PropertyConfigurer. | |||
| * All property configurers. (For XML elements) | |||
| */ | |||
| private final Map m_props = new HashMap(); | |||
| private final HashMap m_adders = new HashMap(); | |||
| /** | |||
| * All property configurers. | |||
| * Setter property configurers. (For XML attributes) | |||
| */ | |||
| private final List m_allProps = new ArrayList(); | |||
| private final HashMap m_setters = new HashMap(); | |||
| /** | |||
| * The typed property configurer. | |||
| */ | |||
| private PropertyConfigurer m_typedPropConfigurer; | |||
| private PropertyConfigurer m_typedPropertyConfigurer; | |||
| /** | |||
| * Content configurer. | |||
| @@ -80,19 +80,20 @@ class DefaultObjectConfigurer | |||
| private void enableProperties() | |||
| throws ConfigurationException | |||
| { | |||
| final Map adders = findAdders(); | |||
| final Map configurers = findPropertyConfigurers(); | |||
| // Add the elements | |||
| final Iterator iterator = adders.keySet().iterator(); | |||
| final Iterator iterator = configurers.keySet().iterator(); | |||
| while( iterator.hasNext() ) | |||
| { | |||
| final String propName = (String)iterator.next(); | |||
| final Method addMethod = (Method)adders.get( propName ); | |||
| final String name = (String)iterator.next(); | |||
| final Method method = (Method)configurers.get( name ); | |||
| final boolean isSetter = method.getName().startsWith( "set" ); | |||
| // Determine and check the return type | |||
| final Class type = addMethod.getParameterTypes()[ 0 ]; | |||
| final boolean isTypedProp = ( propName.length() == 0 ); | |||
| final Class type = method.getParameterTypes()[ 0 ]; | |||
| final boolean isTypedProp = ( name.length() == 0 ); | |||
| if( isTypedProp && !type.isInterface() ) | |||
| { | |||
| final String message = | |||
| @@ -101,27 +102,48 @@ class DefaultObjectConfigurer | |||
| 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" ) ) | |||
| else if( isTypedProp && isSetter ) | |||
| { | |||
| final String message = | |||
| REZ.getString( "typed-setter-not-allowed.error", | |||
| m_class.getName(), | |||
| type.getName() ); | |||
| throw new ConfigurationException( message ); | |||
| } | |||
| else if( isTypedProp && null != m_typedPropertyConfigurer ) | |||
| { | |||
| maxCount = 1; | |||
| final String message = | |||
| REZ.getString( "typed-adder-duplicates.error", | |||
| m_class.getName(), | |||
| type.getName() ); | |||
| throw new ConfigurationException( message ); | |||
| } | |||
| final DefaultPropertyConfigurer configurer = | |||
| new DefaultPropertyConfigurer( m_allProps.size(), | |||
| type, | |||
| addMethod, | |||
| maxCount ); | |||
| m_allProps.add( configurer ); | |||
| if( isTypedProp ) | |||
| // Determine the max count for the property | |||
| if( isSetter ) | |||
| { | |||
| m_typedPropConfigurer = configurer; | |||
| final DefaultPropertyConfigurer setter = | |||
| new DefaultPropertyConfigurer( getPropertyCount(), | |||
| type, | |||
| method, | |||
| 1 ); | |||
| m_setters.put( name, setter ); | |||
| } | |||
| else | |||
| { | |||
| m_props.put( propName, configurer ); | |||
| final DefaultPropertyConfigurer configurer = | |||
| new DefaultPropertyConfigurer( getPropertyCount(), | |||
| type, | |||
| method, | |||
| Integer.MAX_VALUE ); | |||
| if( isTypedProp ) | |||
| { | |||
| m_typedPropertyConfigurer = configurer; | |||
| } | |||
| else | |||
| { | |||
| m_adders.put( name, configurer ); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| @@ -130,7 +152,7 @@ class DefaultObjectConfigurer | |||
| * Locate all 'add' and 'set' methods which return void, and take a | |||
| * single parameter. | |||
| */ | |||
| private Map findAdders() | |||
| private Map findPropertyConfigurers() | |||
| throws ConfigurationException | |||
| { | |||
| final Map adders = new HashMap(); | |||
| @@ -163,6 +185,12 @@ class DefaultObjectConfigurer | |||
| if( adders.containsKey( propName ) ) | |||
| { | |||
| final Method candidate = (Method)adders.get( propName ); | |||
| final String operation = methodName.substring( 0, 3 ); | |||
| if( !candidate.getName().startsWith( operation ) ) | |||
| { | |||
| continue; | |||
| } | |||
| final Class currentType = candidate.getParameterTypes()[ 0 ]; | |||
| // Ditch the string version, if any | |||
| @@ -226,14 +254,20 @@ class DefaultObjectConfigurer | |||
| final Class type = method.getParameterTypes()[ 0 ]; | |||
| m_contentConfigurer = | |||
| new DefaultPropertyConfigurer( m_allProps.size(), | |||
| new DefaultPropertyConfigurer( getPropertyCount(), | |||
| type, | |||
| method, | |||
| 1 ); | |||
| m_allProps.add( m_contentConfigurer ); | |||
| } | |||
| } | |||
| private int getPropertyCount() | |||
| { | |||
| final int typedSize = ( null != m_typedPropertyConfigurer ) ? 1 : 0; | |||
| final int contentSize = ( null != m_contentConfigurer ) ? 1 : 0; | |||
| return m_adders.size() + m_setters.size() + contentSize + typedSize; | |||
| } | |||
| /** | |||
| * Locates the configurer for a particular class. | |||
| */ | |||
| @@ -251,7 +285,7 @@ class DefaultObjectConfigurer | |||
| public ConfigurationState startConfiguration( Object object ) | |||
| throws ConfigurationException | |||
| { | |||
| return new ConfigurationState( this, object, m_allProps.size() ); | |||
| return new ConfigurationState( this, object, getPropertyCount() ); | |||
| } | |||
| /** | |||
| @@ -269,9 +303,17 @@ class DefaultObjectConfigurer | |||
| /** | |||
| * Returns a configurer for an element of this class. | |||
| */ | |||
| public PropertyConfigurer getProperty( final String name ) | |||
| public PropertyConfigurer getAdder( final String name ) | |||
| { | |||
| return (PropertyConfigurer)m_adders.get( name ); | |||
| } | |||
| /** | |||
| * Returns a configurer for an element of this class. | |||
| */ | |||
| public PropertyConfigurer getSetter( final String name ) | |||
| { | |||
| return (PropertyConfigurer)m_props.get( name ); | |||
| return (PropertyConfigurer)m_setters.get( name ); | |||
| } | |||
| /** | |||
| @@ -279,7 +321,7 @@ class DefaultObjectConfigurer | |||
| */ | |||
| public PropertyConfigurer getTypedProperty() | |||
| { | |||
| return m_typedPropConfigurer; | |||
| return m_typedPropertyConfigurer; | |||
| } | |||
| /** | |||
| @@ -26,17 +26,17 @@ class DefaultPropertyConfigurer | |||
| private final static Resources REZ = | |||
| ResourceManager.getPackageResources( DefaultPropertyConfigurer.class ); | |||
| private final int m_propIndex; | |||
| private final int m_propertyIndex; | |||
| private final Class m_type; | |||
| private final Method m_addMethod; | |||
| private final Method m_method; | |||
| private final int m_maxCount; | |||
| public DefaultPropertyConfigurer( final int propIndex, | |||
| final Class type, | |||
| final Method addMethod, | |||
| final Method method, | |||
| final int maxCount ) | |||
| { | |||
| m_propIndex = propIndex; | |||
| m_propertyIndex = propIndex; | |||
| if( type.isPrimitive() ) | |||
| { | |||
| m_type = getComplexTypeFor( type ); | |||
| @@ -45,8 +45,13 @@ class DefaultPropertyConfigurer | |||
| { | |||
| m_type = type; | |||
| } | |||
| m_addMethod = addMethod; | |||
| m_method = method; | |||
| m_maxCount = maxCount; | |||
| if( null == m_method ) | |||
| { | |||
| throw new NullPointerException( "method" ); | |||
| } | |||
| } | |||
| /** | |||
| @@ -64,22 +69,18 @@ class DefaultPropertyConfigurer | |||
| throws ConfigurationException | |||
| { | |||
| final ConfigurationState defState = (ConfigurationState)state; | |||
| // Check the property count | |||
| if( defState.getPropertyCount( m_propIndex ) >= m_maxCount ) | |||
| if( defState.getPropertyCount( m_propertyIndex ) >= m_maxCount ) | |||
| { | |||
| final String message = REZ.getString( "too-many-values.error" ); | |||
| throw new ConfigurationException( message ); | |||
| } | |||
| defState.incPropertyCount( m_propIndex ); | |||
| defState.incPropertyCount( m_propertyIndex ); | |||
| try | |||
| { | |||
| // Add the value | |||
| if( null != m_addMethod ) | |||
| { | |||
| m_addMethod.invoke( defState.getObject(), new Object[]{value} ); | |||
| } | |||
| m_method.invoke( defState.getObject(), new Object[]{value} ); | |||
| } | |||
| catch( final InvocationTargetException ite ) | |||
| { | |||
| @@ -40,13 +40,22 @@ interface ObjectConfigurer | |||
| throws ConfigurationException; | |||
| /** | |||
| * Returns a configurer for a property of this class. | |||
| * Returns a configurer for a atribute property of this class. | |||
| * | |||
| * @param name The element name. Property names are case-insensitive. | |||
| * @param name The attribute name. | |||
| * @return A configurer for the property, or null if the property is not | |||
| * valid for this class. | |||
| */ | |||
| PropertyConfigurer getProperty( String name ); | |||
| PropertyConfigurer getSetter( String name ); | |||
| /** | |||
| * Returns a configurer for a element property of this class. | |||
| * | |||
| * @param name The element name. | |||
| * @return A configurer for the property, or null if the property is not | |||
| * valid for this class. | |||
| */ | |||
| PropertyConfigurer getAdder( String name ); | |||
| /** | |||
| * Returns a configurer for the text content of this class. | |||
| @@ -17,3 +17,5 @@ typed-adder-non-interface.error=The typed adder for class "{0}" must have a sing | |||
| create-typed-object.error=Could not create an object of type "{0}" of class {1}. | |||
| unknown-reference.error=Could not find referenced object "{0}". | |||
| bad-configure-element.error=Could not configure element <{0}>. | |||
| typed-setter-not-allowed.error=Not allowed to have "typed" setters as found in class {0}. | |||
| typed-adder-duplicates.error=Multiple typed adders found in class {0}. | |||