git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@270194 13f79535-47bb-0310-9956-ffa450edef68master
| @@ -1,854 +0,0 @@ | |||
| /* | |||
| * 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 file. | |||
| */ | |||
| package org.apache.tools.ant; | |||
| import java.io.File; | |||
| import java.lang.reflect.Constructor; | |||
| import java.lang.reflect.InvocationTargetException; | |||
| import java.lang.reflect.Method; | |||
| import java.util.Enumeration; | |||
| import java.util.Hashtable; | |||
| import java.util.Locale; | |||
| import org.apache.myrmidon.api.TaskException; | |||
| import org.apache.tools.ant.types.EnumeratedAttribute; | |||
| import org.apache.tools.ant.types.Path; | |||
| import org.apache.tools.ant.util.FileUtils; | |||
| /** | |||
| * Helper class that collects the methods a task or nested element holds to set | |||
| * attributes, create nested elements or hold PCDATA elements. | |||
| * | |||
| * @author <a href="mailto:stefan.bodewig@epost.de">Stefan Bodewig</a> | |||
| */ | |||
| public class IntrospectionHelper implements BuildListener | |||
| { | |||
| /** | |||
| * instances we've already created | |||
| */ | |||
| private static Hashtable helpers = new Hashtable(); | |||
| /** | |||
| * The method to add PCDATA stuff. | |||
| */ | |||
| private Method addText = null; | |||
| /** | |||
| * holds the attribute setter methods. | |||
| */ | |||
| private Hashtable attributeSetters; | |||
| /** | |||
| * holds the types of the attributes that could be set. | |||
| */ | |||
| private Hashtable attributeTypes; | |||
| /** | |||
| * The Class that's been introspected. | |||
| */ | |||
| private Class bean; | |||
| /** | |||
| * Holds methods to create nested elements. | |||
| */ | |||
| private Hashtable nestedCreators; | |||
| /** | |||
| * Holds methods to store configured nested elements. | |||
| */ | |||
| private Hashtable nestedStorers; | |||
| /** | |||
| * Holds the types of nested elements that could be created. | |||
| */ | |||
| private Hashtable nestedTypes; | |||
| private IntrospectionHelper( final Class bean ) | |||
| throws TaskException | |||
| { | |||
| attributeTypes = new Hashtable(); | |||
| attributeSetters = new Hashtable(); | |||
| nestedTypes = new Hashtable(); | |||
| nestedCreators = new Hashtable(); | |||
| nestedStorers = new Hashtable(); | |||
| this.bean = bean; | |||
| Method[] methods = bean.getMethods(); | |||
| for( int i = 0; i < methods.length; i++ ) | |||
| { | |||
| final Method m = methods[ i ]; | |||
| final String name = m.getName(); | |||
| Class returnType = m.getReturnType(); | |||
| Class[] args = m.getParameterTypes(); | |||
| // hide addTask for TaskContainers | |||
| if( org.apache.tools.ant.TaskContainer.class.isAssignableFrom( bean ) | |||
| && args.length == 1 && "addTask".equals( name ) | |||
| && org.apache.tools.ant.Task.class.equals( args[ 0 ] ) ) | |||
| { | |||
| continue; | |||
| } | |||
| if( "addText".equals( name ) | |||
| && java.lang.Void.TYPE.equals( returnType ) | |||
| && args.length == 1 | |||
| && java.lang.String.class.equals( args[ 0 ] ) ) | |||
| { | |||
| addText = methods[ i ]; | |||
| } | |||
| else if( name.startsWith( "set" ) | |||
| && java.lang.Void.TYPE.equals( returnType ) | |||
| && args.length == 1 | |||
| && !args[ 0 ].isArray() ) | |||
| { | |||
| String propName = getPropertyName( name, "set" ); | |||
| if( attributeSetters.get( propName ) != null ) | |||
| { | |||
| if( java.lang.String.class.equals( args[ 0 ] ) ) | |||
| { | |||
| /* | |||
| * Ignore method m, as there is an overloaded | |||
| * form of this method that takes in a | |||
| * non-string argument, which gains higher | |||
| * priority. | |||
| */ | |||
| continue; | |||
| } | |||
| /* | |||
| * If the argument is not a String, and if there | |||
| * is an overloaded form of this method already defined, | |||
| * we just override that with the new one. | |||
| * This mechanism does not guarantee any specific order | |||
| * in which the methods will be selected: so any code | |||
| * that depends on the order in which "set" methods have | |||
| * been defined, is not guaranteed to be selected in any | |||
| * particular order. | |||
| */ | |||
| } | |||
| AttributeSetter as = createAttributeSetter( m, args[ 0 ] ); | |||
| if( as != null ) | |||
| { | |||
| attributeTypes.put( propName, args[ 0 ] ); | |||
| attributeSetters.put( propName, as ); | |||
| } | |||
| } | |||
| else if( name.startsWith( "create" ) | |||
| && !returnType.isArray() | |||
| && !returnType.isPrimitive() | |||
| && args.length == 0 ) | |||
| { | |||
| String propName = getPropertyName( name, "create" ); | |||
| nestedTypes.put( propName, returnType ); | |||
| nestedCreators.put( propName, | |||
| new NestedCreator() | |||
| { | |||
| public Object create( Object parent ) | |||
| throws InvocationTargetException, | |||
| IllegalAccessException | |||
| { | |||
| return m.invoke( parent, new Object[]{} ); | |||
| } | |||
| } ); | |||
| } | |||
| else if( name.startsWith( "addConfigured" ) | |||
| && java.lang.Void.TYPE.equals( returnType ) | |||
| && args.length == 1 | |||
| && !java.lang.String.class.equals( args[ 0 ] ) | |||
| && !args[ 0 ].isArray() | |||
| && !args[ 0 ].isPrimitive() ) | |||
| { | |||
| try | |||
| { | |||
| final Constructor c = | |||
| args[ 0 ].getConstructor( new Class[]{} ); | |||
| String propName = getPropertyName( name, "addConfigured" ); | |||
| nestedTypes.put( propName, args[ 0 ] ); | |||
| nestedCreators.put( propName, | |||
| new NestedCreator() | |||
| { | |||
| public Object create( Object parent ) | |||
| throws InvocationTargetException, IllegalAccessException, InstantiationException | |||
| { | |||
| Object o = c.newInstance( new Object[]{} ); | |||
| return o; | |||
| } | |||
| } ); | |||
| nestedStorers.put( propName, | |||
| new NestedStorer() | |||
| { | |||
| public void store( Object parent, Object child ) | |||
| throws InvocationTargetException, IllegalAccessException, InstantiationException | |||
| { | |||
| m.invoke( parent, new Object[]{child} ); | |||
| } | |||
| } ); | |||
| } | |||
| catch( NoSuchMethodException nse ) | |||
| { | |||
| } | |||
| } | |||
| else if( name.startsWith( "add" ) | |||
| && java.lang.Void.TYPE.equals( returnType ) | |||
| && args.length == 1 | |||
| && !java.lang.String.class.equals( args[ 0 ] ) | |||
| && !args[ 0 ].isArray() | |||
| && !args[ 0 ].isPrimitive() ) | |||
| { | |||
| try | |||
| { | |||
| final Constructor c = | |||
| args[ 0 ].getConstructor( new Class[]{} ); | |||
| String propName = getPropertyName( name, "add" ); | |||
| nestedTypes.put( propName, args[ 0 ] ); | |||
| nestedCreators.put( propName, | |||
| new NestedCreator() | |||
| { | |||
| public Object create( Object parent ) | |||
| throws InvocationTargetException, IllegalAccessException, InstantiationException | |||
| { | |||
| Object o = c.newInstance( new Object[]{} ); | |||
| m.invoke( parent, new Object[]{o} ); | |||
| return o; | |||
| } | |||
| } ); | |||
| } | |||
| catch( NoSuchMethodException nse ) | |||
| { | |||
| } | |||
| } | |||
| } | |||
| } | |||
| /** | |||
| * Factory method for helper objects. | |||
| * | |||
| * @param c Description of Parameter | |||
| * @return The Helper value | |||
| */ | |||
| public static synchronized IntrospectionHelper getHelper( Class c ) | |||
| { | |||
| IntrospectionHelper ih = (IntrospectionHelper)helpers.get( c ); | |||
| if( ih == null ) | |||
| { | |||
| ih = new IntrospectionHelper( c ); | |||
| helpers.put( c, ih ); | |||
| } | |||
| return ih; | |||
| } | |||
| /** | |||
| * Sets the named attribute. | |||
| * | |||
| * @param p The new Attribute value | |||
| * @param element The new Attribute value | |||
| * @param attributeName The new Attribute value | |||
| * @param value The new Attribute value | |||
| * @exception BuildException Description of Exception | |||
| */ | |||
| public void setAttribute( Project p, Object element, String attributeName, | |||
| String value ) | |||
| throws TaskException | |||
| { | |||
| AttributeSetter as = (AttributeSetter)attributeSetters.get( attributeName ); | |||
| if( as == null ) | |||
| { | |||
| String msg = getElementName( p, element ) + | |||
| //String msg = "Class " + element.getClass().getName() + | |||
| " doesn't support the \"" + attributeName + "\" attribute."; | |||
| throw new TaskException( msg ); | |||
| } | |||
| try | |||
| { | |||
| as.set( p, element, value ); | |||
| } | |||
| catch( IllegalAccessException ie ) | |||
| { | |||
| // impossible as getMethods should only return public methods | |||
| throw new TaskException( ie.toString(), ie ); | |||
| } | |||
| catch( InvocationTargetException ite ) | |||
| { | |||
| Throwable t = ite.getTargetException(); | |||
| if( t instanceof TaskException ) | |||
| { | |||
| throw (TaskException)t; | |||
| } | |||
| throw new TaskException( t.toString(), t ); | |||
| } | |||
| } | |||
| /** | |||
| * returns the type of a named attribute. | |||
| * | |||
| * @param attributeName Description of Parameter | |||
| * @return The AttributeType value | |||
| * @exception TaskException Description of Exception | |||
| */ | |||
| public Class getAttributeType( String attributeName ) | |||
| throws TaskException | |||
| { | |||
| Class at = (Class)attributeTypes.get( attributeName ); | |||
| if( at == null ) | |||
| { | |||
| String msg = "Class " + bean.getName() + | |||
| " doesn't support the \"" + attributeName + "\" attribute."; | |||
| throw new TaskException( msg ); | |||
| } | |||
| return at; | |||
| } | |||
| /** | |||
| * Return all attribues supported by the introspected class. | |||
| * | |||
| * @return The Attributes value | |||
| */ | |||
| public Enumeration getAttributes() | |||
| { | |||
| return attributeSetters.keys(); | |||
| } | |||
| /** | |||
| * returns the type of a named nested element. | |||
| * | |||
| * @param elementName Description of Parameter | |||
| * @return The ElementType value | |||
| * @exception TaskException Description of Exception | |||
| */ | |||
| public Class getElementType( String elementName ) | |||
| throws TaskException | |||
| { | |||
| Class nt = (Class)nestedTypes.get( elementName ); | |||
| if( nt == null ) | |||
| { | |||
| String msg = "Class " + bean.getName() + | |||
| " doesn't support the nested \"" + elementName + "\" element."; | |||
| throw new TaskException( msg ); | |||
| } | |||
| return nt; | |||
| } | |||
| /** | |||
| * Return all nested elements supported by the introspected class. | |||
| * | |||
| * @return The NestedElements value | |||
| */ | |||
| public Enumeration getNestedElements() | |||
| { | |||
| return nestedTypes.keys(); | |||
| } | |||
| /** | |||
| * Adds PCDATA areas. | |||
| * | |||
| * @param project The feature to be added to the Text attribute | |||
| * @param element The feature to be added to the Text attribute | |||
| * @param text The feature to be added to the Text attribute | |||
| */ | |||
| public void addText( Project project, Object element, String text ) | |||
| throws TaskException | |||
| { | |||
| if( addText == null ) | |||
| { | |||
| String msg = getElementName( project, element ) + | |||
| //String msg = "Class " + element.getClass().getName() + | |||
| " doesn't support nested text data."; | |||
| throw new TaskException( msg ); | |||
| } | |||
| try | |||
| { | |||
| addText.invoke( element, new String[]{text} ); | |||
| } | |||
| catch( IllegalAccessException ie ) | |||
| { | |||
| // impossible as getMethods should only return public methods | |||
| throw new TaskException( ie.getMessage(), ie ); | |||
| } | |||
| catch( InvocationTargetException ite ) | |||
| { | |||
| Throwable t = ite.getTargetException(); | |||
| if( t instanceof TaskException ) | |||
| { | |||
| throw (TaskException)t; | |||
| } | |||
| throw new TaskException( t.getMessage(), t ); | |||
| } | |||
| } | |||
| public void buildFinished( BuildEvent event ) | |||
| { | |||
| attributeTypes.clear(); | |||
| attributeSetters.clear(); | |||
| nestedTypes.clear(); | |||
| nestedCreators.clear(); | |||
| addText = null; | |||
| helpers.clear(); | |||
| } | |||
| public void buildStarted( BuildEvent event ) | |||
| { | |||
| } | |||
| /** | |||
| * Creates a named nested element. | |||
| * | |||
| * @param project Description of Parameter | |||
| * @param element Description of Parameter | |||
| * @param elementName Description of Parameter | |||
| * @return Description of the Returned Value | |||
| * @exception TaskException Description of Exception | |||
| */ | |||
| public Object createElement( Project project, Object element, String elementName ) | |||
| throws TaskException | |||
| { | |||
| NestedCreator nc = (NestedCreator)nestedCreators.get( elementName ); | |||
| if( nc == null ) | |||
| { | |||
| String msg = getElementName( project, element ) + | |||
| " doesn't support the nested \"" + elementName + "\" element."; | |||
| throw new TaskException( msg ); | |||
| } | |||
| try | |||
| { | |||
| Object nestedElement = nc.create( element ); | |||
| if( nestedElement instanceof ProjectComponent ) | |||
| { | |||
| ( (ProjectComponent)nestedElement ).setProject( project ); | |||
| } | |||
| return nestedElement; | |||
| } | |||
| catch( IllegalAccessException ie ) | |||
| { | |||
| // impossible as getMethods should only return public methods | |||
| throw new TaskException( ie.getMessage(), ie ); | |||
| } | |||
| catch( InstantiationException ine ) | |||
| { | |||
| // impossible as getMethods should only return public methods | |||
| throw new TaskException( ine.getMessage(), ine ); | |||
| } | |||
| catch( InvocationTargetException ite ) | |||
| { | |||
| Throwable t = ite.getTargetException(); | |||
| if( t instanceof TaskException ) | |||
| { | |||
| throw (TaskException)t; | |||
| } | |||
| throw new TaskException( t.getMessage(), t ); | |||
| } | |||
| } | |||
| public void messageLogged( BuildEvent event ) | |||
| { | |||
| } | |||
| /** | |||
| * Creates a named nested element. | |||
| * | |||
| * @param project Description of Parameter | |||
| * @param element Description of Parameter | |||
| * @param child Description of Parameter | |||
| * @param elementName Description of Parameter | |||
| * @exception TaskException Description of Exception | |||
| */ | |||
| public void storeElement( Project project, Object element, Object child, String elementName ) | |||
| throws TaskException | |||
| { | |||
| if( elementName == null ) | |||
| { | |||
| return; | |||
| } | |||
| NestedStorer ns = (NestedStorer)nestedStorers.get( elementName ); | |||
| if( ns == null ) | |||
| { | |||
| return; | |||
| } | |||
| try | |||
| { | |||
| ns.store( element, child ); | |||
| } | |||
| catch( IllegalAccessException ie ) | |||
| { | |||
| // impossible as getMethods should only return public methods | |||
| throw new TaskException( ie.getMessage(), ie ); | |||
| } | |||
| catch( InstantiationException ine ) | |||
| { | |||
| // impossible as getMethods should only return public methods | |||
| throw new TaskException( ine.getMessage(), ine ); | |||
| } | |||
| catch( InvocationTargetException ite ) | |||
| { | |||
| Throwable t = ite.getTargetException(); | |||
| if( t instanceof TaskException ) | |||
| { | |||
| throw (TaskException)t; | |||
| } | |||
| throw new TaskException( t.getMessage(), t ); | |||
| } | |||
| } | |||
| /** | |||
| * Does the introspected class support PCDATA? | |||
| * | |||
| * @return Description of the Returned Value | |||
| */ | |||
| public boolean supportsCharacters() | |||
| { | |||
| return addText != null; | |||
| } | |||
| public void targetFinished( BuildEvent event ) | |||
| { | |||
| } | |||
| public void targetStarted( BuildEvent event ) | |||
| { | |||
| } | |||
| public void taskFinished( BuildEvent event ) | |||
| { | |||
| } | |||
| public void taskStarted( BuildEvent event ) | |||
| { | |||
| } | |||
| protected String getElementName( Project project, Object element ) | |||
| { | |||
| Hashtable elements = project.getTaskDefinitions(); | |||
| String typeName = "task"; | |||
| if( !elements.contains( element.getClass() ) ) | |||
| { | |||
| elements = project.getDataTypeDefinitions(); | |||
| typeName = "data type"; | |||
| if( !elements.contains( element.getClass() ) ) | |||
| { | |||
| elements = null; | |||
| } | |||
| } | |||
| if( elements != null ) | |||
| { | |||
| Enumeration e = elements.keys(); | |||
| while( e.hasMoreElements() ) | |||
| { | |||
| String elementName = (String)e.nextElement(); | |||
| Class elementClass = (Class)elements.get( elementName ); | |||
| if( element.getClass().equals( elementClass ) ) | |||
| { | |||
| return "The <" + elementName + "> " + typeName; | |||
| } | |||
| } | |||
| } | |||
| return "Class " + element.getClass().getName(); | |||
| } | |||
| /** | |||
| * extract the name of a property from a method name - subtracting a given | |||
| * prefix. | |||
| * | |||
| * @param methodName Description of Parameter | |||
| * @param prefix Description of Parameter | |||
| * @return The PropertyName value | |||
| */ | |||
| private String getPropertyName( String methodName, String prefix ) | |||
| { | |||
| int start = prefix.length(); | |||
| return methodName.substring( start ).toLowerCase( Locale.US ); | |||
| } | |||
| /** | |||
| * Create a proper implementation of AttributeSetter for the given attribute | |||
| * type. | |||
| * | |||
| * @param m Description of Parameter | |||
| * @param arg Description of Parameter | |||
| * @return Description of the Returned Value | |||
| */ | |||
| private AttributeSetter createAttributeSetter( final Method m, | |||
| final Class arg ) | |||
| throws TaskException | |||
| { | |||
| // simplest case - setAttribute expects String | |||
| if( java.lang.String.class.equals( arg ) ) | |||
| { | |||
| return | |||
| new AttributeSetter() | |||
| { | |||
| public void set( Project p, Object parent, String value ) | |||
| throws InvocationTargetException, IllegalAccessException | |||
| { | |||
| m.invoke( parent, new String[]{value} ); | |||
| } | |||
| }; | |||
| // now for the primitive types, use their wrappers | |||
| } | |||
| else if( java.lang.Character.class.equals( arg ) | |||
| || java.lang.Character.TYPE.equals( arg ) ) | |||
| { | |||
| return | |||
| new AttributeSetter() | |||
| { | |||
| public void set( Project p, Object parent, String value ) | |||
| throws InvocationTargetException, IllegalAccessException | |||
| { | |||
| m.invoke( parent, new Character[]{new Character( value.charAt( 0 ) )} ); | |||
| } | |||
| }; | |||
| } | |||
| else if( java.lang.Byte.TYPE.equals( arg ) ) | |||
| { | |||
| return | |||
| new AttributeSetter() | |||
| { | |||
| public void set( Project p, Object parent, String value ) | |||
| throws InvocationTargetException, IllegalAccessException | |||
| { | |||
| m.invoke( parent, new Byte[]{new Byte( value )} ); | |||
| } | |||
| }; | |||
| } | |||
| else if( java.lang.Short.TYPE.equals( arg ) ) | |||
| { | |||
| return | |||
| new AttributeSetter() | |||
| { | |||
| public void set( Project p, Object parent, String value ) | |||
| throws InvocationTargetException, IllegalAccessException | |||
| { | |||
| m.invoke( parent, new Short[]{new Short( value )} ); | |||
| } | |||
| }; | |||
| } | |||
| else if( java.lang.Integer.TYPE.equals( arg ) ) | |||
| { | |||
| return | |||
| new AttributeSetter() | |||
| { | |||
| public void set( Project p, Object parent, String value ) | |||
| throws InvocationTargetException, IllegalAccessException | |||
| { | |||
| m.invoke( parent, new Integer[]{new Integer( value )} ); | |||
| } | |||
| }; | |||
| } | |||
| else if( java.lang.Long.TYPE.equals( arg ) ) | |||
| { | |||
| return | |||
| new AttributeSetter() | |||
| { | |||
| public void set( Project p, Object parent, String value ) | |||
| throws InvocationTargetException, IllegalAccessException | |||
| { | |||
| m.invoke( parent, new Long[]{new Long( value )} ); | |||
| } | |||
| }; | |||
| } | |||
| else if( java.lang.Float.TYPE.equals( arg ) ) | |||
| { | |||
| return | |||
| new AttributeSetter() | |||
| { | |||
| public void set( Project p, Object parent, String value ) | |||
| throws InvocationTargetException, IllegalAccessException | |||
| { | |||
| m.invoke( parent, new Float[]{new Float( value )} ); | |||
| } | |||
| }; | |||
| } | |||
| else if( java.lang.Double.TYPE.equals( arg ) ) | |||
| { | |||
| return | |||
| new AttributeSetter() | |||
| { | |||
| public void set( Project p, Object parent, String value ) | |||
| throws InvocationTargetException, IllegalAccessException | |||
| { | |||
| m.invoke( parent, new Double[]{new Double( value )} ); | |||
| } | |||
| }; | |||
| // boolean gets an extra treatment, because we have a nice method | |||
| // in Project | |||
| } | |||
| else if( java.lang.Boolean.class.equals( arg ) | |||
| || java.lang.Boolean.TYPE.equals( arg ) ) | |||
| { | |||
| return | |||
| new AttributeSetter() | |||
| { | |||
| public void set( Project p, Object parent, String value ) | |||
| throws InvocationTargetException, IllegalAccessException | |||
| { | |||
| m.invoke( parent, | |||
| new Boolean[]{new Boolean( Project.toBoolean( value ) )} ); | |||
| } | |||
| }; | |||
| // Class doesn't have a String constructor but a decent factory method | |||
| } | |||
| else if( java.lang.Class.class.equals( arg ) ) | |||
| { | |||
| return | |||
| new AttributeSetter() | |||
| { | |||
| public void set( Project p, Object parent, String value ) | |||
| throws InvocationTargetException, IllegalAccessException, TaskException | |||
| { | |||
| try | |||
| { | |||
| m.invoke( parent, new Class[]{Class.forName( value )} ); | |||
| } | |||
| catch( ClassNotFoundException ce ) | |||
| { | |||
| throw new TaskException( ce.toString(), ce ); | |||
| } | |||
| } | |||
| }; | |||
| // resolve relative paths through Project | |||
| } | |||
| else if( java.io.File.class.equals( arg ) ) | |||
| { | |||
| return | |||
| new AttributeSetter() | |||
| { | |||
| public void set( Project p, Object parent, String value ) | |||
| throws InvocationTargetException, IllegalAccessException | |||
| { | |||
| final File file = | |||
| FileUtils.newFileUtils().resolveFile( p.getBaseDir(), value ); | |||
| m.invoke( parent, new File[]{file} ); | |||
| } | |||
| }; | |||
| // resolve relative paths through Project | |||
| } | |||
| else if( org.apache.tools.ant.types.Path.class.equals( arg ) ) | |||
| { | |||
| return | |||
| new AttributeSetter() | |||
| { | |||
| public void set( Project p, Object parent, String value ) | |||
| throws InvocationTargetException, IllegalAccessException | |||
| { | |||
| m.invoke( parent, new Path[]{new Path( p, value )} ); | |||
| } | |||
| }; | |||
| // EnumeratedAttributes have their own helper class | |||
| } | |||
| else if( org.apache.tools.ant.types.EnumeratedAttribute.class.isAssignableFrom( arg ) ) | |||
| { | |||
| return | |||
| new AttributeSetter() | |||
| { | |||
| public void set( Project p, Object parent, String value ) | |||
| throws InvocationTargetException, IllegalAccessException, TaskException | |||
| { | |||
| try | |||
| { | |||
| org.apache.tools.ant.types.EnumeratedAttribute ea = (org.apache.tools.ant.types.EnumeratedAttribute)arg.newInstance(); | |||
| ea.setValue( value ); | |||
| m.invoke( parent, new EnumeratedAttribute[]{ea} ); | |||
| } | |||
| catch( InstantiationException ie ) | |||
| { | |||
| throw new TaskException( ie.getMessage(), ie ); | |||
| } | |||
| } | |||
| }; | |||
| // worst case. look for a public String constructor and use it | |||
| } | |||
| else | |||
| { | |||
| try | |||
| { | |||
| final Constructor c = | |||
| arg.getConstructor( new Class[]{java.lang.String.class} ); | |||
| return | |||
| new AttributeSetter() | |||
| { | |||
| public void set( Project p, Object parent, | |||
| String value ) | |||
| throws InvocationTargetException, IllegalAccessException, TaskException | |||
| { | |||
| try | |||
| { | |||
| Object attribute = c.newInstance( new String[]{value} ); | |||
| if( attribute instanceof ProjectComponent ) | |||
| { | |||
| ( (ProjectComponent)attribute ).setProject( p ); | |||
| } | |||
| m.invoke( parent, new Object[]{attribute} ); | |||
| } | |||
| catch( InstantiationException ie ) | |||
| { | |||
| throw new TaskException( ie.getMessage(), ie ); | |||
| } | |||
| } | |||
| }; | |||
| } | |||
| catch( NoSuchMethodException nme ) | |||
| { | |||
| } | |||
| } | |||
| return null; | |||
| } | |||
| private interface AttributeSetter | |||
| { | |||
| void set( Project p, Object parent, String value ) | |||
| throws InvocationTargetException, IllegalAccessException, | |||
| TaskException; | |||
| } | |||
| private interface NestedCreator | |||
| { | |||
| Object create( Object parent ) | |||
| throws InvocationTargetException, IllegalAccessException, InstantiationException; | |||
| } | |||
| private interface NestedStorer | |||
| { | |||
| void store( Object parent, Object child ) | |||
| throws InvocationTargetException, IllegalAccessException, InstantiationException; | |||
| } | |||
| } | |||
| @@ -1,854 +0,0 @@ | |||
| /* | |||
| * 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 file. | |||
| */ | |||
| package org.apache.tools.ant; | |||
| import java.io.File; | |||
| import java.lang.reflect.Constructor; | |||
| import java.lang.reflect.InvocationTargetException; | |||
| import java.lang.reflect.Method; | |||
| import java.util.Enumeration; | |||
| import java.util.Hashtable; | |||
| import java.util.Locale; | |||
| import org.apache.myrmidon.api.TaskException; | |||
| import org.apache.tools.ant.types.EnumeratedAttribute; | |||
| import org.apache.tools.ant.types.Path; | |||
| import org.apache.tools.ant.util.FileUtils; | |||
| /** | |||
| * Helper class that collects the methods a task or nested element holds to set | |||
| * attributes, create nested elements or hold PCDATA elements. | |||
| * | |||
| * @author <a href="mailto:stefan.bodewig@epost.de">Stefan Bodewig</a> | |||
| */ | |||
| public class IntrospectionHelper implements BuildListener | |||
| { | |||
| /** | |||
| * instances we've already created | |||
| */ | |||
| private static Hashtable helpers = new Hashtable(); | |||
| /** | |||
| * The method to add PCDATA stuff. | |||
| */ | |||
| private Method addText = null; | |||
| /** | |||
| * holds the attribute setter methods. | |||
| */ | |||
| private Hashtable attributeSetters; | |||
| /** | |||
| * holds the types of the attributes that could be set. | |||
| */ | |||
| private Hashtable attributeTypes; | |||
| /** | |||
| * The Class that's been introspected. | |||
| */ | |||
| private Class bean; | |||
| /** | |||
| * Holds methods to create nested elements. | |||
| */ | |||
| private Hashtable nestedCreators; | |||
| /** | |||
| * Holds methods to store configured nested elements. | |||
| */ | |||
| private Hashtable nestedStorers; | |||
| /** | |||
| * Holds the types of nested elements that could be created. | |||
| */ | |||
| private Hashtable nestedTypes; | |||
| private IntrospectionHelper( final Class bean ) | |||
| throws TaskException | |||
| { | |||
| attributeTypes = new Hashtable(); | |||
| attributeSetters = new Hashtable(); | |||
| nestedTypes = new Hashtable(); | |||
| nestedCreators = new Hashtable(); | |||
| nestedStorers = new Hashtable(); | |||
| this.bean = bean; | |||
| Method[] methods = bean.getMethods(); | |||
| for( int i = 0; i < methods.length; i++ ) | |||
| { | |||
| final Method m = methods[ i ]; | |||
| final String name = m.getName(); | |||
| Class returnType = m.getReturnType(); | |||
| Class[] args = m.getParameterTypes(); | |||
| // hide addTask for TaskContainers | |||
| if( org.apache.tools.ant.TaskContainer.class.isAssignableFrom( bean ) | |||
| && args.length == 1 && "addTask".equals( name ) | |||
| && org.apache.tools.ant.Task.class.equals( args[ 0 ] ) ) | |||
| { | |||
| continue; | |||
| } | |||
| if( "addText".equals( name ) | |||
| && java.lang.Void.TYPE.equals( returnType ) | |||
| && args.length == 1 | |||
| && java.lang.String.class.equals( args[ 0 ] ) ) | |||
| { | |||
| addText = methods[ i ]; | |||
| } | |||
| else if( name.startsWith( "set" ) | |||
| && java.lang.Void.TYPE.equals( returnType ) | |||
| && args.length == 1 | |||
| && !args[ 0 ].isArray() ) | |||
| { | |||
| String propName = getPropertyName( name, "set" ); | |||
| if( attributeSetters.get( propName ) != null ) | |||
| { | |||
| if( java.lang.String.class.equals( args[ 0 ] ) ) | |||
| { | |||
| /* | |||
| * Ignore method m, as there is an overloaded | |||
| * form of this method that takes in a | |||
| * non-string argument, which gains higher | |||
| * priority. | |||
| */ | |||
| continue; | |||
| } | |||
| /* | |||
| * If the argument is not a String, and if there | |||
| * is an overloaded form of this method already defined, | |||
| * we just override that with the new one. | |||
| * This mechanism does not guarantee any specific order | |||
| * in which the methods will be selected: so any code | |||
| * that depends on the order in which "set" methods have | |||
| * been defined, is not guaranteed to be selected in any | |||
| * particular order. | |||
| */ | |||
| } | |||
| AttributeSetter as = createAttributeSetter( m, args[ 0 ] ); | |||
| if( as != null ) | |||
| { | |||
| attributeTypes.put( propName, args[ 0 ] ); | |||
| attributeSetters.put( propName, as ); | |||
| } | |||
| } | |||
| else if( name.startsWith( "create" ) | |||
| && !returnType.isArray() | |||
| && !returnType.isPrimitive() | |||
| && args.length == 0 ) | |||
| { | |||
| String propName = getPropertyName( name, "create" ); | |||
| nestedTypes.put( propName, returnType ); | |||
| nestedCreators.put( propName, | |||
| new NestedCreator() | |||
| { | |||
| public Object create( Object parent ) | |||
| throws InvocationTargetException, | |||
| IllegalAccessException | |||
| { | |||
| return m.invoke( parent, new Object[]{} ); | |||
| } | |||
| } ); | |||
| } | |||
| else if( name.startsWith( "addConfigured" ) | |||
| && java.lang.Void.TYPE.equals( returnType ) | |||
| && args.length == 1 | |||
| && !java.lang.String.class.equals( args[ 0 ] ) | |||
| && !args[ 0 ].isArray() | |||
| && !args[ 0 ].isPrimitive() ) | |||
| { | |||
| try | |||
| { | |||
| final Constructor c = | |||
| args[ 0 ].getConstructor( new Class[]{} ); | |||
| String propName = getPropertyName( name, "addConfigured" ); | |||
| nestedTypes.put( propName, args[ 0 ] ); | |||
| nestedCreators.put( propName, | |||
| new NestedCreator() | |||
| { | |||
| public Object create( Object parent ) | |||
| throws InvocationTargetException, IllegalAccessException, InstantiationException | |||
| { | |||
| Object o = c.newInstance( new Object[]{} ); | |||
| return o; | |||
| } | |||
| } ); | |||
| nestedStorers.put( propName, | |||
| new NestedStorer() | |||
| { | |||
| public void store( Object parent, Object child ) | |||
| throws InvocationTargetException, IllegalAccessException, InstantiationException | |||
| { | |||
| m.invoke( parent, new Object[]{child} ); | |||
| } | |||
| } ); | |||
| } | |||
| catch( NoSuchMethodException nse ) | |||
| { | |||
| } | |||
| } | |||
| else if( name.startsWith( "add" ) | |||
| && java.lang.Void.TYPE.equals( returnType ) | |||
| && args.length == 1 | |||
| && !java.lang.String.class.equals( args[ 0 ] ) | |||
| && !args[ 0 ].isArray() | |||
| && !args[ 0 ].isPrimitive() ) | |||
| { | |||
| try | |||
| { | |||
| final Constructor c = | |||
| args[ 0 ].getConstructor( new Class[]{} ); | |||
| String propName = getPropertyName( name, "add" ); | |||
| nestedTypes.put( propName, args[ 0 ] ); | |||
| nestedCreators.put( propName, | |||
| new NestedCreator() | |||
| { | |||
| public Object create( Object parent ) | |||
| throws InvocationTargetException, IllegalAccessException, InstantiationException | |||
| { | |||
| Object o = c.newInstance( new Object[]{} ); | |||
| m.invoke( parent, new Object[]{o} ); | |||
| return o; | |||
| } | |||
| } ); | |||
| } | |||
| catch( NoSuchMethodException nse ) | |||
| { | |||
| } | |||
| } | |||
| } | |||
| } | |||
| /** | |||
| * Factory method for helper objects. | |||
| * | |||
| * @param c Description of Parameter | |||
| * @return The Helper value | |||
| */ | |||
| public static synchronized IntrospectionHelper getHelper( Class c ) | |||
| { | |||
| IntrospectionHelper ih = (IntrospectionHelper)helpers.get( c ); | |||
| if( ih == null ) | |||
| { | |||
| ih = new IntrospectionHelper( c ); | |||
| helpers.put( c, ih ); | |||
| } | |||
| return ih; | |||
| } | |||
| /** | |||
| * Sets the named attribute. | |||
| * | |||
| * @param p The new Attribute value | |||
| * @param element The new Attribute value | |||
| * @param attributeName The new Attribute value | |||
| * @param value The new Attribute value | |||
| * @exception BuildException Description of Exception | |||
| */ | |||
| public void setAttribute( Project p, Object element, String attributeName, | |||
| String value ) | |||
| throws TaskException | |||
| { | |||
| AttributeSetter as = (AttributeSetter)attributeSetters.get( attributeName ); | |||
| if( as == null ) | |||
| { | |||
| String msg = getElementName( p, element ) + | |||
| //String msg = "Class " + element.getClass().getName() + | |||
| " doesn't support the \"" + attributeName + "\" attribute."; | |||
| throw new TaskException( msg ); | |||
| } | |||
| try | |||
| { | |||
| as.set( p, element, value ); | |||
| } | |||
| catch( IllegalAccessException ie ) | |||
| { | |||
| // impossible as getMethods should only return public methods | |||
| throw new TaskException( ie.toString(), ie ); | |||
| } | |||
| catch( InvocationTargetException ite ) | |||
| { | |||
| Throwable t = ite.getTargetException(); | |||
| if( t instanceof TaskException ) | |||
| { | |||
| throw (TaskException)t; | |||
| } | |||
| throw new TaskException( t.toString(), t ); | |||
| } | |||
| } | |||
| /** | |||
| * returns the type of a named attribute. | |||
| * | |||
| * @param attributeName Description of Parameter | |||
| * @return The AttributeType value | |||
| * @exception TaskException Description of Exception | |||
| */ | |||
| public Class getAttributeType( String attributeName ) | |||
| throws TaskException | |||
| { | |||
| Class at = (Class)attributeTypes.get( attributeName ); | |||
| if( at == null ) | |||
| { | |||
| String msg = "Class " + bean.getName() + | |||
| " doesn't support the \"" + attributeName + "\" attribute."; | |||
| throw new TaskException( msg ); | |||
| } | |||
| return at; | |||
| } | |||
| /** | |||
| * Return all attribues supported by the introspected class. | |||
| * | |||
| * @return The Attributes value | |||
| */ | |||
| public Enumeration getAttributes() | |||
| { | |||
| return attributeSetters.keys(); | |||
| } | |||
| /** | |||
| * returns the type of a named nested element. | |||
| * | |||
| * @param elementName Description of Parameter | |||
| * @return The ElementType value | |||
| * @exception TaskException Description of Exception | |||
| */ | |||
| public Class getElementType( String elementName ) | |||
| throws TaskException | |||
| { | |||
| Class nt = (Class)nestedTypes.get( elementName ); | |||
| if( nt == null ) | |||
| { | |||
| String msg = "Class " + bean.getName() + | |||
| " doesn't support the nested \"" + elementName + "\" element."; | |||
| throw new TaskException( msg ); | |||
| } | |||
| return nt; | |||
| } | |||
| /** | |||
| * Return all nested elements supported by the introspected class. | |||
| * | |||
| * @return The NestedElements value | |||
| */ | |||
| public Enumeration getNestedElements() | |||
| { | |||
| return nestedTypes.keys(); | |||
| } | |||
| /** | |||
| * Adds PCDATA areas. | |||
| * | |||
| * @param project The feature to be added to the Text attribute | |||
| * @param element The feature to be added to the Text attribute | |||
| * @param text The feature to be added to the Text attribute | |||
| */ | |||
| public void addText( Project project, Object element, String text ) | |||
| throws TaskException | |||
| { | |||
| if( addText == null ) | |||
| { | |||
| String msg = getElementName( project, element ) + | |||
| //String msg = "Class " + element.getClass().getName() + | |||
| " doesn't support nested text data."; | |||
| throw new TaskException( msg ); | |||
| } | |||
| try | |||
| { | |||
| addText.invoke( element, new String[]{text} ); | |||
| } | |||
| catch( IllegalAccessException ie ) | |||
| { | |||
| // impossible as getMethods should only return public methods | |||
| throw new TaskException( ie.getMessage(), ie ); | |||
| } | |||
| catch( InvocationTargetException ite ) | |||
| { | |||
| Throwable t = ite.getTargetException(); | |||
| if( t instanceof TaskException ) | |||
| { | |||
| throw (TaskException)t; | |||
| } | |||
| throw new TaskException( t.getMessage(), t ); | |||
| } | |||
| } | |||
| public void buildFinished( BuildEvent event ) | |||
| { | |||
| attributeTypes.clear(); | |||
| attributeSetters.clear(); | |||
| nestedTypes.clear(); | |||
| nestedCreators.clear(); | |||
| addText = null; | |||
| helpers.clear(); | |||
| } | |||
| public void buildStarted( BuildEvent event ) | |||
| { | |||
| } | |||
| /** | |||
| * Creates a named nested element. | |||
| * | |||
| * @param project Description of Parameter | |||
| * @param element Description of Parameter | |||
| * @param elementName Description of Parameter | |||
| * @return Description of the Returned Value | |||
| * @exception TaskException Description of Exception | |||
| */ | |||
| public Object createElement( Project project, Object element, String elementName ) | |||
| throws TaskException | |||
| { | |||
| NestedCreator nc = (NestedCreator)nestedCreators.get( elementName ); | |||
| if( nc == null ) | |||
| { | |||
| String msg = getElementName( project, element ) + | |||
| " doesn't support the nested \"" + elementName + "\" element."; | |||
| throw new TaskException( msg ); | |||
| } | |||
| try | |||
| { | |||
| Object nestedElement = nc.create( element ); | |||
| if( nestedElement instanceof ProjectComponent ) | |||
| { | |||
| ( (ProjectComponent)nestedElement ).setProject( project ); | |||
| } | |||
| return nestedElement; | |||
| } | |||
| catch( IllegalAccessException ie ) | |||
| { | |||
| // impossible as getMethods should only return public methods | |||
| throw new TaskException( ie.getMessage(), ie ); | |||
| } | |||
| catch( InstantiationException ine ) | |||
| { | |||
| // impossible as getMethods should only return public methods | |||
| throw new TaskException( ine.getMessage(), ine ); | |||
| } | |||
| catch( InvocationTargetException ite ) | |||
| { | |||
| Throwable t = ite.getTargetException(); | |||
| if( t instanceof TaskException ) | |||
| { | |||
| throw (TaskException)t; | |||
| } | |||
| throw new TaskException( t.getMessage(), t ); | |||
| } | |||
| } | |||
| public void messageLogged( BuildEvent event ) | |||
| { | |||
| } | |||
| /** | |||
| * Creates a named nested element. | |||
| * | |||
| * @param project Description of Parameter | |||
| * @param element Description of Parameter | |||
| * @param child Description of Parameter | |||
| * @param elementName Description of Parameter | |||
| * @exception TaskException Description of Exception | |||
| */ | |||
| public void storeElement( Project project, Object element, Object child, String elementName ) | |||
| throws TaskException | |||
| { | |||
| if( elementName == null ) | |||
| { | |||
| return; | |||
| } | |||
| NestedStorer ns = (NestedStorer)nestedStorers.get( elementName ); | |||
| if( ns == null ) | |||
| { | |||
| return; | |||
| } | |||
| try | |||
| { | |||
| ns.store( element, child ); | |||
| } | |||
| catch( IllegalAccessException ie ) | |||
| { | |||
| // impossible as getMethods should only return public methods | |||
| throw new TaskException( ie.getMessage(), ie ); | |||
| } | |||
| catch( InstantiationException ine ) | |||
| { | |||
| // impossible as getMethods should only return public methods | |||
| throw new TaskException( ine.getMessage(), ine ); | |||
| } | |||
| catch( InvocationTargetException ite ) | |||
| { | |||
| Throwable t = ite.getTargetException(); | |||
| if( t instanceof TaskException ) | |||
| { | |||
| throw (TaskException)t; | |||
| } | |||
| throw new TaskException( t.getMessage(), t ); | |||
| } | |||
| } | |||
| /** | |||
| * Does the introspected class support PCDATA? | |||
| * | |||
| * @return Description of the Returned Value | |||
| */ | |||
| public boolean supportsCharacters() | |||
| { | |||
| return addText != null; | |||
| } | |||
| public void targetFinished( BuildEvent event ) | |||
| { | |||
| } | |||
| public void targetStarted( BuildEvent event ) | |||
| { | |||
| } | |||
| public void taskFinished( BuildEvent event ) | |||
| { | |||
| } | |||
| public void taskStarted( BuildEvent event ) | |||
| { | |||
| } | |||
| protected String getElementName( Project project, Object element ) | |||
| { | |||
| Hashtable elements = project.getTaskDefinitions(); | |||
| String typeName = "task"; | |||
| if( !elements.contains( element.getClass() ) ) | |||
| { | |||
| elements = project.getDataTypeDefinitions(); | |||
| typeName = "data type"; | |||
| if( !elements.contains( element.getClass() ) ) | |||
| { | |||
| elements = null; | |||
| } | |||
| } | |||
| if( elements != null ) | |||
| { | |||
| Enumeration e = elements.keys(); | |||
| while( e.hasMoreElements() ) | |||
| { | |||
| String elementName = (String)e.nextElement(); | |||
| Class elementClass = (Class)elements.get( elementName ); | |||
| if( element.getClass().equals( elementClass ) ) | |||
| { | |||
| return "The <" + elementName + "> " + typeName; | |||
| } | |||
| } | |||
| } | |||
| return "Class " + element.getClass().getName(); | |||
| } | |||
| /** | |||
| * extract the name of a property from a method name - subtracting a given | |||
| * prefix. | |||
| * | |||
| * @param methodName Description of Parameter | |||
| * @param prefix Description of Parameter | |||
| * @return The PropertyName value | |||
| */ | |||
| private String getPropertyName( String methodName, String prefix ) | |||
| { | |||
| int start = prefix.length(); | |||
| return methodName.substring( start ).toLowerCase( Locale.US ); | |||
| } | |||
| /** | |||
| * Create a proper implementation of AttributeSetter for the given attribute | |||
| * type. | |||
| * | |||
| * @param m Description of Parameter | |||
| * @param arg Description of Parameter | |||
| * @return Description of the Returned Value | |||
| */ | |||
| private AttributeSetter createAttributeSetter( final Method m, | |||
| final Class arg ) | |||
| throws TaskException | |||
| { | |||
| // simplest case - setAttribute expects String | |||
| if( java.lang.String.class.equals( arg ) ) | |||
| { | |||
| return | |||
| new AttributeSetter() | |||
| { | |||
| public void set( Project p, Object parent, String value ) | |||
| throws InvocationTargetException, IllegalAccessException | |||
| { | |||
| m.invoke( parent, new String[]{value} ); | |||
| } | |||
| }; | |||
| // now for the primitive types, use their wrappers | |||
| } | |||
| else if( java.lang.Character.class.equals( arg ) | |||
| || java.lang.Character.TYPE.equals( arg ) ) | |||
| { | |||
| return | |||
| new AttributeSetter() | |||
| { | |||
| public void set( Project p, Object parent, String value ) | |||
| throws InvocationTargetException, IllegalAccessException | |||
| { | |||
| m.invoke( parent, new Character[]{new Character( value.charAt( 0 ) )} ); | |||
| } | |||
| }; | |||
| } | |||
| else if( java.lang.Byte.TYPE.equals( arg ) ) | |||
| { | |||
| return | |||
| new AttributeSetter() | |||
| { | |||
| public void set( Project p, Object parent, String value ) | |||
| throws InvocationTargetException, IllegalAccessException | |||
| { | |||
| m.invoke( parent, new Byte[]{new Byte( value )} ); | |||
| } | |||
| }; | |||
| } | |||
| else if( java.lang.Short.TYPE.equals( arg ) ) | |||
| { | |||
| return | |||
| new AttributeSetter() | |||
| { | |||
| public void set( Project p, Object parent, String value ) | |||
| throws InvocationTargetException, IllegalAccessException | |||
| { | |||
| m.invoke( parent, new Short[]{new Short( value )} ); | |||
| } | |||
| }; | |||
| } | |||
| else if( java.lang.Integer.TYPE.equals( arg ) ) | |||
| { | |||
| return | |||
| new AttributeSetter() | |||
| { | |||
| public void set( Project p, Object parent, String value ) | |||
| throws InvocationTargetException, IllegalAccessException | |||
| { | |||
| m.invoke( parent, new Integer[]{new Integer( value )} ); | |||
| } | |||
| }; | |||
| } | |||
| else if( java.lang.Long.TYPE.equals( arg ) ) | |||
| { | |||
| return | |||
| new AttributeSetter() | |||
| { | |||
| public void set( Project p, Object parent, String value ) | |||
| throws InvocationTargetException, IllegalAccessException | |||
| { | |||
| m.invoke( parent, new Long[]{new Long( value )} ); | |||
| } | |||
| }; | |||
| } | |||
| else if( java.lang.Float.TYPE.equals( arg ) ) | |||
| { | |||
| return | |||
| new AttributeSetter() | |||
| { | |||
| public void set( Project p, Object parent, String value ) | |||
| throws InvocationTargetException, IllegalAccessException | |||
| { | |||
| m.invoke( parent, new Float[]{new Float( value )} ); | |||
| } | |||
| }; | |||
| } | |||
| else if( java.lang.Double.TYPE.equals( arg ) ) | |||
| { | |||
| return | |||
| new AttributeSetter() | |||
| { | |||
| public void set( Project p, Object parent, String value ) | |||
| throws InvocationTargetException, IllegalAccessException | |||
| { | |||
| m.invoke( parent, new Double[]{new Double( value )} ); | |||
| } | |||
| }; | |||
| // boolean gets an extra treatment, because we have a nice method | |||
| // in Project | |||
| } | |||
| else if( java.lang.Boolean.class.equals( arg ) | |||
| || java.lang.Boolean.TYPE.equals( arg ) ) | |||
| { | |||
| return | |||
| new AttributeSetter() | |||
| { | |||
| public void set( Project p, Object parent, String value ) | |||
| throws InvocationTargetException, IllegalAccessException | |||
| { | |||
| m.invoke( parent, | |||
| new Boolean[]{new Boolean( Project.toBoolean( value ) )} ); | |||
| } | |||
| }; | |||
| // Class doesn't have a String constructor but a decent factory method | |||
| } | |||
| else if( java.lang.Class.class.equals( arg ) ) | |||
| { | |||
| return | |||
| new AttributeSetter() | |||
| { | |||
| public void set( Project p, Object parent, String value ) | |||
| throws InvocationTargetException, IllegalAccessException, TaskException | |||
| { | |||
| try | |||
| { | |||
| m.invoke( parent, new Class[]{Class.forName( value )} ); | |||
| } | |||
| catch( ClassNotFoundException ce ) | |||
| { | |||
| throw new TaskException( ce.toString(), ce ); | |||
| } | |||
| } | |||
| }; | |||
| // resolve relative paths through Project | |||
| } | |||
| else if( java.io.File.class.equals( arg ) ) | |||
| { | |||
| return | |||
| new AttributeSetter() | |||
| { | |||
| public void set( Project p, Object parent, String value ) | |||
| throws InvocationTargetException, IllegalAccessException | |||
| { | |||
| final File file = | |||
| FileUtils.newFileUtils().resolveFile( p.getBaseDir(), value ); | |||
| m.invoke( parent, new File[]{file} ); | |||
| } | |||
| }; | |||
| // resolve relative paths through Project | |||
| } | |||
| else if( org.apache.tools.ant.types.Path.class.equals( arg ) ) | |||
| { | |||
| return | |||
| new AttributeSetter() | |||
| { | |||
| public void set( Project p, Object parent, String value ) | |||
| throws InvocationTargetException, IllegalAccessException | |||
| { | |||
| m.invoke( parent, new Path[]{new Path( p, value )} ); | |||
| } | |||
| }; | |||
| // EnumeratedAttributes have their own helper class | |||
| } | |||
| else if( org.apache.tools.ant.types.EnumeratedAttribute.class.isAssignableFrom( arg ) ) | |||
| { | |||
| return | |||
| new AttributeSetter() | |||
| { | |||
| public void set( Project p, Object parent, String value ) | |||
| throws InvocationTargetException, IllegalAccessException, TaskException | |||
| { | |||
| try | |||
| { | |||
| org.apache.tools.ant.types.EnumeratedAttribute ea = (org.apache.tools.ant.types.EnumeratedAttribute)arg.newInstance(); | |||
| ea.setValue( value ); | |||
| m.invoke( parent, new EnumeratedAttribute[]{ea} ); | |||
| } | |||
| catch( InstantiationException ie ) | |||
| { | |||
| throw new TaskException( ie.getMessage(), ie ); | |||
| } | |||
| } | |||
| }; | |||
| // worst case. look for a public String constructor and use it | |||
| } | |||
| else | |||
| { | |||
| try | |||
| { | |||
| final Constructor c = | |||
| arg.getConstructor( new Class[]{java.lang.String.class} ); | |||
| return | |||
| new AttributeSetter() | |||
| { | |||
| public void set( Project p, Object parent, | |||
| String value ) | |||
| throws InvocationTargetException, IllegalAccessException, TaskException | |||
| { | |||
| try | |||
| { | |||
| Object attribute = c.newInstance( new String[]{value} ); | |||
| if( attribute instanceof ProjectComponent ) | |||
| { | |||
| ( (ProjectComponent)attribute ).setProject( p ); | |||
| } | |||
| m.invoke( parent, new Object[]{attribute} ); | |||
| } | |||
| catch( InstantiationException ie ) | |||
| { | |||
| throw new TaskException( ie.getMessage(), ie ); | |||
| } | |||
| } | |||
| }; | |||
| } | |||
| catch( NoSuchMethodException nme ) | |||
| { | |||
| } | |||
| } | |||
| return null; | |||
| } | |||
| private interface AttributeSetter | |||
| { | |||
| void set( Project p, Object parent, String value ) | |||
| throws InvocationTargetException, IllegalAccessException, | |||
| TaskException; | |||
| } | |||
| private interface NestedCreator | |||
| { | |||
| Object create( Object parent ) | |||
| throws InvocationTargetException, IllegalAccessException, InstantiationException; | |||
| } | |||
| private interface NestedStorer | |||
| { | |||
| void store( Object parent, Object child ) | |||
| throws InvocationTargetException, IllegalAccessException, InstantiationException; | |||
| } | |||
| } | |||