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