From: peter r. <pet...@us...> - 2003-10-09 11:13:56
|
Update of /cvsroot/ant-contrib/ant-contrib/src/net/sf/antcontrib/logic In directory sc8-pr-cvs1:/tmp/cvs-serv18403 Modified Files: ForEach.java Log Message: Add initial version of macrodef based version of foreach This adds the processing of <sequential> to <foreach>. The code uses reflection so to detects if the ant runtime supports the macrodef task. The code uses a public method on MacroInstance which is not available in the released ant 1.6 beta1, and so needs a current ant nightly build (after oct 8 2003). use a <sequential> in-line instead of a target. <foreach list="a,b,c" param="x"> <sequential> <echo>x is ${x}</echo> </sequential> </foreach> the target version works as before <foreach list="a,b,c" param="x" target="doecho"/> Index: ForEach.java =================================================================== RCS file: /cvsroot/ant-contrib/ant-contrib/src/net/sf/antcontrib/logic/ForEach.java,v retrieving revision 1.13 retrieving revision 1.14 diff -C2 -d -r1.13 -r1.14 *** ForEach.java 3 Oct 2003 03:20:32 -0000 1.13 --- ForEach.java 9 Oct 2003 11:13:52 -0000 1.14 *************** *** 52,55 **** --- 52,58 ---- import java.util.StringTokenizer; import java.util.Vector; + import java.lang.reflect.Constructor; + import java.lang.reflect.InvocationTargetException; + import java.lang.reflect.Method; import org.apache.tools.ant.BuildException; *************** *** 98,103 **** * @author <a href="mailto:mat...@mi...">Matthew Inger</a> */ ! public class ForEach extends Task { private String list; private String param; --- 101,119 ---- * @author <a href="mailto:mat...@mi...">Matthew Inger</a> */ ! public class ForEach extends Task implements TaskContainer { + private static boolean antVersionOk = true; + static { + try { + Class c = Class.forName( + "org.apache.tools.ant.taskdefs.MacroInstance"); + Class c2 = Class.forName( + "org.apache.tools.ant.taskdefs.MacroDef"); + Method m = c.getMethod("setMacroDef", new Class[]{c2}); + } catch (Throwable t) { + antVersionOk = false; + } + } + private String list; private String param; *************** *** 111,115 **** private boolean parallel; private boolean trim; ! private CallTarget currentTarget; --- 127,131 ---- private boolean parallel; private boolean trim; ! private Reflector macroDef; private CallTarget currentTarget; *************** *** 131,144 **** } public void execute() throws BuildException { if (list == null && currPath == null) { ! throw new BuildException("You must have a list or path to iterate through"); } if (param == null) ! throw new BuildException("You must supply a property name to set on each iteration in param"); ! if (target == null) ! throw new BuildException("You must supply a target to perform"); --- 147,278 ---- } + private static class Reflector { + private Object obj; + public Reflector(String name) { + try { + Class clazz; + clazz = Class.forName(name); + Constructor constructor; + constructor = clazz.getConstructor(new Class[]{}); + obj = constructor.newInstance(new Object[]{}); + } catch (Throwable t) { + throw new BuildException(t); + } + } + public Object getObject() { + return obj; + } + public void call(String methodName) { + try { + Method method; + method = obj.getClass().getMethod( + methodName, new Class[] {}); + method.invoke(obj, new Object[] {}); + } catch (InvocationTargetException t) { + Throwable t2 = t.getTargetException(); + if (t2 instanceof BuildException) { + throw (BuildException) t2; + } + throw new BuildException(t2); + } catch (Throwable t) { + throw new BuildException(t); + } + } + + public void callExplicit(String methodName, String className, Object o) { + try { + Method method; + Class clazz = Class.forName(className); + method = obj.getClass().getMethod( + methodName, new Class[] {clazz}); + method.invoke(obj, new Object[] {o}); + } catch (InvocationTargetException t) { + Throwable t2 = t.getTargetException(); + if (t2 instanceof BuildException) { + throw (BuildException) t2; + } + throw new BuildException(t2); + } catch (Throwable t) { + throw new BuildException(t); + } + } + public void call(String methodName, Object o) { + try { + Method method; + method = obj.getClass().getMethod( + methodName, new Class[] {o.getClass()}); + method.invoke(obj, new Object[] {o}); + } catch (InvocationTargetException t) { + Throwable t2 = t.getTargetException(); + if (t2 instanceof BuildException) { + throw (BuildException) t2; + } + throw new BuildException(t2); + } catch (Throwable t) { + throw new BuildException(t); + } + } + public void call(String methodName, Object o1, Object o2) { + try { + Method method; + method = obj.getClass().getMethod( + methodName, new Class[] {o1.getClass(), o2.getClass()}); + method.invoke(obj, new Object[] {o1, o2}); + } catch (InvocationTargetException t) { + Throwable t2 = t.getTargetException(); + if (t2 instanceof BuildException) { + throw (BuildException) t2; + } + throw new BuildException(t2); + } catch (Throwable t) { + throw new BuildException(t); + } + } + }; + + /** + * Add a nested task to Foreach + * @param nestedTask Nested task/type should be sequential + */ + public void addTask(Task nestedTask) { + if (nestedTask.getTaskName().indexOf("sequential") == -1) { + throw new BuildException("Unsupported nested element " + + nestedTask.getTaskName()); + } + if (!antVersionOk) { + throw new BuildException("Only allowed for ant >= 1.6Beta2"); + } + if (macroDef != null) { + throw new BuildException("Only one sequential allowed"); + } + macroDef = new Reflector("org.apache.tools.ant.taskdefs.MacroDef"); + macroDef.call("setProject", getProject()); + macroDef.callExplicit("addTask", Task.class.getName(), nestedTask); + } + public void execute() throws BuildException { if (list == null && currPath == null) { ! throw new BuildException( ! "You must have a list or path to iterate through"); } if (param == null) ! throw new BuildException( ! "You must supply a property name to set on each iteration in param"); ! if (target == null && macroDef == null) ! throw new BuildException( ! "You must supply a target or an embedded sequential " ! + "to perform"); ! ! if (target != null && macroDef != null) { ! throw new BuildException( ! "You must only supply either a target" + ! " or a sequential to perform"); ! } ! if (macroDef != null) { ! doTheTasks(); ! return; ! } *************** *** 157,168 **** if (trim) tok = tok.trim(); values.addElement(tok); - /* - CallTarget ct = createCallTarget(); - currentTarget = ct; - Property p = ct.createParam(); - p.setName(param); - p.setValue(tok); - ct.execute(); - */ } } --- 291,294 ---- *************** *** 203,206 **** --- 329,379 ---- ((Task)tc).execute(); + } + + + private void doSequentialIteration(String val) { + Reflector instance = new Reflector( + "org.apache.tools.ant.taskdefs.MacroInstance"); + instance.call("setProject", getProject()); + instance.call("setOwningTarget", getOwningTarget()); + instance.call("setMacroDef", macroDef.getObject()); + instance.call("setDynamicAttribute", param, val); + instance.call("execute"); + } + + private void doTheTasks() { + if (params.size() != 0 || references.size() != 0) { + throw new BuildException( + "It is not allowed to use <param> or <reference>" + + " elements with a <sequential> element."); + } + // Create a macro attribute + Reflector attribute = new Reflector( + "org.apache.tools.ant.taskdefs.MacroDef$Attribute"); + attribute.call("setName", param); + macroDef.call("addConfiguredAttribute", + attribute.getObject()); + // Take Care of the list attribute + if (list != null) { + StringTokenizer st = new StringTokenizer(list, delimiter); + String toks[] = new String[st.countTokens()]; + int i = 0; + + while (st.hasMoreTokens()) { + String tok = st.nextToken(); + if (trim) tok = tok.trim(); + doSequentialIteration(tok); + } + } + + String[] pathElements = new String[0]; + if (currPath != null) { + pathElements = currPath.list(); + } + + for (int i = 0; i < pathElements.length; i++) { + File nextFile = new File(pathElements[i]); + doSequentialIteration(nextFile.getAbsolutePath()); + } } |