git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@276533 13f79535-47bb-0310-9956-ffa450edef68master
| @@ -30,6 +30,9 @@ Other changes: | |||
| * Changed default tempdir for <javac> from user.dir to java.io.tmpdir. | |||
| * A new base class DispatchTask has been added to facilitate elegant | |||
| creation of tasks with multiple actions. | |||
| Changes from Ant 1.6.1 to current Ant 1.6 CVS version | |||
| ===================================================== | |||
| @@ -76,6 +76,15 @@ Abstract Base class for unpack tasks. | |||
| </td> | |||
| </tr> | |||
| <tr> | |||
| <td> | |||
| <a href="api/org/apache/tools/ant/dispatch/DispatchTask.html">DispatchTask</a> | |||
| </td> | |||
| <td> | |||
| Abstract Base class for tasks that may have multiple actions. | |||
| </td> | |||
| </tr> | |||
| </tbody> | |||
| </table> | |||
| @@ -0,0 +1,18 @@ | |||
| <?xml version="1.0"?> | |||
| <project name="dispatch-test" default="disp"> | |||
| <path id="testclasses"> | |||
| <pathelement location="../../../../build/testcases" /> | |||
| <pathelement path="${java.class.path}" /> | |||
| </path> | |||
| <target name="disp"> | |||
| <taskdef name="disptask" | |||
| classname="org.apache.tools.ant.taskdefs.PickOneTask"> | |||
| <classpath refid="testclasses" /> | |||
| </taskdef> | |||
| <disptask action="list"/> | |||
| </target> | |||
| </project> | |||
| @@ -17,7 +17,9 @@ | |||
| package org.apache.tools.ant; | |||
| import java.lang.reflect.InvocationTargetException; | |||
| import java.lang.reflect.Method; | |||
| import org.apache.tools.ant.dispatch.Dispatchable; | |||
| /** | |||
| * Uses introspection to "adapt" an arbitrary Bean which doesn't | |||
| @@ -32,6 +34,9 @@ public class TaskAdapter extends Task implements TypeAdapter { | |||
| /** | |||
| * Checks whether or not a class is suitable to be adapted by TaskAdapter. | |||
| * If the class is of type Dispatchable, the check is not performed because | |||
| * the method that will be executed will be determined only at runtime of | |||
| * the actual task and not during parse time. | |||
| * | |||
| * This only checks conditions which are additionally required for | |||
| * tasks adapted by TaskAdapter. Thus, this method should be called by | |||
| @@ -50,28 +55,30 @@ public class TaskAdapter extends Task implements TypeAdapter { | |||
| */ | |||
| public static void checkTaskClass(final Class taskClass, | |||
| final Project project) { | |||
| // don't have to check for interface, since then | |||
| // taskClass would be abstract too. | |||
| try { | |||
| final Method executeM = taskClass.getMethod("execute", null); | |||
| // don't have to check for public, since | |||
| // getMethod finds public method only. | |||
| // don't have to check for abstract, since then | |||
| if (!Dispatchable.class.isAssignableFrom(taskClass)) { | |||
| // don't have to check for interface, since then | |||
| // taskClass would be abstract too. | |||
| if (!Void.TYPE.equals(executeM.getReturnType())) { | |||
| final String message = "return type of execute() should be " | |||
| + "void but was \"" + executeM.getReturnType() + "\" in " | |||
| + taskClass; | |||
| project.log(message, Project.MSG_WARN); | |||
| try { | |||
| final Method executeM = taskClass.getMethod("execute", null); | |||
| // don't have to check for public, since | |||
| // getMethod finds public method only. | |||
| // don't have to check for abstract, since then | |||
| // taskClass would be abstract too. | |||
| if (!Void.TYPE.equals(executeM.getReturnType())) { | |||
| final String message = "return type of execute() should be " | |||
| + "void but was \"" + executeM.getReturnType() + "\" in " | |||
| + taskClass; | |||
| project.log(message, Project.MSG_WARN); | |||
| } | |||
| } catch (NoSuchMethodException e) { | |||
| final String message = "No public execute() in " + taskClass; | |||
| project.log(message, Project.MSG_ERR); | |||
| throw new BuildException(message); | |||
| } catch (LinkageError e) { | |||
| String message = "Could not load " + taskClass + ": " + e; | |||
| project.log(message, Project.MSG_ERR); | |||
| throw new BuildException(message, e); | |||
| } | |||
| } catch (NoSuchMethodException e) { | |||
| final String message = "No public execute() in " + taskClass; | |||
| project.log(message, Project.MSG_ERR); | |||
| throw new BuildException(message); | |||
| } catch (LinkageError e) { | |||
| String message = "Could not load " + taskClass + ": " + e; | |||
| project.log(message, Project.MSG_ERR); | |||
| throw new BuildException(message, e); | |||
| } | |||
| } | |||
| @@ -85,6 +92,37 @@ public class TaskAdapter extends Task implements TypeAdapter { | |||
| checkTaskClass(proxyClass, getProject()); | |||
| } | |||
| /** | |||
| * Returns the name of the action method that the task must | |||
| * execute. | |||
| */ | |||
| private final String getExecuteMethodName() throws NoSuchMethodException, | |||
| InvocationTargetException, IllegalAccessException { | |||
| String methodName = "execute"; | |||
| if (proxy instanceof Dispatchable) { | |||
| final Dispatchable dispatchable = (Dispatchable) proxy; | |||
| final String name = dispatchable.getActionParameterName(); | |||
| if (name != null && name.trim().length() > 0) { | |||
| String mName = "get" + name.trim().substring(0, 1).toUpperCase(); | |||
| if (name.length() > 1) { | |||
| mName += name.substring(1); | |||
| } | |||
| final Class c = proxy.getClass(); | |||
| final Method actionM = c.getMethod(mName, new Class[0]); | |||
| if (actionM != null) { | |||
| final Object o = actionM.invoke(proxy, null); | |||
| if (o != null) { | |||
| final String s = o.toString(); | |||
| if (s != null && s.trim().length() > 0) { | |||
| methodName = s.trim(); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| } | |||
| return methodName; | |||
| } | |||
| /** | |||
| * Executes the proxied task. | |||
| * | |||
| @@ -113,11 +151,12 @@ public class TaskAdapter extends Task implements TypeAdapter { | |||
| Method executeM = null; | |||
| try { | |||
| Class c = proxy.getClass(); | |||
| executeM = c.getMethod("execute", new Class[0]); | |||
| final String methodName = getExecuteMethodName(); | |||
| executeM = c.getMethod(methodName, new Class[0]); | |||
| if (executeM == null) { | |||
| log("No public execute() in " + proxy.getClass(), | |||
| log("No public " + methodName + " in " + proxy.getClass(), | |||
| Project.MSG_ERR); | |||
| throw new BuildException("No public execute() in " | |||
| throw new BuildException("No public " + methodName + "() in " | |||
| + proxy.getClass()); | |||
| } | |||
| executeM.invoke(proxy, null); | |||
| @@ -0,0 +1,46 @@ | |||
| /* | |||
| * Copyright 2004 The Apache Software Foundation | |||
| * | |||
| * Licensed under the Apache License, Version 2.0 (the "License"); | |||
| * you may not use this file except in compliance with the License. | |||
| * You may obtain a copy of the License at | |||
| * | |||
| * http://www.apache.org/licenses/LICENSE-2.0 | |||
| * | |||
| * Unless required by applicable law or agreed to in writing, software | |||
| * distributed under the License is distributed on an "AS IS" BASIS, | |||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
| * See the License for the specific language governing permissions and | |||
| * limitations under the License. | |||
| * | |||
| */ | |||
| package org.apache.tools.ant.dispatch; | |||
| import org.apache.tools.ant.Task; | |||
| /** | |||
| * Tasks extending this class may contain multiple actions. | |||
| * The method that is invoked for executoin depends upon the | |||
| * value of the action attribute of the task. | |||
| * <br/> | |||
| * Example:<br/> | |||
| * <mytask action="list"/> will invoke the method | |||
| * with the signature public void list() in mytask's class. | |||
| * If the action attribute is not defined in the task or is empty, | |||
| * the execute() method will be called. | |||
| */ | |||
| public abstract class DispatchTask implements Dispatchable { | |||
| private String action; | |||
| public String getActionParameterName() { | |||
| return "action"; | |||
| } | |||
| public void setAction(String action) { | |||
| this.action = action; | |||
| } | |||
| public String getAction() { | |||
| return action; | |||
| } | |||
| } | |||
| @@ -0,0 +1,26 @@ | |||
| /* | |||
| * Copyright 2004 The Apache Software Foundation | |||
| * | |||
| * Licensed under the Apache License, Version 2.0 (the "License"); | |||
| * you may not use this file except in compliance with the License. | |||
| * You may obtain a copy of the License at | |||
| * | |||
| * http://www.apache.org/licenses/LICENSE-2.0 | |||
| * | |||
| * Unless required by applicable law or agreed to in writing, software | |||
| * distributed under the License is distributed on an "AS IS" BASIS, | |||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
| * See the License for the specific language governing permissions and | |||
| * limitations under the License. | |||
| * | |||
| */ | |||
| package org.apache.tools.ant.dispatch; | |||
| /** | |||
| * Classes implementing this interface specify the | |||
| * name of the parameter that contains the name | |||
| * of the task's method to execute. | |||
| */ | |||
| public interface Dispatchable { | |||
| public String getActionParameterName(); | |||
| } | |||
| @@ -0,0 +1,35 @@ | |||
| /* | |||
| * Copyright 2004 The Apache Software Foundation | |||
| * | |||
| * Licensed under the Apache License, Version 2.0 (the "License"); | |||
| * you may not use this file except in compliance with the License. | |||
| * You may obtain a copy of the License at | |||
| * | |||
| * http://www.apache.org/licenses/LICENSE-2.0 | |||
| * | |||
| * Unless required by applicable law or agreed to in writing, software | |||
| * distributed under the License is distributed on an "AS IS" BASIS, | |||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
| * See the License for the specific language governing permissions and | |||
| * limitations under the License. | |||
| * | |||
| */ | |||
| package org.apache.tools.ant; | |||
| import org.apache.tools.ant.BuildFileTest; | |||
| public class DispatchTaskTest extends BuildFileTest { | |||
| public DispatchTaskTest(String name) { | |||
| super(name); | |||
| } | |||
| public void setUp() { | |||
| configureProject("src/etc/testcases/core/dispatch/dispatch.xml"); | |||
| } | |||
| public void testDisp() { | |||
| expectBuildException("disp", "list"); | |||
| } | |||
| } | |||
| @@ -0,0 +1,30 @@ | |||
| /* | |||
| * Copyright 2004 The Apache Software Foundation | |||
| * | |||
| * Licensed under the Apache License, Version 2.0 (the "License"); | |||
| * you may not use this file except in compliance with the License. | |||
| * You may obtain a copy of the License at | |||
| * | |||
| * http://www.apache.org/licenses/LICENSE-2.0 | |||
| * | |||
| * Unless required by applicable law or agreed to in writing, software | |||
| * distributed under the License is distributed on an "AS IS" BASIS, | |||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
| * See the License for the specific language governing permissions and | |||
| * limitations under the License. | |||
| * | |||
| */ | |||
| package org.apache.tools.ant; | |||
| import org.apache.tools.ant.dispatch.DispatchTask; | |||
| public class PickOneTask extends DispatchTask { | |||
| public void list() { | |||
| throw new BuildException("list"); | |||
| } | |||
| public void show() { | |||
| throw new BuildException("show"); | |||
| } | |||
| } | |||