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. * 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
===================================================== =====================================================




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

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




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


+ 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