1. /*
  2. * Copyright 2000-2004 The Apache Software Foundation
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. *
  16. */
  17. package org.apache.tools.ant;
  18. import java.lang.reflect.Method;
  19. /**
  20. * Uses introspection to "adapt" an arbitrary Bean which doesn't
  21. * itself extend Task, but still contains an execute method and optionally
  22. * a setProject method.
  23. *
  24. */
  25. public class TaskAdapter extends Task implements TypeAdapter {
  26. /** Object to act as a proxy for. */
  27. private Object proxy;
  28. /**
  29. * Checks whether or not a class is suitable to be adapted by TaskAdapter.
  30. *
  31. * This only checks conditions which are additionally required for
  32. * tasks adapted by TaskAdapter. Thus, this method should be called by
  33. * Project.checkTaskClass.
  34. *
  35. * Throws a BuildException and logs as Project.MSG_ERR for
  36. * conditions that will cause the task execution to fail.
  37. * Logs other suspicious conditions with Project.MSG_WARN.
  38. *
  39. * @param taskClass Class to test for suitability.
  40. * Must not be <code>null</code>.
  41. * @param project Project to log warnings/errors to.
  42. * Must not be <code>null</code>.
  43. *
  44. * @see Project#checkTaskClass(Class)
  45. */
  46. public static void checkTaskClass(final Class taskClass,
  47. final Project project) {
  48. // don't have to check for interface, since then
  49. // taskClass would be abstract too.
  50. try {
  51. final Method executeM = taskClass.getMethod("execute", null);
  52. // don't have to check for public, since
  53. // getMethod finds public method only.
  54. // don't have to check for abstract, since then
  55. // taskClass would be abstract too.
  56. if (!Void.TYPE.equals(executeM.getReturnType())) {
  57. final String message = "return type of execute() should be "
  58. + "void but was \"" + executeM.getReturnType() + "\" in "
  59. + taskClass;
  60. project.log(message, Project.MSG_WARN);
  61. }
  62. } catch (NoSuchMethodException e) {
  63. final String message = "No public execute() in " + taskClass;
  64. project.log(message, Project.MSG_ERR);
  65. throw new BuildException(message);
  66. } catch (LinkageError e) {
  67. String message = "Could not load " + taskClass + ": " + e;
  68. project.log(message, Project.MSG_ERR);
  69. throw new BuildException(message, e);
  70. }
  71. }
  72. /**
  73. * check if the proxy class is a valid class to use
  74. * with this adapter.
  75. * the class must have a public no-arg "execute()" method.
  76. * @param proxyClass the class to check
  77. */
  78. public void checkProxyClass(Class proxyClass) {
  79. checkTaskClass(proxyClass, getProject());
  80. }
  81. /**
  82. * Executes the proxied task.
  83. *
  84. * @exception BuildException if the project could not be set
  85. * or the method could not be executed.
  86. */
  87. public void execute() throws BuildException {
  88. Method setProjectM = null;
  89. try {
  90. Class c = proxy.getClass();
  91. setProjectM =
  92. c.getMethod("setProject", new Class[] {Project.class});
  93. if (setProjectM != null) {
  94. setProjectM.invoke(proxy, new Object[] {getProject()});
  95. }
  96. } catch (NoSuchMethodException e) {
  97. // ignore this if the class being used as a task does not have
  98. // a set project method.
  99. } catch (Exception ex) {
  100. log("Error setting project in " + proxy.getClass(),
  101. Project.MSG_ERR);
  102. throw new BuildException(ex);
  103. }
  104. Method executeM = null;
  105. try {
  106. Class c = proxy.getClass();
  107. executeM = c.getMethod("execute", new Class[0]);
  108. if (executeM == null) {
  109. log("No public execute() in " + proxy.getClass(),
  110. Project.MSG_ERR);
  111. throw new BuildException("No public execute() in "
  112. + proxy.getClass());
  113. }
  114. executeM.invoke(proxy, null);
  115. return;
  116. } catch (java.lang.reflect.InvocationTargetException ie) {
  117. log("Error in " + proxy.getClass(), Project.MSG_VERBOSE);
  118. Throwable t = ie.getTargetException();
  119. if (t instanceof BuildException) {
  120. throw ((BuildException) t);
  121. } else {
  122. throw new BuildException(t);
  123. }
  124. } catch (Exception ex) {
  125. log("Error in " + proxy.getClass(), Project.MSG_VERBOSE);
  126. throw new BuildException(ex);
  127. }
  128. }
  129. /**
  130. * Sets the target object to proxy for.
  131. *
  132. * @param o The target object. Must not be <code>null</code>.
  133. */
  134. public void setProxy(Object o) {
  135. this.proxy = o;
  136. }
  137. /**
  138. * Returns the target object being proxied.
  139. *
  140. * @return the target proxy object
  141. */
  142. public Object getProxy() {
  143. return proxy;
  144. }
  145. }