Return-Path: Delivered-To: apmail-jakarta-ant-dev-archive@apache.org Received: (qmail 57667 invoked from network); 22 Jan 2002 07:08:59 -0000 Received: from unknown (HELO nagoya.betaversion.org) (192.18.49.131) by daedalus.apache.org with SMTP; 22 Jan 2002 07:08:59 -0000 Received: (qmail 24230 invoked by uid 97); 22 Jan 2002 05:11:30 -0000 Delivered-To: qmlist-jakarta-archive-ant-dev@jakarta.apache.org Received: (qmail 24190 invoked by uid 97); 22 Jan 2002 05:11:29 -0000 Mailing-List: contact ant-dev-help@jakarta.apache.org; run by ezmlm Precedence: bulk List-Unsubscribe: List-Subscribe: List-Help: List-Post: List-Id: "Ant Developers List" Reply-To: "Ant Developers List" Delivered-To: mailing list ant-dev@jakarta.apache.org Received: (qmail 24179 invoked from network); 22 Jan 2002 05:11:29 -0000 From: "Adam Murdoch" To: Subject: [myrmidon] configurer changes Date: Tue, 22 Jan 2002 15:08:06 +1000 Message-ID: MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="----=_NextPart_000_0004_01C1A356.98AB1B70" X-Priority: 3 (Normal) X-MSMail-Priority: Normal X-Mailer: Microsoft Outlook IMO, Build 9.0.2416 (9.0.2910.0) Importance: Normal X-MimeOLE: Produced By Microsoft MimeOLE V5.50.4522.1200 X-Spam-Rating: 64.125.133.20 1.6.2 0/1000/N X-Spam-Rating: daedalus.apache.org 1.6.2 0/1000/N ------=_NextPart_000_0004_01C1A356.98AB1B70 Content-Type: text/plain; charset="iso-8859-1" Content-Transfer-Encoding: 7bit Hi, 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 * 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. * Created a unit test suite. Added some tests for DefaultConfigurer. Adam ------=_NextPart_000_0004_01C1A356.98AB1B70 Content-Type: text/plain; name="patch.txt" Content-Transfer-Encoding: quoted-printable Content-Disposition: attachment; filename="patch.txt" Index: proposal/myrmidon/build.xml =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D RCS file: /home/cvspublic/jakarta-ant/proposal/myrmidon/build.xml,v retrieving revision 1.40 diff -u -r1.40 build.xml --- proposal/myrmidon/build.xml 19 Jan 2002 07:41:47 -0000 1.40 +++ proposal/myrmidon/build.xml 22 Jan 2002 04:41:51 -0000 @@ -59,6 +59,8 @@ =20 + + =20 @@ -477,9 +479,31 @@ =20 + + + + + + + + + + + + + + + + + =20 Index: = proposal/myrmidon/src/java/org/apache/myrmidon/components/configurer/Defa= ultConfigurer.java =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D RCS file: = /home/cvspublic/jakarta-ant/proposal/myrmidon/src/java/org/apache/myrmido= n/components/configurer/DefaultConfigurer.java,v retrieving revision 1.18 diff -u -r1.18 DefaultConfigurer.java --- = proposal/myrmidon/src/java/org/apache/myrmidon/components/configurer/Defa= ultConfigurer.java 20 Jan 2002 17:32:57 -0000 1.18 +++ = proposal/myrmidon/src/java/org/apache/myrmidon/components/configurer/Defa= ultConfigurer.java 22 Jan 2002 04:41:54 -0000 @@ -7,11 +7,13 @@ */ package org.apache.myrmidon.components.configurer; =20 +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 =3D ResourceManager.getPackageResources( DefaultConfigurer.class ); =20 - ///Compile time constant to turn on extreme debugging - private final static boolean DEBUG =3D false; - ///Converter to use for converting between values private MasterConverter m_converter; =20 @@ -71,50 +70,90 @@ final Context context ) throws ConfigurationException { - if( DEBUG ) + try { - final String message =3D REZ.getString( = "configuring-object.notice", object ); - getLogger().debug( message ); + configureObject( object, configuration, context ); } + catch( InvocationTargetException ite ) + { + // A configuration exception thrown from a nested object. = Unpack + // and re-throw + throw (ConfigurationException)ite.getTargetException(); + } + } =20 + /** + * 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 =3D REZ.getString( = "configurable.notice" ); - getLogger().debug( message ); - } - // Let the object configure itself ( (Configurable)object ).configure( configuration ); } else { - if( DEBUG ) - { - final String message =3D REZ.getString( = "reflection.notice" ); - getLogger().debug( message ); - } + final String elemName =3D configuration.getName(); =20 // Locate the configurer for this object final ObjectConfigurer configurer =3D getConfigurer( = object.getClass() ); =20 + // Start configuring this object + final ConfigurationState state =3D = configurer.startConfiguration( object ); + // Set each of the attributes final String[] attributes =3D = configuration.getAttributeNames(); for( int i =3D 0; i < attributes.length; i++ ) { final String name =3D attributes[ i ]; - final String value =3D configuration.getAttribute( name = ); - - // Set the attribute - setAttribute( configurer, object, name, value, context = ); + try + { + // Set the attribute + final String value =3D configuration.getAttribute( = name ); + setAttribute( state, name, value, context ); + } + catch( NoSuchPropertyException exc ) + { + final String message =3D REZ.getString( = "no-such-attribute.error", + elemName, + name ); + throw new ConfigurationException( message, exc ); + } + catch( CascadingException exc ) + { + final String message =3D REZ.getString( = "bad-set-attribute.error", + elemName, + name ); + throw new ConfigurationException( message, exc ); + } } =20 // Set the text content final String content =3D configuration.getValue( null ); if( null !=3D content && content.length() > 0 ) { - setContent( configurer, object, content, context ); + try + { + // Set the content + final PropertyConfigurer contentConfigurer =3D = state.getConfigurer().getContentConfigurer(); + setValue( contentConfigurer, state, content, = context ); + } + catch( NoSuchPropertyException exc ) + { + final String message =3D REZ.getString( = "no-content.error", + elemName ); + throw new ConfigurationException( message, exc ); + } + catch( CascadingException exc ) + { + final String message =3D REZ.getString( = "bad-set-content.error", + elemName ); + throw new ConfigurationException( message, exc ); + } } =20 // Create and configure each of the child elements @@ -122,8 +161,28 @@ for( int i =3D 0; i < children.length; i++ ) { final Configuration childConfig =3D children[ i ]; - configureElement( configurer, object, childConfig, = context ); + final String name =3D childConfig.getName(); + try + { + configureElement( state, childConfig, context ); + } + catch( NoSuchPropertyException exc ) + { + final String message =3D REZ.getString( = "no-such-element.error", + elemName, + name ); + throw new ConfigurationException( message, exc ); + } + catch( CascadingException exc ) + { + final String message =3D REZ.getString( = "bad-set-element.error", + name ); + throw new ConfigurationException( message, exc ); + } } + + // Finish configuring the object + configurer.finishConfiguration( state ); } } =20 @@ -147,121 +206,100 @@ // Locate the configurer for this object final ObjectConfigurer configurer =3D getConfigurer( = object.getClass() ); =20 - // 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 =3D - REZ.getString( "configure-content.notice", content ); - getLogger().debug( message ); - } - - // Set the content - final PropertyConfigurer contentConfigurer =3D = configurer.getContentConfigurer(); - if( null =3D=3D contentConfigurer ) - { - final String message =3D 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 =3D = configurer.startConfiguration( object ); =20 + // Set the attribute value try { - setValue( contentConfigurer, object, content, context ); + setAttribute( state, name, value, context ); } - catch( final Exception e ) + catch( CascadingException exc ) { - final String message =3D REZ.getString( = "bad-set-content.error" ); - throw new ConfigurationException( message, e ); + final String message =3D REZ.getString( = "bad-set-class-attribute.error", + name, + = object.getClass().getName() ); + throw new ConfigurationException( message, exc ); } + + // Finish up + configurer.finishConfiguration( state ); } =20 /** * 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 =3D element.getName(); - - if( DEBUG ) - { - final String message =3D - 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 ); } } =20 /** * 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 =3D element.getName(); =20 // Locate the configurer for the child element - final PropertyConfigurer childConfigurer =3D = configurer.getProperty( elementName ); - if( null =3D=3D childConfigurer ) + final PropertyConfigurer childConfigurer =3D = state.getConfigurer().getProperty( elementName ); + + // Create the child element + Object child =3D childConfigurer.createValue( state ); + if( child =3D=3D null ) { - final String message =3D REZ.getString( = "unknown-property.error", elementName ); - throw new ConfigurationException( message ); + // Create an instance using the default constructor + try + { + child =3D childConfigurer.getType().newInstance(); + } + catch( Exception exc ) + { + final String message =3D REZ.getString( = "create-object.error", childConfigurer.getType().getName() ); + throw new ConfigurationException( message, exc ); + } } =20 + // Configure the child element try { - // Create the child element - final Object child =3D 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 ) + catch( ConfigurationException exc ) { - final String message =3D - 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( exc ); } + + // Set the child element + childConfigurer.addValue( state, child ); } =20 /** * 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 =3D element.getName(); @@ -277,33 +315,23 @@ } =20 // Set the property - setReference( configurer, object, name, id, context ); + setReference( state, name, id, context ); } =20 /** * 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 =3D = configurer.getProperty( name ); - if( null =3D=3D childConfigurer ) - { - final String message =3D REZ.getString( = "unknown-property.error", name ); - throw new ConfigurationException( message ); - } + final PropertyConfigurer childConfigurer =3D = state.getConfigurer().getProperty( name ); =20 - // Check if the creator method must be used - if( childConfigurer.useCreator() ) - { - final String message =3D REZ.getString( = "must-be-element.error" ); - throw new ConfigurationException( message ); - } + // Resolve any props in the id + Object id =3D PropertyUtil.resolveProperty( unresolvedId, = context, false ); =20 // Locate the referenced object Object ref =3D null; @@ -311,77 +339,44 @@ { ref =3D context.get( id ); } - catch( final ContextException ce ) + catch( final ContextException exc ) { - final String message =3D REZ.getString( "get-ref.error", = id, name ); - throw new ConfigurationException( message, ce ); + final String message =3D REZ.getString( "get-ref.error", id = ); + throw new ConfigurationException( message, exc ); } =20 // Check the types final Class type =3D childConfigurer.getType(); if( !type.isInstance( ref ) ) { - final String message =3D REZ.getString( = "mismatch-ref-types.error", id, name ); + final String message =3D REZ.getString( = "mismatch-ref-types.error", id, type.getName(), ref.getClass().getName() = ); throw new ConfigurationException( message ); } =20 // Set the child element - try - { - childConfigurer.setValue( object, ref ); - } - catch( final ConfigurationException ce ) - { - final String message =3D - REZ.getString( "bad-set-property.error", name ); - throw new ConfigurationException( message, ce ); - } + childConfigurer.addValue( state, ref ); } =20 /** * 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 =3D REZ.getString( = "configure-attribute.notice", - name, - value ); - getLogger().debug( message ); - } - - if( name.endsWith( "-ref" ) ) + if( name.toLowerCase().endsWith( "-ref" ) ) { // A reference final String refName =3D 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 =3D = configurer.getProperty( name ); - if( null =3D=3D propConfigurer ) - { - final String message =3D 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 =3D REZ.getString( = "bad-set-property.error", name ); - throw new ConfigurationException( message, e ); - } + final PropertyConfigurer propConfigurer =3D = state.getConfigurer().getProperty( name ); + setValue( propConfigurer, state, value, context ); } } =20 @@ -389,18 +384,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 =3D REZ.getString( = "must-be-element.error" ); - throw new ConfigurationException( message ); - } - // Resolve property references in the attribute value Object objValue =3D PropertyUtil.resolveProperty( value, = context, false ); =20 @@ -409,7 +397,7 @@ objValue =3D m_converter.convert( clazz, objValue, context ); =20 // Set the value - setter.setValue( object, objValue ); + setter.addValue( state, objValue ); } =20 /** Index: = proposal/myrmidon/src/java/org/apache/myrmidon/components/configurer/Defa= ultObjectConfigurer.java =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D RCS file: = /home/cvspublic/jakarta-ant/proposal/myrmidon/src/java/org/apache/myrmido= n/components/configurer/DefaultObjectConfigurer.java,v retrieving revision 1.3 diff -u -r1.3 DefaultObjectConfigurer.java --- = proposal/myrmidon/src/java/org/apache/myrmidon/components/configurer/Defa= ultObjectConfigurer.java 20 Jan 2002 17:32:57 -0000 1.3 +++ = proposal/myrmidon/src/java/org/apache/myrmidon/components/configurer/Defa= ultObjectConfigurer.java 22 Jan 2002 04:41:54 -0000 @@ -7,20 +7,19 @@ */ package org.apache.myrmidon.components.configurer; =20 -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; =20 /** * An object configurer which uses reflection to determine the = properties @@ -43,6 +42,11 @@ private final Map m_props =3D new HashMap(); =20 /** + * All property configurers. + */ + private final List m_allProps =3D new ArrayList(); + + /** * Content configurer. */ private PropertyConfigurer m_contentConfigurer; @@ -101,8 +105,8 @@ { final String message =3D REZ.getString( = "incompatible-element-types.error", - propName, - m_class.getName() ); + m_class.getName(), + propName ); throw new ConfigurationException( message ); } } @@ -115,9 +119,21 @@ type =3D addMethod.getParameterTypes()[ 0 ]; } =20 + // Determine the max count for the property + int maxCount =3D Integer.MAX_VALUE; + if( addMethod !=3D null && = addMethod.getName().startsWith("set") ) + { + maxCount =3D 1; + } + final DefaultPropertyConfigurer configurer =3D - new DefaultPropertyConfigurer( type, createMethod, = addMethod ); + new DefaultPropertyConfigurer( m_allProps.size(), + type, + createMethod, + addMethod, + maxCount ); m_props.put( propName, configurer ); + m_allProps.add( configurer ); } } =20 @@ -138,8 +154,8 @@ { final Method method =3D (Method)iterator.next(); final String methodName =3D method.getName(); - if( method.getReturnType() !=3D Void.TYPE || - method.getParameterTypes().length !=3D 1 ) + if( method.getReturnType() !=3D Void.TYPE + || method.getParameterTypes().length !=3D 1 ) { continue; } @@ -150,19 +166,37 @@ continue; } =20 - // Extract element name - final String elemName =3D extractName( 3, methodName ); + // Extract property name + final String propName =3D extractName( 3, methodName ); + + final Class type =3D method.getParameterTypes()[0]; =20 // Add to the adders map - if( adders.containsKey( elemName ) ) + if( adders.containsKey( propName ) ) { - final String message =3D - REZ.getString( = "multiple-adder-methods-for-element.error", - m_class.getName(), - elemName ); - throw new ConfigurationException( message ); + final Class currentType =3D ((Method)adders.get( = propName )).getParameterTypes()[0]; + + // Ditch the string version, if any + if( currentType !=3D String.class && type =3D=3D = String.class ) + { + // New type is string, and current type is not. = Ignore + // the new method + continue; + } + if( currentType !=3D String.class || type =3D=3D = String.class ) + { + // Both are string, or both are not string + final String message =3D + 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; } @@ -236,7 +270,12 @@ } =20 Class type =3D method.getParameterTypes()[0]; - m_contentConfigurer =3D new DefaultPropertyConfigurer( = type, null, method ); + m_contentConfigurer =3D new DefaultPropertyConfigurer( = m_allProps.size(), + type, + null, + = method, + 1 ); + m_allProps.add( m_contentConfigurer ); } } =20 @@ -252,27 +291,64 @@ } =20 /** - * 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( ConfigurationState state ) + throws ConfigurationException + { + // Make sure there are no pending created objects + DefaultConfigurationState defState =3D = (DefaultConfigurationState)state; + for( int i =3D 0; i < m_allProps.size(); i++ ) + { + if( defState.getCreatedObject( i ) !=3D null ) + { + final String message =3D REZ.getString( = "pending-property-value.error" ); + throw new ConfigurationException( message ); + } + } + + return defState.getObject(); } =20 /** * 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 ); + PropertyConfigurer prop =3D (PropertyConfigurer)m_props.get( = name ); + if( prop !=3D null ) + { + return prop; + } + + // Unknown property + final String message =3D REZ.getString( = "unknown-property.error", m_class.getName(), name ); + throw new NoSuchPropertyException( message ); } =20 /** * Returns a configurer for the content of this class. */ - public PropertyConfigurer getContentConfigurer() + public PropertyConfigurer getContentConfigurer() throws = NoSuchPropertyException { - return m_contentConfigurer; + if( m_contentConfigurer !=3D null ) + { + return m_contentConfigurer; + } + + // Does not handle content + final String message =3D REZ.getString( = "content-unsupported.error", m_class.getName() ); + throw new NoSuchPropertyException( message ); } =20 /** Index: = proposal/myrmidon/src/java/org/apache/myrmidon/components/configurer/Defa= ultPropertyConfigurer.java =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D RCS file: = /home/cvspublic/jakarta-ant/proposal/myrmidon/src/java/org/apache/myrmido= n/components/configurer/DefaultPropertyConfigurer.java,v retrieving revision 1.2 diff -u -r1.2 DefaultPropertyConfigurer.java --- = proposal/myrmidon/src/java/org/apache/myrmidon/components/configurer/Defa= ultPropertyConfigurer.java 20 Jan 2002 17:32:57 -0000 1.2 +++ = proposal/myrmidon/src/java/org/apache/myrmidon/components/configurer/Defa= ultPropertyConfigurer.java 22 Jan 2002 04:41:55 -0000 @@ -7,13 +7,12 @@ */ package org.apache.myrmidon.components.configurer; =20 +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; =20 -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; - /** * The default property configurer implementation, which uses = reflection to * create and set property values. @@ -27,21 +26,30 @@ private final static Resources REZ =3D ResourceManager.getPackageResources( = DefaultPropertyConfigurer.class ); =20 + 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; =20 - 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 =3D propIndex; if ( type.isPrimitive() ) { - type =3D getComplexTypeFor(type); + m_type =3D getComplexTypeFor(type); + } + else + { + m_type =3D type; } - m_type =3D type; m_createMethod =3D createMethod; m_addMethod =3D addMethod; + m_maxCount =3D maxCount; } =20 /** @@ -53,29 +61,31 @@ } =20 /** - * Determines if the property value must be created via {@link = #createValue}. - */ - public boolean useCreator() - { - return (m_createMethod !=3D 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 =3D=3D m_createMethod ) + { + return null; + } + + final DefaultConfigurationState defState =3D = (DefaultConfigurationState)state; + + // Make sure there isn't a pending object for this property + if( defState.getCreatedObject( m_propIndex ) !=3D null ) + { + final String message =3D REZ.getString( = "pending-property-value.error" ); + throw new ConfigurationException( message ); + } + try { - if( null !=3D m_createMethod ) - { - return m_createMethod.invoke( parent, null ); - } - else - { - return m_type.newInstance(); - } + // Create the value + final Object object =3D m_createMethod.invoke( = defState.getObject(), null ); + defState.setCreatedObject( m_propIndex, object ); + return object; } catch( final InvocationTargetException ite ) { @@ -89,16 +99,42 @@ } =20 /** - * 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 =3D = (DefaultConfigurationState)state; + + // Make sure the supplied object is the pending object + final Object pending =3D defState.getCreatedObject( m_propIndex = ); + if( pending !=3D null && pending !=3D value ) + { + } + + // Make sure the creator method was called, if necessary + if( pending =3D=3D null && m_createMethod !=3D null ) + { + final String message =3D REZ.getString( = "must-be-element.error" ); + throw new ConfigurationException( message ); + } + + defState.setCreatedObject( m_propIndex, null ); + + // Check the property count + if( defState.getPropCount( m_propIndex ) >=3D m_maxCount ) + { + final String message =3D REZ.getString( = "too-many-values.error" ); + throw new ConfigurationException( message ); + } + defState.incPropCount( m_propIndex ); + try { + // Add the value if( null !=3D m_addMethod ) { - m_addMethod.invoke( parent, new Object[]{child} ); + m_addMethod.invoke( defState.getObject(), new Object[]{ = value } ); } } catch( final InvocationTargetException ite ) Index: = proposal/myrmidon/src/java/org/apache/myrmidon/components/configurer/Obje= ctConfigurer.java =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D RCS file: = /home/cvspublic/jakarta-ant/proposal/myrmidon/src/java/org/apache/myrmido= n/components/configurer/ObjectConfigurer.java,v retrieving revision 1.2 diff -u -r1.2 ObjectConfigurer.java --- = proposal/myrmidon/src/java/org/apache/myrmidon/components/configurer/Obje= ctConfigurer.java 14 Jan 2002 09:31:22 -0000 1.2 +++ = proposal/myrmidon/src/java/org/apache/myrmidon/components/configurer/Obje= ctConfigurer.java 22 Jan 2002 04:41:55 -0000 @@ -7,6 +7,8 @@ */ package org.apache.myrmidon.components.configurer; =20 +import = org.apache.avalon.framework.configuration.ConfigurationException; + /** * Configures objects of a particular class. * @@ -16,24 +18,53 @@ 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; =20 /** * 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; =20 /** * 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; } Index: = proposal/myrmidon/src/java/org/apache/myrmidon/components/configurer/Prop= ertyConfigurer.java =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D RCS file: = /home/cvspublic/jakarta-ant/proposal/myrmidon/src/java/org/apache/myrmido= n/components/configurer/PropertyConfigurer.java,v retrieving revision 1.1 diff -u -r1.1 PropertyConfigurer.java --- = proposal/myrmidon/src/java/org/apache/myrmidon/components/configurer/Prop= ertyConfigurer.java 14 Jan 2002 09:31:22 -0000 1.1 +++ = proposal/myrmidon/src/java/org/apache/myrmidon/components/configurer/Prop= ertyConfigurer.java 22 Jan 2002 04:41:55 -0000 @@ -19,36 +19,32 @@ public interface PropertyConfigurer { /** - * Returns the type of the property. + * Returns the type of this property. */ Class getType(); =20 /** - * 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; =20 /** - * 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; } Index: = proposal/myrmidon/src/java/org/apache/myrmidon/components/configurer/Reso= urces.properties =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D RCS file: = /home/cvspublic/jakarta-ant/proposal/myrmidon/src/java/org/apache/myrmido= n/components/configurer/Resources.properties,v retrieving revision 1.4 diff -u -r1.4 Resources.properties --- = proposal/myrmidon/src/java/org/apache/myrmidon/components/configurer/Reso= urces.properties 14 Jan 2002 09:31:22 -0000 1.4 +++ = proposal/myrmidon/src/java/org/apache/myrmidon/components/configurer/Reso= urces.properties 22 Jan 2002 04:41:55 -0000 @@ -1,20 +1,21 @@ -configuring-object.notice=3DConfiguring {0}. -configurable.notice=3DConfiguring object via Configurable interface. -reflection.notice=3DConfiguring object via ObjectConfigurer. -configure-content.notice=3DConfiguring content with "{0}". -configure-subelement.notice=3DConfiguring subelement "{0}". -configure-attribute.notice=3DConfiguring attribute name=3D"{0}" = value=3D"{1}". - -content-not-supported.error=3DText content is not supported for this = element. -bad-set-content.error=3DCould not set text content. -unknown-property.error=3DUnknown property "{0}". -bad-set-property.error=3DCould not set property "{0}". -no-complex-type.error=3DCan not get complex type for non-primitive type = {0}. +create-object.error=3DCould not create an object of class {0}. extra-config-for-ref.error=3DA reference element can only include an = "id" attribute. -get-ref.error=3DCould not locate reference "{0}" for element "{1}". -mismatch-ref-types.error=3DMismatched type for reference "{0}" for = element "{1}". -multiple-creator-methods-for-element.error=3DMultiple creator methods = found in class {0} for property "{0}". -multiple-adder-methods-for-element.error=3DMultiple adder/setter = methods found in class {0} for property "{0}". -incompatible-element-types.error=3DIncompatible creator and = adder/setter types for property "{0}" of class {1}. +get-ref.error=3DCould not locate reference "{0}". +mismatch-ref-types.error=3DMismatched type for reference "{0}". Was = expecting an object of type {1}, instead found an object of type {2}. +incompatible-element-types.error=3DIncompatible creator and = adder/setter methods found in class {0} for property "{1}". +multiple-adder-methods-for-element.error=3DMultiple adder/setter = methods found in class {0} for property "{1}". +multiple-creator-methods-for-element.error=3DMultiple creator methods = found in class {0} for property "{1}". multiple-content-setter-methods.error=3DMultiple content setter methods = found in class {0}. -must-be-element.error=3DThis property must be configured using a nested = element. \ No newline at end of file +pending-property-value.error=3DAn object created using the creator = method has not been set using the adder/setter method. +unknown-property.error=3DClass {0} does not have a "{1}" property. +content-not-supported.error=3DClass {0} does not support text content. +must-be-element.error=3DThis property must be configured using a nested = element. +too-many-values.error=3DToo many values for this property. +no-complex-type.error=3DCan not get complex type for non-primitive type = {0}. +no-such-attribute.error=3DAttribute "{1}" is not allowed for element = <{0}>. +bad-set-attribute.error=3DCould not set attribute "{1}" for element = <{0}>. +bad-set-class-attribute.error=3DCould not set attribute "{0}" for = object of class {1}. +no-such-element.error=3DNested <{1}> elements are not allowed for = element <{0}>. +bad-set-element.error=3DCould not handle element <{1}>, nested in = element <{0}>. +no-content.error=3DText content is not allowed for element <{0}>. +bad-set-content.error=3DCould not set text content for element <{0}>. ------=_NextPart_000_0004_01C1A356.98AB1B70 Content-Type: application/x-zip-compressed; name="newfiles.zip" Content-Transfer-Encoding: base64 Content-Disposition: attachment; filename="newfiles.zip" UEsDBAoAAAAAAKeqNSwAAAAAAAAAAAAAAAAEAAAAc3JjL1BLAwQKAAAAAABwhDUsAAAAAAAAAAAA AAAACQAAAHNyYy9qYXZhL1BLAwQKAAAAAABwhDUsAAAAAAAAAAAAAAAADQAAAHNyYy9qYXZhL29y Zy9QSwMECgAAAAAAhoQ1LAAAAAAAAAAAAAAAABQAAABzcmMvamF2YS9vcmcvYXBhY2hlL1BLAwQK AAAAAACGhDUsAAAAAAAAAAAAAAAAHQAAAHNyYy9qYXZhL29yZy9hcGFjaGUvbXlybWlkb24vUEsD BAoAAAAAAIaENSwAAAAAAAAAAAAAAAAoAAAAc3JjL2phdmEvb3JnL2FwYWNoZS9teXJtaWRvbi9j b21wb25lbnRzL1BLAwQKAAAAAABcPDYsAAAAAAAAAAAAAAAAMwAAAHNyYy9qYXZhL29yZy9hcGFj aGUvbXlybWlkb24vY29tcG9uZW50cy9jb25maWd1cmVyL1BLAwQKAAAAAAA1qzUsAAAAAAAAAAAA AAAADgAAAHNyYy90ZXN0Y2FzZXMvUEsDBAoAAAAAADWrNSwAAAAAAAAAAAAAAAASAAAAc3JjL3Rl c3RjYXNlcy9vcmcvUEsDBAoAAAAAADWrNSwAAAAAAAAAAAAAAAAZAAAAc3JjL3Rlc3RjYXNlcy9v cmcvYXBhY2hlL1BLAwQKAAAAAAA1qzUsAAAAAAAAAAAAAAAAIgAAAHNyYy90ZXN0Y2FzZXMvb3Jn L2FwYWNoZS9teXJtaWRvbi9QSwMECgAAAAAANas1LAAAAAAAAAAAAAAAAC0AAABzcmMvdGVzdGNh c2VzL29yZy9hcGFjaGUvbXlybWlkb24vY29tcG9uZW50cy9QSwMECgAAAAAArG42LAAAAAAAAAAA AAAAADgAAABzcmMvdGVzdGNhc2VzL29yZy9hcGFjaGUvbXlybWlkb24vY29tcG9uZW50cy9jb25m aWd1cmVyL1BLAwQUAAgACADtdDYsAAAAAAAAAAAAAAAASgAAAHNyYy9qYXZhL29yZy9hcGFjaGUv bXlybWlkb24vY29tcG9uZW50cy9jb25maWd1cmVyL0NvbmZpZ3VyYXRpb25TdGF0ZS5qYXZhXVHN TsMwDL5X6jv4uFWo1c5cqCqQkAZIbC+Qpm4T1iZV4mxMiHfHSRmbyCVOYn9/qYo8gwIaO5+dHhTB qlnDXiHUs5C87WxPJ+EQnmwwnSBtTQn1OELq9uDQoztiV0aYBLVX2oO/jHE9h3bUXmEHjIAOiGEJ 3eTB9unwn2qrJRqPCe2IzjMnbMrNHQiQrDOOnZSWCpTw0CIa0EaOoWMGOGlSDMq0nfbkdBuiZG5I aJFt+9w8vu4eS/ok6PWISXmVZyziIAYE64ZSJEXldHaT7tixtNNsDRryXJpeD8Ghu8+zPKuKxXUN k3AHdqcNe+uFZI9KEOczx4h4MpF7EoTRgDBg2w+UFK2MnBPFqFrUZkh4fzQ3yT6IQMo6qDsxwUtw nZXqIj5mLG/Im9/59GO7yJpnX9zMa5EcVwHvSMGZRdvV2aIDgudEyV4fUtsiu7xAVEvxlm6bK8SA N6fVmsP6zrMfUEsHCC1cUbViAQAAbgIAAFBLAwQUAAgACADtdDYsAAAAAAAAAAAAAAAAUQAAAHNy Yy9qYXZhL29yZy9hcGFjaGUvbXlybWlkb24vY29tcG9uZW50cy9jb25maWd1cmVyL0RlZmF1bHRD b25maWd1cmF0aW9uU3RhdGUuamF2YZVU227bMAx9D5B/4NvSNHDQ52LAAq8DinVbsfStKAbFYmKt tmRIctKg2L+PknxtnLQxAsQX8vDwHIrz6XgEU4hVsddik1qYxBfwkCIsCpbQ31Kt7Y5phG+qlJxZ oWQEiywDH21Ao0G9RR45GA/1kAoDpk6j+6JcZcKkyIEQUIMlWIs6N6DW/uFtqTuRoDTo0baoDdWE q+hqBgwS4unSdqlIUkiZgRWiBCGTrORUAXbCpgRKZbkwVotV6ShTgEdz1e5u45ufy5vIvlhYiww9 8/l4RCSe2QZB6U3EPKMo3+tccOo4UXmhJEpr6FauxabUqK/Ho/FoPg1dL4DjmpWZhTrAawXGMksq 5EWGOeVXAsJ3xMKA1VSzacfjVJKo1V9M7CcST6sCtRVoqNsthnYNWsJYZEbBcx+IcgOMzzeQaKT6 HFZ7D+sflYYcbaq4mQHJA1JZ2KN1qHUc42SUB6oiW3u/sJLeaFhwlsOPUnMVmDsFndEJJBkzBr4G OeKuGksnBgXT1ShiYCjkNUSthWQZaSC2XkVpH58g/+M0iWkc7fVQ1C/fug+sug9vzInouDHVZXUd PpZBcUFjPwUuqur+aN+TCuegYltvFpDev7pIlddn5pKWIMv8nqQ0cBFyX1uIrgrwGQ4kCTGhMn1v pGi/NSbRZ4k7b15b8akX2/epSqh8PMz5Vysezp67pvAbbamlCVPeUl+hkBsoDR0Bq9oPnTMW1RDz no0HLm2w8zQ5VEx7AkPj0+Xb41nJFzg2aTwa5uIYhLtT1XtODFZm9U7ZU03y56CcGw2qdV8bOOmM jEu9pS3+MjAzDYfG+sdO/JB7cCvJ+rAF3qW1VYK7RX82r2OELi8/JpPbwii5M6laqyccirujfLZy /YPwrnxLtGcS9SKaj9CcDS2Z4U1xnPTb1UDs6fcfUEsHCF2+daW0AgAAdAgAAFBLAwQUAAgACADt dDYsAAAAAAAAAAAAAAAATwAAAHNyYy9qYXZhL29yZy9hcGFjaGUvbXlybWlkb24vY29tcG9uZW50 cy9jb25maWd1cmVyL05vU3VjaFByb3BlcnR5RXhjZXB0aW9uLmphdmF1UdFu2zAMfDfgf+BjGnQO +tyXBlkGDOjaAekPKBJtCZElg5TiBsP+fZSdNN3aCQYsgbzj8W61rCtYwiYOJ3KdTbDY3MCLRVgP SstvF9s0KkL4FnMwKrkYGlh7D1M3AyEjHdE0hWaierGOgS8wuQ957x1bNCAMSJCENiH1DLGdHv+O enQaA+PEdkRimQl3zd0tKNCis8BG67QFqxj2iAFc0D4bmQCjS1ZIZaxxnMjtc5EsDRNbmfb4fbN9 2m2b9JqgdR4n5au6EhEH1SFE6ho1KWr6E/XOyMY69kMMGBLLNbSuy4R0X1d15aRA6T1IHZUXSEuq xzHSodko1sq40G1fNQ5FzoRcLWe/1gHwUhCBFMcg68lSKohhh1DeA8UBKZ2KnRi0RCEG/mX689dn +DIvzjZmb4Q0YTCS7Kx3iu5NwS3YOKKYe07/s54yrHVB+euYB5WTjQRro3r4kclEbS/2lZQ1aK+Y 4SnusrY/z6qvjLMmho+W1NUvIZJz5vkPwwJ2EmrooEfmktbNjDqDy+EskMW14X4u/a4r+f4AUEsH CEQ6f1OcAQAA7wIAAFBLAwQUAAgACADtdDYsAAAAAAAAAAAAAAAASAAAAHNyYy90ZXN0Y2FzZXMv b3JnL2FwYWNoZS9teXJtaWRvbi9jb21wb25lbnRzL2NvbmZpZ3VyZXIvQ29uZmlnVGVzdDEuamF2 Ya1S26rbMBB8N/gftm9OODjkOQQa0lMopBdI3otsrW2lsuTqkjSU8+9d+RpMOIfSikBkaXZmdlar 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 /PRCfx46sN5tvlxmSJFn19CF50likq2+FhLyWcFCzq/dg2pHy37L/BcDiSl08bua9hPbcyEShpa1 qzAr/2iewYt+r3Zh0KIG/D5F9MnBgRaX/PgjghVn3cVXQvaWYGKZs/a6XqP7559r0R3DcjoIWwjR D4tVi4FvKPjzP1BLBwiebBfMywoAALFFAABQSwECFAAKAAAAAACnqjUsAAAAAAAAAAAAAAAABAAA AAAAAAAAABAA/UEAAAAAc3JjL1BLAQIUAAoAAAAAAHCENSwAAAAAAAAAAAAAAAAJAAAAAAAAAAAA EAD9QSIAAABzcmMvamF2YS9QSwECFAAKAAAAAABwhDUsAAAAAAAAAAAAAAAADQAAAAAAAAAAABAA /UFJAAAAc3JjL2phdmEvb3JnL1BLAQIUAAoAAAAAAIaENSwAAAAAAAAAAAAAAAAUAAAAAAAAAAAA EAD9QXQAAABzcmMvamF2YS9vcmcvYXBhY2hlL1BLAQIUAAoAAAAAAIaENSwAAAAAAAAAAAAAAAAd AAAAAAAAAAAAEAD9QaYAAABzcmMvamF2YS9vcmcvYXBhY2hlL215cm1pZG9uL1BLAQIUAAoAAAAA AIaENSwAAAAAAAAAAAAAAAAoAAAAAAAAAAAAEAD9QeEAAABzcmMvamF2YS9vcmcvYXBhY2hlL215 cm1pZG9uL2NvbXBvbmVudHMvUEsBAhQACgAAAAAAXDw2LAAAAAAAAAAAAAAAADMAAAAAAAAAAAAQ AP1BJwEAAHNyYy9qYXZhL29yZy9hcGFjaGUvbXlybWlkb24vY29tcG9uZW50cy9jb25maWd1cmVy L1BLAQIUAAoAAAAAADWrNSwAAAAAAAAAAAAAAAAOAAAAAAAAAAAAEAD9QXgBAABzcmMvdGVzdGNh c2VzL1BLAQIUAAoAAAAAADWrNSwAAAAAAAAAAAAAAAASAAAAAAAAAAAAEAD9QaQBAABzcmMvdGVz dGNhc2VzL29yZy9QSwECFAAKAAAAAAA1qzUsAAAAAAAAAAAAAAAAGQAAAAAAAAAAABAA/UHUAQAA c3JjL3Rlc3RjYXNlcy9vcmcvYXBhY2hlL1BLAQIUAAoAAAAAADWrNSwAAAAAAAAAAAAAAAAiAAAA AAAAAAAAEAD9QQsCAABzcmMvdGVzdGNhc2VzL29yZy9hcGFjaGUvbXlybWlkb24vUEsBAhQACgAA AAAANas1LAAAAAAAAAAAAAAAAC0AAAAAAAAAAAAQAP1BSwIAAHNyYy90ZXN0Y2FzZXMvb3JnL2Fw YWNoZS9teXJtaWRvbi9jb21wb25lbnRzL1BLAQIUAAoAAAAAAKxuNiwAAAAAAAAAAAAAAAA4AAAA AAAAAAAAEAD9QZYCAABzcmMvdGVzdGNhc2VzL29yZy9hcGFjaGUvbXlybWlkb24vY29tcG9uZW50 cy9jb25maWd1cmVyL1BLAQIUABQACAAIAO10NiwtXFG1YgEAAG4CAABKAAAAAAAAAAAAAAAAAOwC AABzcmMvamF2YS9vcmcvYXBhY2hlL215cm1pZG9uL2NvbXBvbmVudHMvY29uZmlndXJlci9Db25m aWd1cmF0aW9uU3RhdGUuamF2YVBLAQIUABQACAAIAO10NixdvnWltAIAAHQIAABRAAAAAAAAAAAA AAAAAMYEAABzcmMvamF2YS9vcmcvYXBhY2hlL215cm1pZG9uL2NvbXBvbmVudHMvY29uZmlndXJl ci9EZWZhdWx0Q29uZmlndXJhdGlvblN0YXRlLmphdmFQSwECFAAUAAgACADtdDYsRDp/U5wBAADv AgAATwAAAAAAAAAAAAAAAAD5BwAAc3JjL2phdmEvb3JnL2FwYWNoZS9teXJtaWRvbi9jb21wb25l bnRzL2NvbmZpZ3VyZXIvTm9TdWNoUHJvcGVydHlFeGNlcHRpb24uamF2YVBLAQIUABQACAAIAO10 Niyjdhi0BgIAADIFAABIAAAAAAAAAAAAAAAAABIKAABzcmMvdGVzdGNhc2VzL29yZy9hcGFjaGUv bXlybWlkb24vY29tcG9uZW50cy9jb25maWd1cmVyL0NvbmZpZ1Rlc3QxLmphdmFQSwECFAAUAAgA CADtdDYsJrDtxuABAAA2BAAASAAAAAAAAAAAAAAAAACODAAAc3JjL3Rlc3RjYXNlcy9vcmcvYXBh Y2hlL215cm1pZG9uL2NvbXBvbmVudHMvY29uZmlndXJlci9Db25maWdUZXN0Mi5qYXZhUEsBAhQA FAAIAAgA7XQ2LAtudvZnAgAAQQcAAEgAAAAAAAAAAAAAAAAA5A4AAHNyYy90ZXN0Y2FzZXMvb3Jn L2FwYWNoZS9teXJtaWRvbi9jb21wb25lbnRzL2NvbmZpZ3VyZXIvQ29uZmlnVGVzdDMuamF2YVBL AQIUABQACAAIAO10NiyebBfMywoAALFFAABSAAAAAAAAAAAAAAAAAMERAABzcmMvdGVzdGNhc2Vz L29yZy9hcGFjaGUvbXlybWlkb24vY29tcG9uZW50cy9jb25maWd1cmVyL0RlZmF1bHRDb25maWd1 cmVyVGVzdC5qYXZhUEsFBgAAAAAUABQAEgcAAAwdAAAAAA== ------=_NextPart_000_0004_01C1A356.98AB1B70 Content-Type: text/plain; charset=us-ascii -- To unsubscribe, e-mail: For additional commands, e-mail: ------=_NextPart_000_0004_01C1A356.98AB1B70--