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