Browse Source

Tasks extending from abstract DispatchTask may have multiple action methods that will get invoked depending upon the action attribute of the task.

git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@276533 13f79535-47bb-0310-9956-ffa450edef68
master
Magesh Umasankar 21 years ago
parent
commit
9f1eefd3a2
8 changed files with 229 additions and 23 deletions
  1. +3
    -0
      WHATSNEW
  2. +9
    -0
      docs/manual/base_task_classes.html
  3. +18
    -0
      src/etc/testcases/core/dispatch/dispatch.xml
  4. +62
    -23
      src/main/org/apache/tools/ant/TaskAdapter.java
  5. +46
    -0
      src/main/org/apache/tools/ant/dispatch/DispatchTask.java
  6. +26
    -0
      src/main/org/apache/tools/ant/dispatch/Dispatchable.java
  7. +35
    -0
      src/testcases/org/apache/tools/ant/DispatchTaskTest.java
  8. +30
    -0
      src/testcases/org/apache/tools/ant/PickOneTask.java

+ 3
- 0
WHATSNEW View File

@@ -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
=====================================================



+ 9
- 0
docs/manual/base_task_classes.html View File

@@ -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>



+ 18
- 0
src/etc/testcases/core/dispatch/dispatch.xml View File

@@ -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>

+ 62
- 23
src/main/org/apache/tools/ant/TaskAdapter.java View File

@@ -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);


+ 46
- 0
src/main/org/apache/tools/ant/dispatch/DispatchTask.java View File

@@ -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/>
* &lt;mytask action=&quot;list&quot;/&gt; 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;
}
}

+ 26
- 0
src/main/org/apache/tools/ant/dispatch/Dispatchable.java View File

@@ -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();
}

+ 35
- 0
src/testcases/org/apache/tools/ant/DispatchTaskTest.java View File

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

+ 30
- 0
src/testcases/org/apache/tools/ant/PickOneTask.java View File

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

Loading…
Cancel
Save