KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > tools > ant > taskdefs > ExecuteJava


1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one or more
3  * contributor license agreements. See the NOTICE file distributed with
4  * this work for additional information regarding copyright ownership.
5  * The ASF licenses this file to You under the Apache License, Version 2.0
6  * (the "License"); you may not use this file except in compliance with
7  * the License. You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  */

18
19 package org.apache.tools.ant.taskdefs;
20
21 import java.io.File JavaDoc;
22 import java.io.IOException JavaDoc;
23 import java.io.PrintStream JavaDoc;
24 import java.lang.reflect.InvocationTargetException JavaDoc;
25 import java.lang.reflect.Method JavaDoc;
26 import java.lang.reflect.Modifier JavaDoc;
27 import org.apache.tools.ant.AntClassLoader;
28 import org.apache.tools.ant.BuildException;
29 import org.apache.tools.ant.Project;
30 import org.apache.tools.ant.ProjectComponent;
31 import org.apache.tools.ant.Task;
32 import org.apache.tools.ant.taskdefs.condition.Os;
33 import org.apache.tools.ant.types.Commandline;
34 import org.apache.tools.ant.types.CommandlineJava;
35 import org.apache.tools.ant.types.Path;
36 import org.apache.tools.ant.types.Permissions;
37 import org.apache.tools.ant.util.JavaEnvUtils;
38 import org.apache.tools.ant.util.TimeoutObserver;
39 import org.apache.tools.ant.util.Watchdog;
40
41 /**
42  * Execute a Java class.
43  * @since Ant 1.2
44  */

