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. | * Sets the property value from a nested element. | ||||
*/ | */ | ||||
public void set( final DataType value ) | |||||
public void add( final DataType value ) | |||||
throws TaskException | throws TaskException | ||||
{ | { | ||||
setValue( value ); | setValue( value ); | ||||
@@ -21,8 +21,8 @@ class ConfigurationState | |||||
private final Object m_object; | private final Object m_object; | ||||
public ConfigurationState( final ObjectConfigurer configurer, | public ConfigurationState( final ObjectConfigurer configurer, | ||||
final Object object, | |||||
final int propertyCount ) | |||||
final Object object, | |||||
final int propertyCount ) | |||||
{ | { | ||||
m_configurer = configurer; | m_configurer = configurer; | ||||
m_object = object; | m_object = object; | ||||
@@ -140,7 +140,7 @@ public class DefaultConfigurer | |||||
{ | { | ||||
final String message = | final String message = | ||||
REZ.getString( "no-such-attribute.error", elemName, name ); | REZ.getString( "no-such-attribute.error", elemName, name ); | ||||
throw new ReportableConfigurationException( message ); | |||||
throw new ReportableConfigurationException( message ); | |||||
} | } | ||||
catch( final Exception ce ) | catch( final Exception ce ) | ||||
{ | { | ||||
@@ -299,7 +299,7 @@ public class DefaultConfigurer | |||||
// Locate the configurer for the child element | // Locate the configurer for the child element | ||||
final PropertyConfigurer childConfigurer = | final PropertyConfigurer childConfigurer = | ||||
getConfigurerFromName( state.getConfigurer(), name, true ); | |||||
getConfigurerFromName( state.getConfigurer(), name, true, true ); | |||||
// Create & configure the child element | // Create & configure the child element | ||||
final Object child = | final Object child = | ||||
@@ -317,7 +317,6 @@ public class DefaultConfigurer | |||||
final TaskContext context ) | final TaskContext context ) | ||||
throws Exception | throws Exception | ||||
{ | { | ||||
// Extract the id | // Extract the id | ||||
final String id = element.getAttribute( "id" ); | final String id = element.getAttribute( "id" ); | ||||
if( 1 != element.getAttributeNames().length || | if( 1 != element.getAttributeNames().length || | ||||
@@ -329,7 +328,7 @@ public class DefaultConfigurer | |||||
// Set the property | // Set the property | ||||
final String name = element.getName(); | 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, | private void setReference( final ConfigurationState state, | ||||
final String refName, | final String refName, | ||||
final String unresolvedId, | final String unresolvedId, | ||||
final TaskContext context ) | |||||
final TaskContext context, | |||||
final boolean isAdder ) | |||||
throws Exception | throws Exception | ||||
{ | { | ||||
// Adjust the name | // Adjust the name | ||||
final String name = refName.substring( 0, refName.length() - 4 ); | final String name = refName.substring( 0, refName.length() - 4 ); | ||||
// Locate the configurer for the property | // 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 | // Resolve any props in the id | ||||
String id = context.resolveValue( unresolvedId ).toString(); | String id = context.resolveValue( unresolvedId ).toString(); | ||||
// Locate the referenced object | // Locate the referenced object | ||||
Object ref = context.getProperty( id ); | Object ref = context.getProperty( id ); | ||||
if( ref == null ) | |||||
if( null == ref ) | |||||
{ | { | ||||
final String message = REZ.getString( "unknown-reference.error", id ); | final String message = REZ.getString( "unknown-reference.error", id ); | ||||
throw new ConfigurationException( message ); | throw new ConfigurationException( message ); | ||||
} | } | ||||
// Convert the object, if necessary | // Convert the object, if necessary | ||||
final Class type = childConfigurer.getType(); | |||||
final Class type = configurer.getType(); | |||||
if( !type.isInstance( ref ) ) | if( !type.isInstance( ref ) ) | ||||
{ | { | ||||
try | try | ||||
@@ -375,7 +375,7 @@ public class DefaultConfigurer | |||||
} | } | ||||
// Set the child element | // Set the child element | ||||
childConfigurer.addValue( state, ref ); | |||||
configurer.addValue( state, ref ); | |||||
} | } | ||||
/** | /** | ||||
@@ -390,13 +390,12 @@ public class DefaultConfigurer | |||||
if( name.toLowerCase().endsWith( "-ref" ) ) | if( name.toLowerCase().endsWith( "-ref" ) ) | ||||
{ | { | ||||
// A reference | // A reference | ||||
setReference( state, name, value, context ); | |||||
setReference( state, name, value, context, false ); | |||||
} | } | ||||
else | else | ||||
{ | { | ||||
// Set the value | // Set the value | ||||
PropertyConfigurer propConfigurer | |||||
= getConfigurerFromName( state.getConfigurer(), name, false ); | |||||
PropertyConfigurer propConfigurer = getConfigurerFromName( state.getConfigurer(), name, false, false ); | |||||
setValue( propConfigurer, state, value, context ); | setValue( propConfigurer, state, value, context ); | ||||
} | } | ||||
} | } | ||||
@@ -495,35 +494,46 @@ public class DefaultConfigurer | |||||
*/ | */ | ||||
private PropertyConfigurer getConfigurerFromName( final ObjectConfigurer configurer, | private PropertyConfigurer getConfigurerFromName( final ObjectConfigurer configurer, | ||||
final String name, | final String name, | ||||
boolean ignoreRoleName ) | |||||
boolean ignoreRoleName, | |||||
final boolean isAdder ) | |||||
throws Exception | throws Exception | ||||
{ | { | ||||
// Try a named property | // 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; | 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; | 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 | // Unknown prop | ||||
throw new NoSuchPropertyException(); | throw new NoSuchPropertyException(); | ||||
} | } | ||||
@@ -35,19 +35,19 @@ class DefaultObjectConfigurer | |||||
private final Class m_class; | 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. | * The typed property configurer. | ||||
*/ | */ | ||||
private PropertyConfigurer m_typedPropConfigurer; | |||||
private PropertyConfigurer m_typedPropertyConfigurer; | |||||
/** | /** | ||||
* Content configurer. | * Content configurer. | ||||
@@ -80,19 +80,20 @@ class DefaultObjectConfigurer | |||||
private void enableProperties() | private void enableProperties() | ||||
throws ConfigurationException | throws ConfigurationException | ||||
{ | { | ||||
final Map adders = findAdders(); | |||||
final Map configurers = findPropertyConfigurers(); | |||||
// Add the elements | // Add the elements | ||||
final Iterator iterator = adders.keySet().iterator(); | |||||
final Iterator iterator = configurers.keySet().iterator(); | |||||
while( iterator.hasNext() ) | 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 | // 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() ) | if( isTypedProp && !type.isInterface() ) | ||||
{ | { | ||||
final String message = | final String message = | ||||
@@ -101,27 +102,48 @@ class DefaultObjectConfigurer | |||||
type.getName() ); | type.getName() ); | ||||
throw new ConfigurationException( message ); | 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 | 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 | * Locate all 'add' and 'set' methods which return void, and take a | ||||
* single parameter. | * single parameter. | ||||
*/ | */ | ||||
private Map findAdders() | |||||
private Map findPropertyConfigurers() | |||||
throws ConfigurationException | throws ConfigurationException | ||||
{ | { | ||||
final Map adders = new HashMap(); | final Map adders = new HashMap(); | ||||
@@ -163,6 +185,12 @@ class DefaultObjectConfigurer | |||||
if( adders.containsKey( propName ) ) | if( adders.containsKey( propName ) ) | ||||
{ | { | ||||
final Method candidate = (Method)adders.get( 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 ]; | final Class currentType = candidate.getParameterTypes()[ 0 ]; | ||||
// Ditch the string version, if any | // Ditch the string version, if any | ||||
@@ -226,14 +254,20 @@ class DefaultObjectConfigurer | |||||
final Class type = method.getParameterTypes()[ 0 ]; | final Class type = method.getParameterTypes()[ 0 ]; | ||||
m_contentConfigurer = | m_contentConfigurer = | ||||
new DefaultPropertyConfigurer( m_allProps.size(), | |||||
new DefaultPropertyConfigurer( getPropertyCount(), | |||||
type, | type, | ||||
method, | method, | ||||
1 ); | 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. | * Locates the configurer for a particular class. | ||||
*/ | */ | ||||
@@ -251,7 +285,7 @@ class DefaultObjectConfigurer | |||||
public ConfigurationState startConfiguration( Object object ) | public ConfigurationState startConfiguration( Object object ) | ||||
throws ConfigurationException | 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. | * 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() | public PropertyConfigurer getTypedProperty() | ||||
{ | { | ||||
return m_typedPropConfigurer; | |||||
return m_typedPropertyConfigurer; | |||||
} | } | ||||
/** | /** | ||||
@@ -26,17 +26,17 @@ class DefaultPropertyConfigurer | |||||
private final static Resources REZ = | private final static Resources REZ = | ||||
ResourceManager.getPackageResources( DefaultPropertyConfigurer.class ); | ResourceManager.getPackageResources( DefaultPropertyConfigurer.class ); | ||||
private final int m_propIndex; | |||||
private final int m_propertyIndex; | |||||
private final Class m_type; | private final Class m_type; | ||||
private final Method m_addMethod; | |||||
private final Method m_method; | |||||
private final int m_maxCount; | private final int m_maxCount; | ||||
public DefaultPropertyConfigurer( final int propIndex, | public DefaultPropertyConfigurer( final int propIndex, | ||||
final Class type, | final Class type, | ||||
final Method addMethod, | |||||
final Method method, | |||||
final int maxCount ) | final int maxCount ) | ||||
{ | { | ||||
m_propIndex = propIndex; | |||||
m_propertyIndex = propIndex; | |||||
if( type.isPrimitive() ) | if( type.isPrimitive() ) | ||||
{ | { | ||||
m_type = getComplexTypeFor( type ); | m_type = getComplexTypeFor( type ); | ||||
@@ -45,8 +45,13 @@ class DefaultPropertyConfigurer | |||||
{ | { | ||||
m_type = type; | m_type = type; | ||||
} | } | ||||
m_addMethod = addMethod; | |||||
m_method = method; | |||||
m_maxCount = maxCount; | m_maxCount = maxCount; | ||||
if( null == m_method ) | |||||
{ | |||||
throw new NullPointerException( "method" ); | |||||
} | |||||
} | } | ||||
/** | /** | ||||
@@ -64,22 +69,18 @@ class DefaultPropertyConfigurer | |||||
throws ConfigurationException | throws ConfigurationException | ||||
{ | { | ||||
final ConfigurationState defState = (ConfigurationState)state; | final ConfigurationState defState = (ConfigurationState)state; | ||||
// Check the property count | // 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" ); | final String message = REZ.getString( "too-many-values.error" ); | ||||
throw new ConfigurationException( message ); | throw new ConfigurationException( message ); | ||||
} | } | ||||
defState.incPropertyCount( m_propIndex ); | |||||
defState.incPropertyCount( m_propertyIndex ); | |||||
try | try | ||||
{ | { | ||||
// Add the value | // 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 ) | catch( final InvocationTargetException ite ) | ||||
{ | { | ||||
@@ -40,13 +40,22 @@ interface ObjectConfigurer | |||||
throws ConfigurationException; | 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 | * @return A configurer for the property, or null if the property is not | ||||
* valid for this class. | * 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. | * 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}. | create-typed-object.error=Could not create an object of type "{0}" of class {1}. | ||||
unknown-reference.error=Could not find referenced object "{0}". | unknown-reference.error=Could not find referenced object "{0}". | ||||
bad-configure-element.error=Could not configure element <{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}. |