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.taskdefs;
  18. import java.io.PrintStream;
  19. import java.lang.reflect.InvocationTargetException;
  20. import java.lang.reflect.Method;
  21. import java.lang.reflect.Modifier;
  22. import org.apache.tools.ant.AntClassLoader;
  23. import org.apache.tools.ant.BuildException;
  24. import org.apache.tools.ant.Project;
  25. import org.apache.tools.ant.Task;
  26. import org.apache.tools.ant.types.Commandline;
  27. import org.apache.tools.ant.types.CommandlineJava;
  28. import org.apache.tools.ant.types.Path;
  29. import org.apache.tools.ant.types.Permissions;
  30. import org.apache.tools.ant.util.TimeoutObserver;
  31. import org.apache.tools.ant.util.Watchdog;
  32. /**
  33. *
  34. * @since Ant 1.2
  35. */
  36. public class ExecuteJava implements Runnable, TimeoutObserver {
  37. private Commandline javaCommand = null;
  38. private Path classpath = null;
  39. private CommandlineJava.SysProperties sysProperties = null;
  40. private Permissions perm = null;
  41. private Method main = null;
  42. private Long timeout = null;
  43. private Throwable caught = null;
  44. private boolean timedOut = false;
  45. private Thread thread = null;
  46. public void setJavaCommand(Commandline javaCommand) {
  47. this.javaCommand = javaCommand;
  48. }
  49. /**
  50. * Set the classpath to be used when running the Java class
  51. *
  52. * @param p an Ant Path object containing the classpath.
  53. */
  54. public void setClasspath(Path p) {
  55. classpath = p;
  56. }
  57. public void setSystemProperties(CommandlineJava.SysProperties s) {
  58. sysProperties = s;
  59. }
  60. /**
  61. * Permissions for the application run.
  62. * @since Ant 1.6
  63. * @param permissions
  64. */
  65. public void setPermissions(Permissions permissions) {
  66. perm = permissions;
  67. }
  68. /**
  69. * All output (System.out as well as System.err) will be written
  70. * to this Stream.
  71. *
  72. * @deprecated manage output at the task level
  73. */
  74. public void setOutput(PrintStream out) {
  75. }
  76. /**
  77. * @since Ant 1.5
  78. */
  79. public void setTimeout(Long timeout) {
  80. this.timeout = timeout;
  81. }
  82. public void execute(Project project) throws BuildException {
  83. final String classname = javaCommand.getExecutable();
  84. AntClassLoader loader = null;
  85. try {
  86. if (sysProperties != null) {
  87. sysProperties.setSystem();
  88. }
  89. final Class[] param = {Class.forName("[Ljava.lang.String;")};
  90. Class target = null;
  91. if (classpath == null) {
  92. target = Class.forName(classname);
  93. } else {
  94. loader = project.createClassLoader(classpath);
  95. loader.setParent(project.getCoreLoader());
  96. loader.setParentFirst(false);
  97. loader.addJavaLibraries();
  98. loader.setIsolated(true);
  99. loader.setThreadContextLoader();
  100. loader.forceLoadClass(classname);
  101. target = Class.forName(classname, true, loader);
  102. }
  103. main = target.getMethod("main", param);
  104. if (main == null) {
  105. throw new BuildException("Could not find main() method in "
  106. + classname);
  107. }
  108. if ((main.getModifiers() & Modifier.STATIC) == 0) {
  109. throw new BuildException("main() method in " + classname
  110. + " is not declared static");
  111. }
  112. if (timeout == null) {
  113. run();
  114. } else {
  115. thread = new Thread(this, "ExecuteJava");
  116. Task currentThreadTask
  117. = project.getThreadTask(Thread.currentThread());
  118. project.registerThreadTask(thread, currentThreadTask);
  119. // if we run into a timeout, the run-away thread shall not
  120. // make the VM run forever - if no timeout occurs, Ant's
  121. // main thread will still be there to let the new thread
  122. // finish
  123. thread.setDaemon(true);
  124. Watchdog w = new Watchdog(timeout.longValue());
  125. w.addTimeoutObserver(this);
  126. synchronized (this) {
  127. thread.start();
  128. w.start();
  129. try {
  130. wait();
  131. } catch (InterruptedException e) {
  132. // ignore
  133. }
  134. if (timedOut) {
  135. project.log("Timeout: sub-process interrupted",
  136. Project.MSG_WARN);
  137. } else {
  138. thread = null;
  139. w.stop();
  140. }
  141. }
  142. }
  143. if (caught != null) {
  144. throw caught;
  145. }
  146. } catch (ClassNotFoundException e) {
  147. throw new BuildException("Could not find " + classname + "."
  148. + " Make sure you have it in your"
  149. + " classpath");
  150. } catch (SecurityException e) {
  151. throw e;
  152. } catch (Throwable e) {
  153. throw new BuildException(e);
  154. } finally {
  155. if (loader != null) {
  156. loader.resetThreadContextLoader();
  157. loader.cleanup();
  158. }
  159. if (sysProperties != null) {
  160. sysProperties.restoreSystem();
  161. }
  162. }
  163. }
  164. /**
  165. * @since Ant 1.5
  166. */
  167. public void run() {
  168. final Object[] argument = {javaCommand.getArguments()};
  169. try {
  170. if (perm != null) {
  171. perm.setSecurityManager();
  172. }
  173. main.invoke(null, argument);
  174. } catch (InvocationTargetException e) {
  175. Throwable t = e.getTargetException();
  176. if (!(t instanceof InterruptedException)) {
  177. caught = t;
  178. } /* else { swallow, probably due to timeout } */
  179. } catch (Throwable t) {
  180. caught = t;
  181. } finally {
  182. if (perm != null) {
  183. perm.restoreSecurityManager();
  184. }
  185. synchronized (this) {
  186. notifyAll();
  187. }
  188. }
  189. }
  190. /**
  191. * @since Ant 1.5
  192. */
  193. public synchronized void timeoutOccured(Watchdog w) {
  194. if (thread != null) {
  195. timedOut = true;
  196. thread.interrupt();
  197. }
  198. notifyAll();
  199. }
  200. /**
  201. * @since 1.19, Ant 1.5
  202. */
  203. public synchronized boolean killedProcess() {
  204. return timedOut;
  205. }
  206. }