You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

ExecuteJava.java 10 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298
  1. /*
  2. * Copyright 2000-2005 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.File;
  19. import java.io.IOException;
  20. import java.io.PrintStream;
  21. import java.lang.reflect.InvocationTargetException;
  22. import java.lang.reflect.Method;
  23. import java.lang.reflect.Modifier;
  24. import org.apache.tools.ant.AntClassLoader;
  25. import org.apache.tools.ant.BuildException;
  26. import org.apache.tools.ant.Project;
  27. import org.apache.tools.ant.ProjectComponent;
  28. import org.apache.tools.ant.Task;
  29. import org.apache.tools.ant.taskdefs.condition.Os;
  30. import org.apache.tools.ant.types.Commandline;
  31. import org.apache.tools.ant.types.CommandlineJava;
  32. import org.apache.tools.ant.types.Path;
  33. import org.apache.tools.ant.types.Permissions;
  34. import org.apache.tools.ant.util.JavaEnvUtils;
  35. import org.apache.tools.ant.util.TimeoutObserver;
  36. import org.apache.tools.ant.util.Watchdog;
  37. /**
  38. *
  39. * @since Ant 1.2
  40. */
  41. public class ExecuteJava implements Runnable, TimeoutObserver {
  42. private Commandline javaCommand = null;
  43. private Path classpath = null;
  44. private CommandlineJava.SysProperties sysProperties = null;
  45. private Permissions perm = null;
  46. private Method main = null;
  47. private Long timeout = null;
  48. private Throwable caught = null;
  49. private boolean timedOut = false;
  50. private Thread thread = null;
  51. public void setJavaCommand(Commandline javaCommand) {
  52. this.javaCommand = javaCommand;
  53. }
  54. /**
  55. * Set the classpath to be used when running the Java class
  56. *
  57. * @param p an Ant Path object containing the classpath.
  58. */
  59. public void setClasspath(Path p) {
  60. classpath = p;
  61. }
  62. public void setSystemProperties(CommandlineJava.SysProperties s) {
  63. sysProperties = s;
  64. }
  65. /**
  66. * Permissions for the application run.
  67. * @since Ant 1.6
  68. * @param permissions
  69. */
  70. public void setPermissions(Permissions permissions) {
  71. perm = permissions;
  72. }
  73. /**
  74. * All output (System.out as well as System.err) will be written
  75. * to this Stream.
  76. *
  77. * @deprecated manage output at the task level
  78. */
  79. public void setOutput(PrintStream out) {
  80. }
  81. /**
  82. * @since Ant 1.5
  83. */
  84. public void setTimeout(Long timeout) {
  85. this.timeout = timeout;
  86. }
  87. public void execute(Project project) throws BuildException {
  88. final String classname = javaCommand.getExecutable();
  89. AntClassLoader loader = null;
  90. try {
  91. if (sysProperties != null) {
  92. sysProperties.setSystem();
  93. }
  94. Class target = null;
  95. if (classpath == null) {
  96. target = Class.forName(classname);
  97. } else {
  98. loader = project.createClassLoader(classpath);
  99. loader.setParent(project.getCoreLoader());
  100. loader.setParentFirst(false);
  101. loader.addJavaLibraries();
  102. loader.setIsolated(true);
  103. loader.setThreadContextLoader();
  104. loader.forceLoadClass(classname);
  105. target = Class.forName(classname, true, loader);
  106. }
  107. main = target.getMethod("main", new Class[] {String[].class});
  108. if (main == null) {
  109. throw new BuildException("Could not find main() method in "
  110. + classname);
  111. }
  112. if ((main.getModifiers() & Modifier.STATIC) == 0) {
  113. throw new BuildException("main() method in " + classname
  114. + " is not declared static");
  115. }
  116. if (timeout == null) {
  117. run();
  118. } else {
  119. thread = new Thread(this, "ExecuteJava");
  120. Task currentThreadTask
  121. = project.getThreadTask(Thread.currentThread());
  122. project.registerThreadTask(thread, currentThreadTask);
  123. // if we run into a timeout, the run-away thread shall not
  124. // make the VM run forever - if no timeout occurs, Ant's
  125. // main thread will still be there to let the new thread
  126. // finish
  127. thread.setDaemon(true);
  128. Watchdog w = new Watchdog(timeout.longValue());
  129. w.addTimeoutObserver(this);
  130. synchronized (this) {
  131. thread.start();
  132. w.start();
  133. try {
  134. wait();
  135. } catch (InterruptedException e) {
  136. // ignore
  137. }
  138. if (timedOut) {
  139. project.log("Timeout: sub-process interrupted",
  140. Project.MSG_WARN);
  141. } else {
  142. thread = null;
  143. w.stop();
  144. }
  145. }
  146. }
  147. if (caught != null) {
  148. throw caught;
  149. }
  150. } catch (ClassNotFoundException e) {
  151. throw new BuildException("Could not find " + classname + "."
  152. + " Make sure you have it in your"
  153. + " classpath");
  154. } catch (SecurityException e) {
  155. throw e;
  156. } catch (Throwable e) {
  157. throw new BuildException(e);
  158. } finally {
  159. if (loader != null) {
  160. loader.resetThreadContextLoader();
  161. loader.cleanup();
  162. loader = null;
  163. }
  164. if (sysProperties != null) {
  165. sysProperties.restoreSystem();
  166. }
  167. }
  168. }
  169. /**
  170. * @since Ant 1.5
  171. */
  172. public void run() {
  173. final Object[] argument = {javaCommand.getArguments()};
  174. try {
  175. if (perm != null) {
  176. perm.setSecurityManager();
  177. }
  178. main.invoke(null, argument);
  179. } catch (InvocationTargetException e) {
  180. Throwable t = e.getTargetException();
  181. if (!(t instanceof InterruptedException)) {
  182. caught = t;
  183. } /* else { swallow, probably due to timeout } */
  184. } catch (Throwable t) {
  185. caught = t;
  186. } finally {
  187. if (perm != null) {
  188. perm.restoreSecurityManager();
  189. }
  190. synchronized (this) {
  191. notifyAll();
  192. }
  193. }
  194. }
  195. /**
  196. * @since Ant 1.5
  197. */
  198. public synchronized void timeoutOccured(Watchdog w) {
  199. if (thread != null) {
  200. timedOut = true;
  201. thread.interrupt();
  202. }
  203. notifyAll();
  204. }
  205. /**
  206. * @since 1.19, Ant 1.5
  207. */
  208. public synchronized boolean killedProcess() {
  209. return timedOut;
  210. }
  211. /**
  212. * Runs the Java command in a separate VM, this does not give you
  213. * the full flexibility of the Java task, but may be enough for
  214. * simple needs.
  215. *
  216. * @since Ant 1.6.3
  217. */
  218. public int fork(ProjectComponent pc) throws BuildException {
  219. CommandlineJava cmdl = new CommandlineJava();
  220. cmdl.setClassname(javaCommand.getExecutable());
  221. String[] args = javaCommand.getArguments();
  222. for (int i = 0; i < args.length; i++) {
  223. cmdl.createArgument().setValue(args[i]);
  224. }
  225. if (classpath != null) {
  226. cmdl.createClasspath(pc.getProject()).append(classpath);
  227. }
  228. if (sysProperties != null) {
  229. cmdl.addSysproperties(sysProperties);
  230. }
  231. Redirector redirector = new Redirector(pc);
  232. Execute exe
  233. = new Execute(redirector.createHandler(),
  234. timeout == null
  235. ? null
  236. : new ExecuteWatchdog(timeout.longValue()));
  237. exe.setAntRun(pc.getProject());
  238. if (Os.isFamily("openvms")) {
  239. setupCommandLineForVMS(exe, cmdl.getCommandline());
  240. } else {
  241. exe.setCommandline(cmdl.getCommandline());
  242. }
  243. try {
  244. int rc = exe.execute();
  245. redirector.complete();
  246. timedOut = exe.killedProcess();
  247. return rc;
  248. } catch (IOException e) {
  249. throw new BuildException(e);
  250. }
  251. }
  252. /**
  253. * On VMS platform, we need to create a special java options file
  254. * containing the arguments and classpath for the java command.
  255. * The special file is supported by the "-V" switch on the VMS JVM.
  256. *
  257. * @param exe
  258. * @param command
  259. */
  260. public static void setupCommandLineForVMS(Execute exe, String[] command) {
  261. //Use the VM launcher instead of shell launcher on VMS
  262. exe.setVMLauncher(true);
  263. File vmsJavaOptionFile = null;
  264. try {
  265. String [] args = new String[command.length - 1];
  266. System.arraycopy(command, 1, args, 0, command.length - 1);
  267. vmsJavaOptionFile = JavaEnvUtils.createVmsJavaOptionFile(args);
  268. //we mark the file to be deleted on exit.
  269. //the alternative would be to cache the filename and delete
  270. //after execution finished, which is much better for long-lived runtimes
  271. //though spawning complicates things...
  272. vmsJavaOptionFile.deleteOnExit();
  273. String [] vmsCmd = {command[0], "-V", vmsJavaOptionFile.getPath()};
  274. exe.setCommandline(vmsCmd);
  275. } catch (IOException e) {
  276. throw new BuildException("Failed to create a temporary file for \"-V\" switch");
  277. }
  278. }
  279. }