ant-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From dona...@apache.org
Subject cvs commit: jakarta-ant/proposal/myrmidon/src/java/org/apache/myrmidon/components/configurer ConfigurationState.java DefaultConfigurationState.java NoSuchPropertyException.java DefaultConfigurer.java DefaultObjectConfigurer.java DefaultPropertyConfigurer.java ObjectConfigurer.java PropertyConfigurer.java Resources.properties
Date Tue, 22 Jan 2002 11:15:25 GMT
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:adammurdoch_ml@yahoo.com">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:adammurdoch_ml@yahoo.com">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 {@link #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:adammurdoch_ml@yahoo.com">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:adammurdoch_ml@yahoo.com">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 {@link #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 {@link #setValue}.  This
        * method must be called if {@link #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
  -     *         {@link #getType}.
  +     *         {@link #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 {@link #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:ant-dev-unsubscribe@jakarta.apache.org>
For additional commands, e-mail: <mailto:ant-dev-help@jakarta.apache.org>


Mime
View raw message