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. | * 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 | Changes from Ant 1.6.1 to current Ant 1.6 CVS version | ||||
| ===================================================== | ===================================================== | ||||
| @@ -76,6 +76,15 @@ Abstract Base class for unpack tasks. | |||||
| </td> | </td> | ||||
| </tr> | </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> | </tbody> | ||||
| </table> | </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; | package org.apache.tools.ant; | ||||
| import java.lang.reflect.InvocationTargetException; | |||||
| import java.lang.reflect.Method; | import java.lang.reflect.Method; | ||||
| import org.apache.tools.ant.dispatch.Dispatchable; | |||||
| /** | /** | ||||
| * Uses introspection to "adapt" an arbitrary Bean which doesn't | * 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. | * 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 | * This only checks conditions which are additionally required for | ||||
| * tasks adapted by TaskAdapter. Thus, this method should be called by | * 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, | public static void checkTaskClass(final Class taskClass, | ||||
| final Project project) { | 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. | // 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()); | 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. | * Executes the proxied task. | ||||
| * | * | ||||
| @@ -113,11 +151,12 @@ public class TaskAdapter extends Task implements TypeAdapter { | |||||
| Method executeM = null; | Method executeM = null; | ||||
| try { | try { | ||||
| Class c = proxy.getClass(); | 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) { | if (executeM == null) { | ||||
| log("No public execute() in " + proxy.getClass(), | |||||
| log("No public " + methodName + " in " + proxy.getClass(), | |||||
| Project.MSG_ERR); | Project.MSG_ERR); | ||||
| throw new BuildException("No public execute() in " | |||||
| throw new BuildException("No public " + methodName + "() in " | |||||
| + proxy.getClass()); | + proxy.getClass()); | ||||
| } | } | ||||
| executeM.invoke(proxy, null); | 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"); | |||||
| } | |||||
| } | |||||