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}. |