45 public class ExecuteJava implements Runnable JavaDoc, TimeoutObserver {
46
47     private Commandline javaCommand = null;
48     private Path classpath = null;
49     private CommandlineJava.SysProperties sysProperties = null;
50     private Permissions perm = null;
51     private Method JavaDoc main = null;
52     private Long JavaDoc timeout = null;
53     private volatile Throwable JavaDoc caught = null;
54     private volatile boolean timedOut = false;
55     private Thread JavaDoc thread = null;
56
57     /**
58      * Set the Java "command" for this ExecuteJava.
59      * @param javaCommand the classname and arguments in a Commandline.
60      */

61     public void setJavaCommand(Commandline javaCommand) {
62         this.javaCommand = javaCommand;
63     }
64
65     /**
66      * Set the classpath to be used when running the Java class.
67      *
68      * @param p an Ant Path object containing the classpath.
69      */

70     public void setClasspath(Path p) {
71         classpath = p;
72     }
73
74     /**
75      * Set the system properties to use when running the Java class.
76      * @param s CommandlineJava system properties.
77      */

78     public void setSystemProperties(CommandlineJava.SysProperties s) {
79         sysProperties = s;
80     }
81
82     /**
83      * Set the permissions for the application run.
84      * @param permissions the Permissions to use.
85      * @since Ant 1.6
86      */

87     public void setPermissions(Permissions permissions) {
88         perm = permissions;
89     }
90
91     /**
92      * Set the stream to which all output (System.out as well as System.err)
93      * will be written.
94      * @param out the PrintStream where output should be sent.
95      * @deprecated since 1.4.x.
96      * manage output at the task level.
97      */

98     public void setOutput(PrintStream JavaDoc out) {
99     }
100
101     /**
102      * Set the timeout for this ExecuteJava.
103      * @param timeout timeout as Long.
104      * @since Ant 1.5
105      */

106     public void setTimeout(Long JavaDoc timeout) {
107         this.timeout = timeout;
108     }
109
110     /**
111      * Execute the Java class against the specified Ant Project.
112      * @param project the Project to use.
113      * @throws BuildException on error.
114      */

115     public void execute(Project project) throws BuildException {
116         final String JavaDoc classname = javaCommand.getExecutable();
117
118         AntClassLoader loader = null;
119         try {
120             if (sysProperties != null) {
121                 sysProperties.setSystem();
122             }
123             Class JavaDoc target = null;
124             try {
125                 if (classpath == null) {
126                     target = Class.forName(classname);
127                 } else {
128                     loader = project.createClassLoader(classpath);
129                     loader.setParent(project.getCoreLoader());
130                     loader.setParentFirst(false);
131                     loader.addJavaLibraries();
132                     loader.setIsolated(true);
133                     loader.setThreadContextLoader();
134                     loader.forceLoadClass(classname);
135                     target = Class.forName(classname, true, loader);
136                 }
137             } catch (ClassNotFoundException JavaDoc e) {
138                 throw new BuildException("Could not find " + classname + "."
139                                          + " Make sure you have it in your"
140                                          + " classpath");
141             }
142             main = target.getMethod("main", new Class JavaDoc[] {String JavaDoc[].class});
143             if (main == null) {
144                 throw new BuildException("Could not find main() method in "
145                                          + classname);
146             }
147             if ((main.getModifiers() & Modifier.STATIC) == 0) {
148                 throw new BuildException("main() method in " + classname
149                     + " is not declared static");
150             }
151             if (timeout == null) {
152                 run();
153             } else {
154                 thread = new Thread JavaDoc(this, "ExecuteJava");
155                 Task currentThreadTask
156                     = project.getThreadTask(Thread.currentThread());
157                 // XXX is the following really necessary? it is in the same thread group...
158
project.registerThreadTask(thread, currentThreadTask);
159                 // if we run into a timeout, the run-away thread shall not
160
// make the VM run forever - if no timeout occurs, Ant's
161
// main thread will still be there to let the new thread
162
// finish
163
thread.setDaemon(true);
164                 Watchdog w = new Watchdog(timeout.longValue());
165                 w.addTimeoutObserver(this);
166                 synchronized (this) {
167                     thread.start();
168                     w.start();
169                     try {
170                         wait();
171                     } catch (InterruptedException JavaDoc e) {
172                         // ignore
173
}
174                     if (timedOut) {
175                         project.log("Timeout: sub-process interrupted",
176                                     Project.MSG_WARN);
177                     } else {
178                         thread = null;
179                         w.stop();
180                     }
181                 }
182             }
183             if (caught != null) {
184                 throw caught;
185             }
186         } catch (BuildException e) {
187             throw e;
188         } catch (SecurityException JavaDoc e) {
189             throw e;
190         } catch (ThreadDeath JavaDoc e) {
191             // XXX could perhaps also call thread.stop(); not sure if anyone cares
192
throw e;
193         } catch (Throwable JavaDoc e) {
194             throw new BuildException(e);
195         } finally {
196             if (loader != null) {
197                 loader.resetThreadContextLoader();
198                 loader.cleanup();
199                 loader = null;
200             }
201             if (sysProperties != null) {
202                 sysProperties.restoreSystem();
203             }
204         }
205     }
206
207     /**
208      * Run this ExecuteJava in a Thread.
209      * @since Ant 1.5
210      */

211     public void run() {
212         final Object JavaDoc[] argument = {javaCommand.getArguments()};
213         try {
214             if (perm != null) {
215                 perm.setSecurityManager();
216             }
217             main.invoke(null, argument);
218         } catch (InvocationTargetException JavaDoc e) {
219             Throwable JavaDoc t = e.getTargetException();
220             if (!(t instanceof InterruptedException JavaDoc)) {
221                 caught = t;
222             } /* else { swallow, probably due to timeout } */
223         } catch (Throwable JavaDoc t) {
224             caught = t;
225         } finally {
226             if (perm != null) {
227                 perm.restoreSecurityManager();
228             }
229             synchronized (this) {
230                 notifyAll();
231             }
232         }
233     }
234
235     /**
236      * Mark timeout as having occurred.
237      * @param w the responsible Watchdog.
238      * @since Ant 1.5
239      */

240     public synchronized void timeoutOccured(Watchdog w) {
241         if (thread != null) {
242             timedOut = true;
243             thread.interrupt();
244         }
245         notifyAll();
246     }
247
248     /**
249      * Get whether the process was killed.
250      * @return <code>true</code> if the process was killed, false otherwise.
251      * @since 1.19, Ant 1.5
252      */

253     public synchronized boolean killedProcess() {
254         return timedOut;
255     }
256
257     /**
258      * Run the Java command in a separate VM, this does not give you
259      * the full flexibility of the Java task, but may be enough for
260      * simple needs.
261      * @param pc the ProjectComponent to use for logging, etc.
262      * @return the exit status of the subprocess.
263      * @throws BuildException on error.
264      * @since Ant 1.6.3
265      */

266     public int fork(ProjectComponent pc) throws BuildException {
267         CommandlineJava cmdl = new CommandlineJava();
268         cmdl.setClassname(javaCommand.getExecutable());
269         String JavaDoc[] args = javaCommand.getArguments();
270         for (int i = 0; i < args.length; i++) {
271             cmdl.createArgument().setValue(args[i]);
272         }
273         if (classpath != null) {
274             cmdl.createClasspath(pc.getProject()).append(classpath);
275         }
276         if (sysProperties != null) {
277             cmdl.addSysproperties(sysProperties);
278         }
279         Redirector redirector = new Redirector(pc);
280         Execute exe
281             = new Execute(redirector.createHandler(),
282                           timeout == null
283                           ? null
284                           : new ExecuteWatchdog(timeout.longValue()));
285         exe.setAntRun(pc.getProject());
286         if (Os.isFamily("openvms")) {
287             setupCommandLineForVMS(exe, cmdl.getCommandline());
288         } else {
289             exe.setCommandline(cmdl.getCommandline());
290         }
291         try {
292             int rc = exe.execute();
293             redirector.complete();
294             return rc;
295         } catch (IOException JavaDoc e) {
296             throw new BuildException(e);
297         } finally {
298             timedOut = exe.killedProcess();
299         }
300     }
301
302     /**
303      * On VMS platform, we need to create a special java options file
304      * containing the arguments and classpath for the java command.
305      * The special file is supported by the "-V" switch on the VMS JVM.
306      *
307      * @param exe the Execute instance to alter.
308      * @param command the command-line.
309      */

310     public static void setupCommandLineForVMS(Execute exe, String JavaDoc[] command) {
311         //Use the VM launcher instead of shell launcher on VMS
312
exe.setVMLauncher(true);
313         File JavaDoc vmsJavaOptionFile = null;
314         try {
315             String JavaDoc [] args = new String JavaDoc[command.length - 1];
316             System.arraycopy(command, 1, args, 0, command.length - 1);
317             vmsJavaOptionFile = JavaEnvUtils.createVmsJavaOptionFile(args);
318             //we mark the file to be deleted on exit.
319
//the alternative would be to cache the filename and delete
320
//after execution finished, which is much better for long-lived runtimes
321
//though spawning complicates things...
322
vmsJavaOptionFile.deleteOnExit();
323             String JavaDoc [] vmsCmd = {command[0], "-V", vmsJavaOptionFile.getPath()};
324             exe.setCommandline(vmsCmd);
325         } catch (IOException JavaDoc e) {
326             throw new BuildException("Failed to create a temporary file for \"-V\" switch");
327         }
328     }
329
330 }
331
Popular Tags