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