Return-Path:
* This class is used to help in handling dynamic elements.
* The idea is to allow easy custom extensions
* and to extend the traditional ant bean reflection to call setters
* methods, or add/create methods, with all the magic type conversion
* it does.
*
* The dynamic element classes will be defined by <typedef/>
* or (to be decided) by <taskdef/>
*
* User classes (tasks or datatypes) have methods
*
* This class is currently used by DynamicElementTask, but
* may in the future be used by ant core IntrospectionHelper.
*
* An example: Suppose one had a task buildpath that resolved
* paths using custom resolvers that implement a BuildPathResolver
* interface.
*
* Note:
* x
* createDynamicMethod should possible throw different
* exceptions for the various error conditions:
* dynamicElement(class or interface)
*
* <typedef name=3D"tahoeresolver"
* classname=3D"acme.resolvers.TahoeResolver"
* classpath=3D"acme.classpath"/>
* <buildpath id=3D"tahoebuildpath">
* <tahoeresolver destdir=3D"${destdir}"
* dependencies=3D"${dependencies}"=20
* </buildpath>
*
*
* BuildPath would look something like this.
*
* public class BuildPathTask
* extends DynamicElementTask
* {
* ...
* BuildPathResolver resolver;
* public void dynamicElement(BuildPathResolver resolver) {
* if (resolver !=3D null)
* throw new BuildException();
* resolver =3D resolver;
* }
* ....
* public void execute() {
* if (resolver =3D=3D null)
* throw new BuildException();
* buildPath =3D resolver.getBuildPath();
* }
* }
*
*
*
dynamicelement
* method in object.
* @param project the project the task or datatype is in
* @param object the task or data type instance
* @param elementName the xml tag
* @return the created object.
*/
public Object createDynamicElement(
Project project, Object object, String elementName)
{
if (project =3D=3D null) {
throw new BuildException(
"Project is null for dynamicElementHelper");
}
if (nestedDynamicMethods.size() =3D=3D 0)
return null;
=20
// is element in task definitions
Class elementClass =3D
(Class) project.getTaskDefinitions().get(elementName);
boolean isTask =3D (elementClass !=3D null);
if (elementClass !=3D null) {
if (! (Task.class.isAssignableFrom(elementClass))) {
elementClass =3D TaskAdapter.class;
}
} else {
// is element in data type definitions
elementClass =3D
(Class) project.getDataTypeDefinitions().get(elementName);
}
=20
if (elementClass =3D=3D null) {
return null;
}
Method method =3D getMatchingMethod(elementClass);
if (method =3D=3D null)
return null;
Object nestedObject =3D (isTask
? project.createTask(elementName)
: project.createDataType(elementName));
if (nestedObject =3D=3D null)
return null;
// invoke the dynamic element method
try {
method.invoke(object, new Object[]{nestedObject});
}
catch (InvocationTargetException ex) {
Throwable realException =3D ex.getTargetException();
if (realException instanceof BuildException)
throw (BuildException) realException;
}
catch (Throwable t) {
throw new BuildException(t);
}
// If this is a task call the init method on it
if (isTask) {
((Task) nestedObject).init();
}
return nestedObject;
}
=20
/**
* Search the array of methods to find method names
* of "dynamicElement" with one parameter. Sort the
* methods so that derived classes are placed before
* their parents.
*/
private void extractDynamicElements(Method[] methods) {
loop:
for (int i =3D 0; i < methods.length; ++i) {
Method method =3D methods[i];
Class[] args =3D method.getParameterTypes();
if (args.length !=3D 1)
continue loop;
if (! method.getName().equals("dynamicElement"))
continue loop;
for (int m =3D 0; m < nestedDynamicMethods.size(); ++m) {
Method current =3D (Method) nestedDynamicMethods.elementAt(=
m);
if (current.getParameterTypes()[0].isAssignableFrom(
method.getParameterTypes()[0]))
{
nestedDynamicMethods.insertElementAt(method, m);
continue loop;
}
}
nestedDynamicMethods.addElement(method);
}
}
/**
* Search the list of methods to find the first method
* that has a parameter that accepts the dynamic element object
*/
private Method getMatchingMethod(Class paramClass) {
for (int i =3D 0; i < nestedDynamicMethods.size(); ++i) {
Method method =3D (Method) nestedDynamicMethods.elementAt(i);
if (method.getParameterTypes()[0].isAssignableFrom(paramClass))
return method;
}
return null;
}
}
--=-0MXqqbMLZSwXFgPqllWC
Content-Disposition: attachment; filename=DynamicElementTask.java
Content-Transfer-Encoding: quoted-printable
Content-Type: text/x-java; name=DynamicElementTask.java; charset=UTF-8
package net.sf.antcontrib.util;
import java.util.Vector;
import java.lang.reflect.Method;
import java.lang.reflect.InvocationTargetException;
import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.DynamicConfigurator;
import org.apache.tools.ant.RuntimeConfigurable;
import org.apache.tools.ant.Task;
import org.apache.tools.ant.UnknownElement;
import org.apache.tools.ant.types.EnumeratedAttribute;
import org.apache.tools.ant.taskdefs.condition.Condition;
/**
* Abstract class to use DynamicElementHelper to
* use refection to find methods called dynamicElement.
* This class implements DynamicConfiguator.
* The class may be used as a basis for a task or a
* type.
*/
public abstract class DynamicElementTask
extends Task
implements DynamicConfigurator
{
=20
private DynamicElementHelper dynamicElementHelper =3D null;
public Object createDynamicElement(String name) {
if (dynamicElementHelper =3D=3D null) {
dynamicElementHelper =3D new DynamicElementHelper(
this.getClass());
}
Object ret =3D dynamicElementHelper.createDynamicElement(
getProject(), this, name);
if (ret =3D=3D null)
throw new BuildException("Unknown Element " + name);
return ret;
}
=20
public void setDynamicAttribute(String name, String value) {
throw new BuildException("Unknown attribute " + name);
}
}
--=-0MXqqbMLZSwXFgPqllWC--