donaldp 02/01/22 03:15:25
Modified:
proposal/myrmidon/src/java/org/apache/myrmidon/components/configurer
DefaultConfigurer.java DefaultObjectConfigurer.java
DefaultPropertyConfigurer.java
ObjectConfigurer.java PropertyConfigurer.java
Resources.properties
Added:
proposal/myrmidon/src/java/org/apache/myrmidon/components/configurer
ConfigurationState.java
DefaultConfigurationState.java
NoSuchPropertyException.java
Log:
This patch adds bunch of minor features to the configurer:
* Added max multiplicity checking. Properties with a setter method can only
be set once, whereas properties with an adder method can be set an unlimited
number of times.
* Resolves properties in reference ids. e.g
<javac classpath-ref="${my-classpath-id-name}"/>
* Ignores String adder and setter methods, if other methods exist. Longer
term, the type should be able to specify exactly which method to use.
* Moved all per-object state behind the ConfigurationState interface. The
ObjectConfigurer is now responsible for state-based validation.
* Tidied-up error messages. More context info is available in error
messages, to make figuring out the problem easier. Error messages still
need work.
Revision Changes Path
1.19 +149 -160
jakarta-ant/proposal/myrmidon/src/java/org/apache/myrmidon/components/configurer/DefaultConfigurer.java
Index: DefaultConfigurer.java
===================================================================
RCS file:
/home/cvs/jakarta-ant/proposal/myrmidon/src/java/org/apache/myrmidon/components/configurer/DefaultConfigurer.java,v
retrieving revision 1.18
retrieving revision 1.19
diff -u -r1.18 -r1.19
--- DefaultConfigurer.java 20 Jan 2002 17:32:57 -0000 1.18
+++ DefaultConfigurer.java 22 Jan 2002 11:15:25 -0000 1.19
@@ -7,11 +7,13 @@
*/
package org.apache.myrmidon.components.configurer;
+import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.Map;
import org.apache.avalon.excalibur.i18n.ResourceManager;
import org.apache.avalon.excalibur.i18n.Resources;
import org.apache.avalon.excalibur.property.PropertyUtil;
+import org.apache.avalon.framework.CascadingException;
import org.apache.avalon.framework.component.ComponentException;
import org.apache.avalon.framework.component.ComponentManager;
import org.apache.avalon.framework.component.Composable;
@@ -37,9 +39,6 @@
private final static Resources REZ =
ResourceManager.getPackageResources( DefaultConfigurer.class );
- ///Compile time constant to turn on extreme debugging
- private final static boolean DEBUG = false;
-
///Converter to use for converting between values
private MasterConverter m_converter;
@@ -71,50 +70,88 @@
final Context context )
throws ConfigurationException
{
- if( DEBUG )
+ try
+ {
+ configureObject( object, configuration, context );
+ }
+ catch( InvocationTargetException ite )
{
- final String message = REZ.getString(
"configuring-object.notice", object );
- getLogger().debug( message );
+ // A configuration exception thrown from a nested object. Unpack
+ // and re-throw
+ throw (ConfigurationException)ite.getTargetException();
}
+ }
+ /**
+ * Does the work of configuring an object.
+ */
+ private void configureObject( final Object object,
+ final Configuration configuration,
+ final Context context )
+ throws ConfigurationException, InvocationTargetException
+ {
if( object instanceof Configurable )
{
- if( DEBUG )
- {
- final String message = REZ.getString( "configurable.notice"
);
- getLogger().debug( message );
- }
-
// Let the object configure itself
( (Configurable)object ).configure( configuration );
}
else
{
- if( DEBUG )
- {
- final String message = REZ.getString( "reflection.notice" );
- getLogger().debug( message );
- }
+ final String elemName = configuration.getName();
// Locate the configurer for this object
final ObjectConfigurer configurer = getConfigurer(
object.getClass() );
+ // Start configuring this object
+ final ConfigurationState state = configurer.startConfiguration(
object );
+
// Set each of the attributes
final String[] attributes = configuration.getAttributeNames();
for( int i = 0; i < attributes.length; i++ )
{
final String name = attributes[ i ];
- final String value = configuration.getAttribute( name );
-
- // Set the attribute
- setAttribute( configurer, object, name, value, context );
+ try
+ {
+ // Set the attribute
+ final String value = configuration.getAttribute( name );
+ setAttribute( state, name, value, context );
+ }
+ catch( final NoSuchPropertyException nspe )
+ {
+ final String message =
+ REZ.getString( "no-such-attribute.error", elemName,
name );
+ throw new ConfigurationException( message, nspe );
+ }
+ catch( final CascadingException ce )
+ {
+ final String message =
+ REZ.getString( "bad-set-attribute.error", elemName,
name );
+ throw new ConfigurationException( message, ce );
+ }
}
// Set the text content
final String content = configuration.getValue( null );
if( null != content && content.length() > 0 )
{
- setContent( configurer, object, content, context );
+ try
+ {
+ // Set the content
+ final PropertyConfigurer contentConfigurer =
state.getConfigurer().getContentConfigurer();
+ setValue( contentConfigurer, state, content, context );
+ }
+ catch( final NoSuchPropertyException nspe )
+ {
+ final String message =
+ REZ.getString( "no-content.error", elemName );
+ throw new ConfigurationException( message, nspe );
+ }
+ catch( final CascadingException ce )
+ {
+ final String message =
+ REZ.getString( "bad-set-content.error", elemName );
+ throw new ConfigurationException( message, ce );
+ }
}
// Create and configure each of the child elements
@@ -122,8 +159,27 @@
for( int i = 0; i < children.length; i++ )
{
final Configuration childConfig = children[ i ];
- configureElement( configurer, object, childConfig, context );
+ final String name = childConfig.getName();
+ try
+ {
+ configureElement( state, childConfig, context );
+ }
+ catch( final NoSuchPropertyException nspe )
+ {
+ final String message =
+ REZ.getString( "no-such-element.error", elemName,
name );
+ throw new ConfigurationException( message, nspe );
+ }
+ catch( final CascadingException ce )
+ {
+ final String message =
+ REZ.getString( "bad-set-element.error", name );
+ throw new ConfigurationException( message, ce );
+ }
}
+
+ // Finish configuring the object
+ configurer.finishConfiguration( state );
}
}
@@ -147,121 +203,103 @@
// Locate the configurer for this object
final ObjectConfigurer configurer = getConfigurer( object.getClass()
);
- // Set the attribute value
- setAttribute( configurer, object, name, value, context );
- }
-
- /**
- * Sets the text content of an object.
- */
- private void setContent( final ObjectConfigurer configurer,
- final Object object,
- final String content,
- final Context context )
- throws ConfigurationException
- {
- if( DEBUG )
- {
- final String message =
- REZ.getString( "configure-content.notice", content );
- getLogger().debug( message );
- }
-
- // Set the content
- final PropertyConfigurer contentConfigurer =
configurer.getContentConfigurer();
- if( null == contentConfigurer )
- {
- final String message = REZ.getString(
"content-not-supported.error" );
- throw new ConfigurationException( message );
- }
+ // TODO - this ain't right, the validation is going to be screwed up
+ final ConfigurationState state = configurer.startConfiguration(
object );
+ // Set the attribute value
try
{
- setValue( contentConfigurer, object, content, context );
+ setAttribute( state, name, value, context );
}
- catch( final Exception e )
+ catch( final CascadingException ce )
{
- final String message = REZ.getString( "bad-set-content.error" );
- throw new ConfigurationException( message, e );
+ final String message =
+ REZ.getString( "bad-set-class-attribute.error",
+ name,
+ object.getClass().getName() );
+ throw new ConfigurationException( message, ce );
}
+
+ // Finish up
+ configurer.finishConfiguration( state );
}
/**
* Configures a property from a nested element.
*/
- private void configureElement( final ObjectConfigurer configurer,
- final Object object,
+ private void configureElement( final ConfigurationState state,
final Configuration element,
final Context context )
- throws ConfigurationException
+ throws CascadingException, InvocationTargetException
{
final String elementName = element.getName();
-
- if( DEBUG )
- {
- final String message =
- REZ.getString( "configure-subelement.notice", elementName );
- getLogger().debug( message );
- }
-
- if( elementName.endsWith( "-ref" ) )
+ if( elementName.toLowerCase().endsWith( "-ref" ) )
{
// A reference
- configureReference( configurer, object, element, context );
+ configureReference( state, element, context );
}
else
{
// An inline object
- configureInline( configurer, object, element, context );
+ configureInline( state, element, context );
}
}
/**
* Configure a property from an inline object.
*/
- private void configureInline( final ObjectConfigurer configurer,
- final Object object,
+ private void configureInline( final ConfigurationState state,
final Configuration element,
final Context context )
- throws ConfigurationException
+ throws CascadingException, InvocationTargetException
{
final String elementName = element.getName();
// Locate the configurer for the child element
- final PropertyConfigurer childConfigurer = configurer.getProperty(
elementName );
- if( null == childConfigurer )
+ final PropertyConfigurer childConfigurer =
state.getConfigurer().getProperty( elementName );
+
+ // Create the child element
+ Object child = childConfigurer.createValue( state );
+ if( child == null )
{
- final String message = REZ.getString( "unknown-property.error",
elementName );
- throw new ConfigurationException( message );
+ // Create an instance using the default constructor
+ try
+ {
+ child = childConfigurer.getType().newInstance();
+ }
+ catch( final Exception e )
+ {
+ final String message =
+ REZ.getString( "create-object.error",
+ childConfigurer.getType().getName() );
+ throw new ConfigurationException( message, e );
+ }
}
+ // Configure the child element
try
{
- // Create the child element
- final Object child = childConfigurer.createValue( object );
-
- // Configure the child element
- configure( child, element, context );
-
- // Set the child element
- childConfigurer.setValue( object, child );
+ configureObject( child, element, context );
}
catch( final ConfigurationException ce )
{
- final String message =
- REZ.getString( "bad-set-property.error", elementName );
- throw new ConfigurationException( message, ce );
+ // Nasty hack-o-rama, used to get this exception up through
+ // the stack of doConfigure() calls. This is unpacked by the
+ // top-most configure() call, and rethrown.
+ throw new InvocationTargetException( ce );
}
+
+ // Set the child element
+ childConfigurer.addValue( state, child );
}
/**
* Configures a property from a reference.
*/
- private void configureReference( final ObjectConfigurer configurer,
- final Object object,
+ private void configureReference( final ConfigurationState state,
final Configuration element,
final Context context )
- throws ConfigurationException
+ throws CascadingException
{
// Adjust the name
final String elementName = element.getName();
@@ -277,33 +315,23 @@
}
// Set the property
- setReference( configurer, object, name, id, context );
+ setReference( state, name, id, context );
}
/**
* Sets a property using a reference.
*/
- private void setReference( final ObjectConfigurer configurer,
- final Object object,
+ private void setReference( final ConfigurationState state,
final String name,
- final String id,
+ final String unresolvedId,
final Context context )
- throws ConfigurationException
+ throws CascadingException
{
// Locate the configurer for the child element
- final PropertyConfigurer childConfigurer = configurer.getProperty(
name );
- if( null == childConfigurer )
- {
- final String message = REZ.getString( "unknown-property.error",
name );
- throw new ConfigurationException( message );
- }
+ final PropertyConfigurer childConfigurer =
state.getConfigurer().getProperty( name );
- // Check if the creator method must be used
- if( childConfigurer.useCreator() )
- {
- final String message = REZ.getString( "must-be-element.error" );
- throw new ConfigurationException( message );
- }
+ // Resolve any props in the id
+ Object id = PropertyUtil.resolveProperty( unresolvedId, context,
false );
// Locate the referenced object
Object ref = null;
@@ -311,77 +339,45 @@
{
ref = context.get( id );
}
- catch( final ContextException ce )
+ catch( final ContextException exc )
{
- final String message = REZ.getString( "get-ref.error", id, name
);
- throw new ConfigurationException( message, ce );
+ final String message = REZ.getString( "get-ref.error", id );
+ throw new ConfigurationException( message, exc );
}
// Check the types
final Class type = childConfigurer.getType();
if( !type.isInstance( ref ) )
{
- final String message = REZ.getString(
"mismatch-ref-types.error", id, name );
+ final String message = REZ.getString(
"mismatch-ref-types.error", id, type.getName(), ref.getClass().getName() );
throw new ConfigurationException( message );
}
// Set the child element
- try
- {
- childConfigurer.setValue( object, ref );
- }
- catch( final ConfigurationException ce )
- {
- final String message =
- REZ.getString( "bad-set-property.error", name );
- throw new ConfigurationException( message, ce );
- }
+ childConfigurer.addValue( state, ref );
}
/**
* Sets an attribute value.
*/
- private void setAttribute( final ObjectConfigurer configurer,
- final Object object,
+ private void setAttribute( final ConfigurationState state,
final String name,
final String value,
final Context context )
- throws ConfigurationException
+ throws CascadingException
{
- if( DEBUG )
- {
- final String message = REZ.getString(
"configure-attribute.notice",
- name,
- value );
- getLogger().debug( message );
- }
-
- if( name.endsWith( "-ref" ) )
+ if( name.toLowerCase().endsWith( "-ref" ) )
{
// A reference
final String refName = name.substring( 0, name.length() - 4 );
- setReference( configurer, object, refName, value, context );
+ setReference( state, refName, value, context );
}
else
{
- // Locate the configurer for this attribute
- final PropertyConfigurer propConfigurer =
configurer.getProperty( name );
- if( null == propConfigurer )
- {
- final String message = REZ.getString(
"unknown-property.error", name );
- throw new ConfigurationException( message );
- }
-
// Set the value
- try
- {
- setValue( propConfigurer, object, value, context );
- }
- catch( final Exception e )
- {
- final String message = REZ.getString(
"bad-set-property.error", name );
- throw new ConfigurationException( message, e );
- }
+ final PropertyConfigurer propConfigurer =
+ state.getConfigurer().getProperty( name );
+ setValue( propConfigurer, state, value, context );
}
}
@@ -389,18 +385,11 @@
* Sets an attribute value, or an element's text content.
*/
private void setValue( final PropertyConfigurer setter,
- final Object object,
+ final ConfigurationState state,
final String value,
final Context context )
- throws Exception
+ throws CascadingException
{
- // Check if the creator method must be used
- if( setter.useCreator() )
- {
- final String message = REZ.getString( "must-be-element.error" );
- throw new ConfigurationException( message );
- }
-
// Resolve property references in the attribute value
Object objValue = PropertyUtil.resolveProperty( value, context,
false );
@@ -409,7 +398,7 @@
objValue = m_converter.convert( clazz, objValue, context );
// Set the value
- setter.setValue( object, objValue );
+ setter.addValue( state, objValue );
}
/**
1.4 +109 -32
jakarta-ant/proposal/myrmidon/src/java/org/apache/myrmidon/components/configurer/DefaultObjectConfigurer.java
Index: DefaultObjectConfigurer.java
===================================================================
RCS file:
/home/cvs/jakarta-ant/proposal/myrmidon/src/java/org/apache/myrmidon/components/configurer/DefaultObjectConfigurer.java,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -r1.3 -r1.4
--- DefaultObjectConfigurer.java 20 Jan 2002 17:32:57 -0000 1.3
+++ DefaultObjectConfigurer.java 22 Jan 2002 11:15:25 -0000 1.4
@@ -7,27 +7,26 @@
*/
package org.apache.myrmidon.components.configurer;
-import org.apache.avalon.excalibur.i18n.ResourceManager;
-import org.apache.avalon.excalibur.i18n.Resources;
-import org.apache.avalon.framework.configuration.ConfigurationException;
-
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
-import java.util.Map;
+import java.util.ArrayList;
+import java.util.Collection;
import java.util.HashMap;
-import java.util.Set;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
-import java.util.ArrayList;
-import java.util.Collection;
+import java.util.Map;
+import java.util.Set;
+import org.apache.avalon.excalibur.i18n.ResourceManager;
+import org.apache.avalon.excalibur.i18n.Resources;
+import org.apache.avalon.framework.configuration.ConfigurationException;
/**
* An object configurer which uses reflection to determine the properties
* of a class.
*
* @author <a href="mailto:[EMAIL PROTECTED]">Adam Murdoch</a>
- * @version $Revision: 1.3 $ $Date: 2002/01/20 17:32:57 $
+ * @version $Revision: 1.4 $ $Date: 2002/01/22 11:15:25 $
*/
public class DefaultObjectConfigurer
implements ObjectConfigurer
@@ -43,6 +42,11 @@
private final Map m_props = new HashMap();
/**
+ * All property configurers.
+ */
+ private final List m_allProps = new ArrayList();
+
+ /**
* Content configurer.
*/
private PropertyConfigurer m_contentConfigurer;
@@ -101,8 +105,8 @@
{
final String message =
REZ.getString( "incompatible-element-types.error",
- propName,
- m_class.getName() );
+ m_class.getName(),
+ propName );
throw new ConfigurationException( message );
}
}
@@ -115,9 +119,21 @@
type = addMethod.getParameterTypes()[ 0 ];
}
+ // Determine the max count for the property
+ int maxCount = Integer.MAX_VALUE;
+ if( addMethod != null && addMethod.getName().startsWith( "set" )
)
+ {
+ maxCount = 1;
+ }
+
final DefaultPropertyConfigurer configurer =
- new DefaultPropertyConfigurer( type, createMethod, addMethod
);
+ new DefaultPropertyConfigurer( m_allProps.size(),
+ type,
+ createMethod,
+ addMethod,
+ maxCount );
m_props.put( propName, configurer );
+ m_allProps.add( configurer );
}
}
@@ -138,8 +154,8 @@
{
final Method method = (Method)iterator.next();
final String methodName = method.getName();
- if( method.getReturnType() != Void.TYPE ||
- method.getParameterTypes().length != 1 )
+ if( method.getReturnType() != Void.TYPE
+ || method.getParameterTypes().length != 1 )
{
continue;
}
@@ -150,19 +166,37 @@
continue;
}
- // Extract element name
- final String elemName = extractName( 3, methodName );
+ // Extract property name
+ final String propName = extractName( 3, methodName );
+
+ final Class type = method.getParameterTypes()[ 0 ];
// Add to the adders map
- if( adders.containsKey( elemName ) )
+ if( adders.containsKey( propName ) )
{
- final String message =
- REZ.getString(
"multiple-adder-methods-for-element.error",
- m_class.getName(),
- elemName );
- throw new ConfigurationException( message );
+ final Class currentType = ( (Method)adders.get( propName )
).getParameterTypes()[ 0 ];
+
+ // Ditch the string version, if any
+ if( currentType != String.class && type == String.class )
+ {
+ // New type is string, and current type is not. Ignore
+ // the new method
+ continue;
+ }
+ if( currentType != String.class || type == String.class )
+ {
+ // Both are string, or both are not string
+ final String message =
+ REZ.getString(
"multiple-adder-methods-for-element.error",
+ m_class.getName(),
+ propName );
+ throw new ConfigurationException( message );
+ }
+
+ // Else, current type is string, and new type is not, so
+ // continue below, and overwrite the current method
}
- adders.put( elemName, method );
+ adders.put( propName, method );
}
return adders;
}
@@ -235,8 +269,14 @@
throw new ConfigurationException( message );
}
- Class type = method.getParameterTypes()[0];
- m_contentConfigurer = new DefaultPropertyConfigurer( type, null,
method );
+ final Class type = method.getParameterTypes()[ 0 ];
+ m_contentConfigurer =
+ new DefaultPropertyConfigurer( m_allProps.size(),
+ type,
+ null,
+ method,
+ 1 );
+ m_allProps.add( m_contentConfigurer );
}
}
@@ -252,27 +292,64 @@
}
/**
- * Returns the class.
+ * Starts the configuration of an object.
*/
- public Class getType()
+ public ConfigurationState startConfiguration( Object object )
+ throws ConfigurationException
{
- return m_class;
+ return new DefaultConfigurationState( this, object,
m_allProps.size() );
+ }
+
+ /**
+ * Finishes the configuration of an object, performing any final
+ * validation and type conversion.
+ */
+ public Object finishConfiguration( final ConfigurationState state )
+ throws ConfigurationException
+ {
+ // Make sure there are no pending created objects
+ final DefaultConfigurationState defState =
(DefaultConfigurationState)state;
+ for( int i = 0; i < m_allProps.size(); i++ )
+ {
+ if( defState.getCreatedObject( i ) != null )
+ {
+ final String message = REZ.getString(
"pending-property-value.error" );
+ throw new ConfigurationException( message );
+ }
+ }
+
+ return defState.getObject();
}
/**
* Returns a configurer for an element of this class.
*/
- public PropertyConfigurer getProperty( final String name )
+ public PropertyConfigurer getProperty( final String name ) throws
NoSuchPropertyException
{
- return (PropertyConfigurer)m_props.get( name );
+ final PropertyConfigurer prop = (PropertyConfigurer)m_props.get(
name );
+ if( prop != null )
+ {
+ return prop;
+ }
+
+ // Unknown property
+ final String message = REZ.getString( "unknown-property.error",
m_class.getName(), name );
+ throw new NoSuchPropertyException( message );
}
/**
* Returns a configurer for the content of this class.
*/
- public PropertyConfigurer getContentConfigurer()
+ public PropertyConfigurer getContentConfigurer() throws
NoSuchPropertyException
{
- return m_contentConfigurer;
+ if( m_contentConfigurer != null )
+ {
+ return m_contentConfigurer;
+ }
+
+ // Does not handle content
+ final String message = REZ.getString( "content-unsupported.error",
m_class.getName() );
+ throw new NoSuchPropertyException( message );
}
/**
1.3 +66 -30
jakarta-ant/proposal/myrmidon/src/java/org/apache/myrmidon/components/configurer/DefaultPropertyConfigurer.java
Index: DefaultPropertyConfigurer.java
===================================================================
RCS file:
/home/cvs/jakarta-ant/proposal/myrmidon/src/java/org/apache/myrmidon/components/configurer/DefaultPropertyConfigurer.java,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -r1.2 -r1.3
--- DefaultPropertyConfigurer.java 20 Jan 2002 17:32:57 -0000 1.2
+++ DefaultPropertyConfigurer.java 22 Jan 2002 11:15:25 -0000 1.3
@@ -7,19 +7,18 @@
*/
package org.apache.myrmidon.components.configurer;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
import org.apache.avalon.excalibur.i18n.ResourceManager;
import org.apache.avalon.excalibur.i18n.Resources;
import org.apache.avalon.framework.configuration.ConfigurationException;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-
/**
* The default property configurer implementation, which uses reflection to
* create and set property values.
*
* @author <a href="mailto:[EMAIL PROTECTED]">Adam Murdoch</a>
- * @version $Revision: 1.2 $ $Date: 2002/01/20 17:32:57 $
+ * @version $Revision: 1.3 $ $Date: 2002/01/22 11:15:25 $
*/
class DefaultPropertyConfigurer
implements PropertyConfigurer
@@ -27,21 +26,30 @@
private final static Resources REZ =
ResourceManager.getPackageResources( DefaultPropertyConfigurer.class
);
+ private final int m_propIndex;
private final Class m_type;
private final Method m_createMethod;
private final Method m_addMethod;
+ private final int m_maxCount;
- public DefaultPropertyConfigurer( Class type,
- Method createMethod,
- Method addMethod )
+ public DefaultPropertyConfigurer( final int propIndex,
+ final Class type,
+ final Method createMethod,
+ final Method addMethod,
+ final int maxCount )
{
+ m_propIndex = propIndex;
if ( type.isPrimitive() )
{
- type = getComplexTypeFor(type);
+ m_type = getComplexTypeFor(type);
+ }
+ else
+ {
+ m_type = type;
}
- m_type = type;
m_createMethod = createMethod;
m_addMethod = addMethod;
+ m_maxCount = maxCount;
}
/**
@@ -53,29 +61,31 @@
}
/**
- * Determines if the property value must be created via [EMAIL
PROTECTED] #createValue}.
- */
- public boolean useCreator()
- {
- return (m_createMethod != null);
- }
-
- /**
- * Creates a nested element.
+ * Creates a default value for this property.
*/
- public Object createValue( final Object parent )
+ public Object createValue( ConfigurationState state )
throws ConfigurationException
{
+ if( null == m_createMethod )
+ {
+ return null;
+ }
+
+ final DefaultConfigurationState defState =
(DefaultConfigurationState)state;
+
+ // Make sure there isn't a pending object for this property
+ if( defState.getCreatedObject( m_propIndex ) != null )
+ {
+ final String message = REZ.getString(
"pending-property-value.error" );
+ throw new ConfigurationException( message );
+ }
+
try
{
- if( null != m_createMethod )
- {
- return m_createMethod.invoke( parent, null );
- }
- else
- {
- return m_type.newInstance();
- }
+ // Create the value
+ final Object object = m_createMethod.invoke(
defState.getObject(), null );
+ defState.setCreatedObject( m_propIndex, object );
+ return object;
}
catch( final InvocationTargetException ite )
{
@@ -89,16 +99,42 @@
}
/**
- * Sets the nested element, after it has been configured.
+ * Adds a value for this property, to an object.
*/
- public void setValue( final Object parent, final Object child )
+ public void addValue( ConfigurationState state, Object value )
throws ConfigurationException
{
+ final DefaultConfigurationState defState =
(DefaultConfigurationState)state;
+
+ // Make sure the supplied object is the pending object
+ final Object pending = defState.getCreatedObject( m_propIndex );
+ if( pending != null && pending != value )
+ {
+ }
+
+ // Make sure the creator method was called, if necessary
+ if( pending == null && m_createMethod != null )
+ {
+ final String message = REZ.getString( "must-be-element.error" );
+ throw new ConfigurationException( message );
+ }
+
+ defState.setCreatedObject( m_propIndex, null );
+
+ // Check the property count
+ if( defState.getPropCount( m_propIndex ) >= m_maxCount )
+ {
+ final String message = REZ.getString( "too-many-values.error" );
+ throw new ConfigurationException( message );
+ }
+ defState.incPropCount( m_propIndex );
+
try
{
+ // Add the value
if( null != m_addMethod )
{
- m_addMethod.invoke( parent, new Object[]{child} );
+ m_addMethod.invoke( defState.getObject(), new Object[]{
value } );
}
}
catch( final InvocationTargetException ite )
1.3 +32 -10
jakarta-ant/proposal/myrmidon/src/java/org/apache/myrmidon/components/configurer/ObjectConfigurer.java
Index: ObjectConfigurer.java
===================================================================
RCS file:
/home/cvs/jakarta-ant/proposal/myrmidon/src/java/org/apache/myrmidon/components/configurer/ObjectConfigurer.java,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -r1.2 -r1.3
--- ObjectConfigurer.java 14 Jan 2002 09:31:22 -0000 1.2
+++ ObjectConfigurer.java 22 Jan 2002 11:15:25 -0000 1.3
@@ -7,33 +7,55 @@
*/
package org.apache.myrmidon.components.configurer;
+import org.apache.avalon.framework.configuration.ConfigurationException;
+
/**
* Configures objects of a particular class.
*
* @author <a href="mailto:[EMAIL PROTECTED]">Adam Murdoch</a>
- * @version $Revision: 1.2 $ $Date: 2002/01/14 09:31:22 $
+ * @version $Revision: 1.3 $ $Date: 2002/01/22 11:15:25 $
*/
public interface ObjectConfigurer
{
/**
- * Returns the class.
+ * Starts the configuration of an object.
+ *
+ * @param object The object about to be configured.
+ * @return The state object, used to track type-specific state during
+ * configuration.
+ * @throws ConfigurationException On error starting the configuration.
+ */
+ ConfigurationState startConfiguration( Object object )
+ throws ConfigurationException;
+
+ /**
+ * Finishes the configuration of an object, performing any final
+ * validation and type conversion.
+ *
+ * @param state The state object.
+ * @return The configured object.
+ * @throws ConfigurationException On error finishing the configurtion.
*/
- Class getType();
+ Object finishConfiguration( ConfigurationState state )
+ throws ConfigurationException;
/**
* Returns a configurer for a property of this class.
*
- * @param name The element name.
- * @return A configurer for the property. Returns null if the property
- * is not valid for this class.
+ * @param name The element name. Property names are case-insensitive.
+ * @return A configurer for the property.
+ * @throws NoSuchPropertyException If the property is not valid for this
+ * class
*/
- PropertyConfigurer getProperty( String name );
+ PropertyConfigurer getProperty( String name )
+ throws NoSuchPropertyException;
/**
* Returns a configurer for the content of this class.
*
- * @return A configurer for the content. Returns null if the class does
- * not allow text content.
+ * @return A configurer for the content.
+ * @throws NoSuchPropertyException If the class does not handle content.
*/
- PropertyConfigurer getContentConfigurer();
+ PropertyConfigurer getContentConfigurer()
+ throws NoSuchPropertyException;
}
1.2 +10 -14
jakarta-ant/proposal/myrmidon/src/java/org/apache/myrmidon/components/configurer/PropertyConfigurer.java
Index: PropertyConfigurer.java
===================================================================
RCS file:
/home/cvs/jakarta-ant/proposal/myrmidon/src/java/org/apache/myrmidon/components/configurer/PropertyConfigurer.java,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- PropertyConfigurer.java 14 Jan 2002 09:31:22 -0000 1.1
+++ PropertyConfigurer.java 22 Jan 2002 11:15:25 -0000 1.2
@@ -14,41 +14,37 @@
* TODO - axe useCreator() and createValue().
*
* @author <a href="mailto:[EMAIL PROTECTED]">Adam Murdoch</a>
- * @version $Revision: 1.1 $ $Date: 2002/01/14 09:31:22 $
+ * @version $Revision: 1.2 $ $Date: 2002/01/22 11:15:25 $
*/
public interface PropertyConfigurer
{
/**
- * Returns the type of the property.
+ * Returns the type of this property.
*/
Class getType();
/**
- * Determines if the property value must be created via [EMAIL
PROTECTED] #createValue}.
- */
- boolean useCreator();
-
- /**
- * Creates a default value for the property. This value must be
configured,
+ * Creates a default value for this property. This value must be
configured,
* and then attached to the object using [EMAIL PROTECTED] #setValue}.
This
* method must be called if [EMAIL PROTECTED] #useCreator} returns true.
*
- * @param parent The parent object.
+ * @param state The state object, representing the object being
configured.
* @return An object which is assignable to the type returned by
- * [EMAIL PROTECTED] #getType}.
+ * [EMAIL PROTECTED] #getType}. Returns null if this property
does not
+ * need a default value.
* @throws ConfigurationException If the object cannot be created.
*/
- Object createValue( Object parent )
+ Object createValue( ConfigurationState state )
throws ConfigurationException;
/**
- * Sets a property value for an object.
+ * Adds a value for this property, to an object.
*
- * @param object The object to set the property of.
+ * @param state The state object, representing the object being
configured.
* @param value The property value. This must be assignable to the type
* returned by [EMAIL PROTECTED] #getType}.
* @throws ConfigurationException If the property cannot be set.
*/
- void setValue( Object object, Object value )
+ void addValue( ConfigurationState state, Object value )
throws ConfigurationException;
}
1.5 +19 -18
jakarta-ant/proposal/myrmidon/src/java/org/apache/myrmidon/components/configurer/Resources.properties
Index: Resources.properties
===================================================================
RCS file:
/home/cvs/jakarta-ant/proposal/myrmidon/src/java/org/apache/myrmidon/components/configurer/Resources.properties,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -r1.4 -r1.5
--- Resources.properties 14 Jan 2002 09:31:22 -0000 1.4
+++ Resources.properties 22 Jan 2002 11:15:25 -0000 1.5
@@ -1,20 +1,21 @@
-configuring-object.notice=Configuring {0}.
-configurable.notice=Configuring object via Configurable interface.
-reflection.notice=Configuring object via ObjectConfigurer.
-configure-content.notice=Configuring content with "{0}".
-configure-subelement.notice=Configuring subelement "{0}".
-configure-attribute.notice=Configuring attribute name="{0}" value="{1}".
-
-content-not-supported.error=Text content is not supported for this element.
-bad-set-content.error=Could not set text content.
-unknown-property.error=Unknown property "{0}".
-bad-set-property.error=Could not set property "{0}".
-no-complex-type.error=Can not get complex type for non-primitive type {0}.
+create-object.error=Could not create an object of class {0}.
extra-config-for-ref.error=A reference element can only include an "id"
attribute.
-get-ref.error=Could not locate reference "{0}" for element "{1}".
-mismatch-ref-types.error=Mismatched type for reference "{0}" for element
"{1}".
-multiple-creator-methods-for-element.error=Multiple creator methods found in
class {0} for property "{0}".
-multiple-adder-methods-for-element.error=Multiple adder/setter methods found
in class {0} for property "{0}".
-incompatible-element-types.error=Incompatible creator and adder/setter types
for property "{0}" of class {1}.
+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-creator-methods-for-element.error=Multiple creator methods found in
class {0} for property "{1}".
multiple-content-setter-methods.error=Multiple content setter methods found
in class {0}.
-must-be-element.error=This property must be configured using a nested
element.
\ No newline at end of file
+pending-property-value.error=An object created using the creator method has
not been set using the adder/setter method.
+unknown-property.error=Class {0} does not have a "{1}" property.
+content-not-supported.error=Class {0} does not support text content.
+must-be-element.error=This property must be configured using a nested
element.
+too-many-values.error=Too many values for this property.
+no-complex-type.error=Can not get complex type for non-primitive type {0}.
+no-such-attribute.error=Attribute "{1}" is not allowed for element <{0}>.
+bad-set-attribute.error=Could not set attribute "{1}" for element <{0}>.
+bad-set-class-attribute.error=Could not set attribute "{0}" for object of
class {1}.
+no-such-element.error=Nested <{1}> elements are not allowed for element
<{0}>.
+bad-set-element.error=Could not handle element <{1}>, nested in element
<{0}>.
+no-content.error=Text content is not allowed for element <{0}>.
+bad-set-content.error=Could not set text content for element <{0}>.
1.1
jakarta-ant/proposal/myrmidon/src/java/org/apache/myrmidon/components/configurer/ConfigurationState.java
Index: ConfigurationState.java
===================================================================
/*
* 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;
/**
* A marker interface that represents the state of an object while it is being
* configured.
*
* @author Adam Murdoch
*/
public interface ConfigurationState
{
/**
* Returns the configurer being used to configure the object.
*/
ObjectConfigurer getConfigurer();
}
1.1
jakarta-ant/proposal/myrmidon/src/java/org/apache/myrmidon/components/configurer/DefaultConfigurationState.java
Index: DefaultConfigurationState.java
===================================================================
/*
* 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;
/**
* A default configuration state implementation. Keeps track of which
* of the object's properties have been set. Also keeps track of the
* objects created by the creator methods, but not yet set by the adder
* methods.
*
* @author Adam Murdoch
*/
public class DefaultConfigurationState
implements ConfigurationState
{
final private int[] m_propCount;
final private Object[] m_createdObjects;
final private ObjectConfigurer m_configurer;
final private Object m_object;
public DefaultConfigurationState( final ObjectConfigurer configurer,
final Object object,
final int numProps )
{
m_configurer = configurer;
m_object = object;
m_propCount = new int[ numProps ];
m_createdObjects = new Object[ numProps ];
}
/**
* Returns the configurer being used to configure the object.
*/
public ObjectConfigurer getConfigurer()
{
return m_configurer;
}
/** Returns the object being configured. */
public Object getObject()
{
return m_object;
}
/** Returns a property count. */
public int getPropCount( final int propIndex )
{
return m_propCount[ propIndex ];
}
/** Increments a property count. */
public void incPropCount( final int propIndex )
{
m_propCount[ propIndex ]++;
}
/** Returns a property's pending objects. */
public Object getCreatedObject( final int propIndex )
{
return m_createdObjects[ propIndex ];
}
/** Sets a property's pending objects. */
public void setCreatedObject( final int propIndex, final Object object )
{
m_createdObjects[ propIndex ] = object;
}
}
1.1
jakarta-ant/proposal/myrmidon/src/java/org/apache/myrmidon/components/configurer/NoSuchPropertyException.java
Index: NoSuchPropertyException.java
===================================================================
/*
* Copyright (C) The Apache Software Foundation. All rights reserved.
*
* This software is published under the terms of the Apache Software License
* version 1.1, a copy of which has been included with this distribution in
* the LICENSE.txt file.
*/
package org.apache.myrmidon.components.configurer;
import org.apache.avalon.framework.CascadingException;
/**
* An exception thrown when an unknown property is encountered.
*
* TODO - this should extend ConfigurationException, however
* ConfigurationException is final.
*
* @author Adam Murdoch
*/
public class NoSuchPropertyException extends CascadingException
{
public NoSuchPropertyException( String message )
{
super( message );
}
}
--
To unsubscribe, e-mail: <mailto:[EMAIL PROTECTED]>
For additional commands, e-mail: <mailto:[EMAIL PROTECTED]>