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 package org.apache.commons.launcher;
19
20 import java.io.File;
21 import java.io.FileOutputStream;
22 import java.io.IOException;
23 import java.net.URL;
24 import java.net.URLClassLoader;
25 import java.util.ArrayList;
26 import java.util.HashMap;
27 import java.util.Iterator;
28 import java.util.StringTokenizer;
29 import org.apache.commons.launcher.types.ArgumentSet;
30 import org.apache.commons.launcher.types.ConditionalArgument;
31 import org.apache.commons.launcher.types.ConditionalVariable;
32 import org.apache.commons.launcher.types.JVMArgumentSet;
33 import org.apache.commons.launcher.types.SysPropertySet;
34 import org.apache.tools.ant.BuildException;
35 import org.apache.tools.ant.Task;
36 import org.apache.tools.ant.types.Path;
37 import org.apache.tools.ant.types.Reference;
38
39 /**
40 * A class that eliminates the need for a batch or shell script to launch a Java
41 * class. Some situations where elimination of a batch or shell script may be
42 * desirable are:
43 * <ul>
44 * <li>You want to avoid having to determining where certain application paths
45 * are e.g. your application's home directory, etc. Determining this
46 * dynamically in a Windows batch scripts is very tricky on some versions of
47 * Windows or when softlinks are used on Unix platforms.
48 * <li>You want to avoid having to handle native file and path separators or
49 * native path quoting issues.
50 * <li>You need to enforce certain system properties e.g.
51 * <code>java.endorsed.dirs</code> when running with JDK 1.4.
52 * <li>You want to allow users to pass in custom JVM arguments or system
53 * properties without having to parse and reorder arguments in your script.
54 * This can be tricky and/or messy in batch and shell scripts.
55 * <li>You want to bootstrap system properties from a configuration file instead
56 * hard-coding them in your batch and shell scripts.
57 * <li>You want to provide localized error messages which is very tricky to do
58 * in batch and shell scripts.
59 * </ul>
60 *
61 * @author Patrick Luby
62 */
63 public class LaunchTask extends Task {
64
65 //----------------------------------------------------------- Static Fields
66
67 /**
68 * The argument property name.
69 */
70 public final static String ARG_PROP_NAME = "launch.arg.";
71
72 /**
73 * The name of this task.
74 */
75 public final static String TASK_NAME = "launch";
76
77 /**
78 * Cached synchronous child processes for all instances of this class.
79 */
80 private static ArrayList childProcesses = new ArrayList();
81
82 //------------------------------------------------------------------ Fields
83
84 /**
85 * Cached appendOutput flag.
86 */
87 private boolean appendOutput = false;
88
89 /**
90 * Cached synchronously executing child process.
91 */
92 private Process childProc = null;
93
94 /**
95 * Cached classpath.
96 */
97 private Path classpath = null;
98
99 /**
100 * Cached debug flag.
101 */
102 private boolean debug = false;
103
104 /**
105 * Cached displayMinimizedWindow flag.
106 */
107 private boolean displayMinimizedWindow = false;
108
109 /**
110 * Cached disposeMinimizedWindow flag.
111 */
112 private boolean disposeMinimizedWindow = true;
113
114 /**
115 * Cached failOnError flag.
116 */
117 private boolean failOnError = false;
118
119 /**
120 * Cached filter instance.
121 */
122 private LaunchFilter filter = null;
123
124 /**
125 * Cached filterClassName.
126 */
127 private String filterClassName = null;
128
129 /**
130 * Cached filterClasspath.
131 */
132 private Path filterClasspath = null;
133
134 /**
135 * Cached main class name.
136 */
137 private String mainClassName = null;
138
139 /**
140 * Cached minimizedWindowIcon.
141 */
142 private File minimizedWindowIcon = null;
143
144 /**
145 * Cached minimizedWindowTitle.
146 */
147 private String minimizedWindowTitle = null;
148
149 /**
150 * Cached output file.
151 */
152 private File outputFile = null;
153
154 /**
155 * Cached print flag.
156 */
157 private boolean print = false;
158
159 /**
160 * Cached redirect flag.
161 */
162 private boolean redirect = false;
163
164 /**
165 * Cached requireTools flag.
166 */
167 private boolean requireTools = false;
168
169 /**
170 * Cached arg elements
171 */
172 private ArgumentSet taskArgumentSet = new ArgumentSet();
173
174 /**
175 * Cached jvmarg elements
176 */
177 private JVMArgumentSet taskJVMArgumentSet = new JVMArgumentSet();
178
179 /**
180 * Cached sysproperty elements
181 */
182 private SysPropertySet taskSysPropertySet = new SysPropertySet();
183
184 /**
185 * Cached useArgs flag.
186 */
187 private boolean useArgs = true;
188
189 /**
190 * Cached useSystemIn flag.
191 */
192 private boolean useSystemIn = true;
193
194 /**
195 * Cached waitForChild flag.
196 */
197 private boolean waitForChild = true;
198
199 //---------------------------------------------------------- Static Methods
200
201 /**
202 * Get the synchronous child processes for all instances of this class.
203 *
204 * @return the instances of this class.
205 */
206 public static Process[] getChildProcesses() {
207
208 return (Process[])childProcesses.toArray(new Process[childProcesses.size()]);
209
210 }
211
212 //----------------------------------------------------------------- Methods
213
214 /**
215 * Add a nested arg element. Note that Ant will not invoke the specified
216 * arg object's setter methods until after Ant invokes this method so
217 * processing of the specified arg object is handled in the
218 * {@link #execute()} method.
219 *
220 * @param arg the arg element
221 */
222 public void addArg(ConditionalArgument arg) {
223
224 taskArgumentSet.addArg(arg);
225
226 }
227
228 /**
229 * Add a nested argset element.
230 *
231 * @param set the argset element
232 */
233 public void addArgset(ArgumentSet set) {
234
235 taskArgumentSet.addArgset(set);
236
237 }
238
239 /**
240 * Add a nested jvmarg element. Note that Ant will not invoke the specified
241 * jvmarg object's setter methods until after Ant invokes this method so
242 * processing of the specified jvmarg object is handled in the
243 * {@link #execute()} method.
244 *
245 * @param jvmArg the jvmarg element
246 */
247 public void addJvmarg(ConditionalArgument jvmArg) {
248
249 taskJVMArgumentSet.addJvmarg(jvmArg);
250
251 }
252
253 /**
254 * Add a nested jvmargset element.
255 *
256 * @param set the jvmargset element
257 */
258 public void addJvmargset(JVMArgumentSet set) {
259
260 taskJVMArgumentSet.addJvmargset(set);
261
262 }
263
264 /**
265 * Add a nested sysproperty element. Note that Ant will not invoke the
266 * specified sysproperty object's setter methods until after Ant invokes
267 * this method so processing of the specified sysproperty object is handled
268 * in the {@link #execute()} method.
269 *
270 * @param var the sysproperty element
271 */
272 public void addSysproperty(ConditionalVariable var) {
273
274 taskSysPropertySet.addSysproperty(var);
275
276 }
277
278 /**
279 * Add a nested syspropertyset element.
280 *
281 * @param set the syspropertyset element
282 */
283 public void addSyspropertyset(SysPropertySet set) {
284
285 taskSysPropertySet.addSyspropertyset(set);
286
287 }
288
289 /**
290 * Create a nested classpath element.
291 *
292 * @return the Path object that contains all nested classpath elements
293 */
294 public Path createClasspath() {
295
296 if (classpath == null)
297 classpath = new Path(project);
298 return classpath;
299
300 }
301
302 /**
303 * Create a nested filter classpath element.
304 *
305 * @return the Path object that contains all nested filter classpath
306 * elements
307 */
308 public Path createFilterclasspath() {
309
310 if (filterClasspath == null)
311 filterClasspath = new Path(project);
312 return filterClasspath;
313
314 }
315
316 /**
317 * Construct a Java command and execute it using the settings that Ant
318 * parsed from the Launcher's XML file. This method is called by the Ant
319 * classes.
320 *
321 * @throws BuildException if there is a configuration or other error
322 */
323 public void execute() throws BuildException {
324
325 try {
326
327 // Check that the Launcher class was used to start Ant as this
328 // task is not designed to use in a standalone Ant installation
329 if (!Launcher.isStarted())
330 throw new BuildException(Launcher.getLocalizedString("no.run.standalone", this.getClass().getName()));
331
332 // Don't do anything if the launching process has been stopped
333 if (Launcher.isStopped())
334 throw new BuildException();
335
336 if (mainClassName == null)
337 throw new BuildException(Launcher.getLocalizedString("classname.null", this.getClass().getName()));
338
339 // Copy all of the nested jvmarg elements into the jvmArgs object
340 ArrayList taskJVMArgs = taskJVMArgumentSet.getList();
341 ArrayList jvmArgs = new ArrayList(taskJVMArgs.size());
342 for (int i = 0; i < taskJVMArgs.size(); i++) {
343 ConditionalArgument value = (ConditionalArgument)taskJVMArgs.get(i);
344 // Test "if" and "unless" conditions
345 if (testIfCondition(value.getIf()) && testUnlessCondition(value.getUnless())) {
346 String[] list = value.getParts();
347 for (int j = 0; j < list.length; j++)
348 jvmArgs.add(list[j]);
349 }
350 }
351
352 // Copy all of the nested sysproperty elements into the sysProps
353 // object
354 ArrayList taskSysProps = taskSysPropertySet.getList();
355 HashMap sysProps = new HashMap(taskSysProps.size());
356 for (int i = 0; i < taskSysProps.size(); i++) {
357 ConditionalVariable variable = (ConditionalVariable)taskSysProps.get(i);
358 // Test "if" and "unless" conditions
359 if (testIfCondition(variable.getIf()) && testUnlessCondition(variable.getUnless()))
360 sysProps.put(variable.getKey(), variable.getValue());
361 }
362
363 // Copy all of the nested arg elements into the appArgs object
364 ArrayList taskArgs = taskArgumentSet.getList();
365 ArrayList appArgs = new ArrayList(taskArgs.size());
366 for (int i = 0; i < taskArgs.size(); i++) {
367 ConditionalArgument value = (ConditionalArgument)taskArgs.get(i);
368 // Test "if" and "unless" conditions
369 if (testIfCondition(value.getIf()) && testUnlessCondition(value.getUnless())) {
370 String[] list = value.getParts();
371 for (int j = 0; j < list.length; j++)
372 appArgs.add(list[j]);
373 }
374 }
375
376 // Add the Launcher's command line arguments to the appArgs object
377 if (useArgs) {
378 int currentArg = 0;
379 String arg = null;
380 while ((arg = project.getUserProperty(LaunchTask.ARG_PROP_NAME + Integer.toString(currentArg++))) != null)
381 appArgs.add(arg);
382 }
383
384 // Make working copies of some of the flags since they may get
385 // changed by a filter class
386 String filteredClasspath = null;
387 if (classpath != null)
388 filteredClasspath = classpath.toString();
389 String filteredMainClassName = mainClassName;
390 boolean filteredRedirect = redirect;
391 File filteredOutputFile = outputFile;
392 boolean filteredAppendOutput = appendOutput;
393 boolean filteredDebug = debug;
394 boolean filteredDisplayMinimizedWindow = displayMinimizedWindow;
395 boolean filteredDisposeMinimizedWindow = disposeMinimizedWindow;
396 boolean filteredFailOnError = failOnError;
397 String filteredMinimizedWindowTitle = minimizedWindowTitle;
398 File filteredMinimizedWindowIcon = minimizedWindowIcon;
399 boolean filteredPrint = print;
400 boolean filteredRequireTools = requireTools;
401 boolean filteredUseSystemIn = useSystemIn;
402 boolean filteredWaitForChild = waitForChild;
403
404 // If there is a filter in the filterclassname attribute, let it
405 // evaluate and edit the attributes and nested elements before we
406 // start evaluating them
407 if (filterClassName != null) {
408 if (filter == null) {
409 try {
410 ClassLoader loader = this.getClass().getClassLoader();
411 if (filterClasspath != null) {
412 // Construct a class loader to load the class
413 String[] fileList = filterClasspath.list();
414 URL[] urls = new URL[fileList.length];
415 for (int i = 0; i < fileList.length; i++)
416 urls[i] = new File(fileList[i]).toURL();
417 loader = new URLClassLoader(urls, loader);
418 }
419 Class filterClass = loader.loadClass(filterClassName);
420 filter = (LaunchFilter)filterClass.newInstance();
421 // Execute filter and save any changes
422 LaunchCommand command = new LaunchCommand();
423 command.setJvmargs(jvmArgs);
424 command.setSysproperties(sysProps);
425 command.setArgs(appArgs);
426 command.setClasspath(filteredClasspath);
427 command.setClassname(filteredMainClassName);
428 command.setRedirectoutput(filteredRedirect);
429 command.setOutput(filteredOutputFile);
430 command.setAppendoutput(filteredAppendOutput);
431 command.setDebug(filteredDebug);
432 command.setDisplayminimizedwindow(filteredDisplayMinimizedWindow);
433 command.setDisposeminimizedwindow(filteredDisposeMinimizedWindow);
434 command.setFailonerror(filteredFailOnError);
435 command.setMinimizedwindowtitle(filteredMinimizedWindowTitle);
436 command.setMinimizedwindowicon(filteredMinimizedWindowIcon);
437 command.setPrint(filteredPrint);
438 command.setRequiretools(filteredRequireTools);
439 command.setUsesystemin(filteredUseSystemIn);
440 command.setWaitforchild(filteredWaitForChild);
441 filter.filter(command);
442 jvmArgs = command.getJvmargs();
443 sysProps = command.getSysproperties();
444 appArgs = command.getArgs();
445 filteredClasspath = command.getClasspath();
446 filteredMainClassName = command.getClassname();
447 filteredRedirect = command.getRedirectoutput();
448 filteredOutputFile = command.getOutput();
449 filteredAppendOutput = command.getAppendoutput();
450 filteredDebug = command.getDebug();
451 filteredDisplayMinimizedWindow = command.getDisplayminimizedwindow();
452 filteredDisposeMinimizedWindow = command.getDisposeminimizedwindow();
453 filteredFailOnError = command.getFailonerror();
454 filteredMinimizedWindowTitle = command.getMinimizedwindowtitle();
455 filteredMinimizedWindowIcon = command.getMinimizedwindowicon();
456 filteredPrint = command.getPrint();
457 filteredRequireTools = command.getRequiretools();
458 filteredUseSystemIn = command.getUsesystemin();
459 filteredWaitForChild = command.getWaitforchild();
460 // Check changes
461 if (filteredMainClassName == null)
462 throw new BuildException(Launcher.getLocalizedString("classname.null", this.getClass().getName()));
463 if (jvmArgs == null)
464 jvmArgs = new ArrayList();
465 if (sysProps == null)
466 sysProps = new HashMap();
467 if (appArgs == null)
468 appArgs = new ArrayList();
469 } catch (BuildException be) {
470 throw new BuildException(filterClassName + " " + Launcher.getLocalizedString("filter.exception", this.getClass().getName()), be);
471 } catch (ClassCastException cce) {
472 throw new BuildException(filterClassName + " " + Launcher.getLocalizedString("filter.not.filter", this.getClass().getName()));
473 } catch (Exception e) {
474 throw new BuildException(e);
475 }
476 }
477 }
478
479 // Force child JVM into foreground if running using JDB
480 if (filteredDebug) {
481 filteredWaitForChild = true;
482 filteredUseSystemIn = true;
483 }
484
485 // Prepend standard paths to classpath
486 StringBuffer fullClasspath = new StringBuffer(Launcher.getBootstrapFile().getPath());
487 if (filteredRequireTools) {
488 fullClasspath.append(File.pathSeparator);
489 fullClasspath.append(Launcher.getToolsClasspath());
490 }
491 if (filteredClasspath != null) {
492 fullClasspath.append(File.pathSeparator);
493 fullClasspath.append(filteredClasspath);
494 }
495
496 // Set ChildMain.WAIT_FOR_CHILD_PROP_NAME property for child JVM
497 sysProps.remove(ChildMain.WAIT_FOR_CHILD_PROP_NAME);
498 if (filteredWaitForChild)
499 sysProps.put(ChildMain.WAIT_FOR_CHILD_PROP_NAME, "");
500
501 // Set minimized window properties for child JVM
502 sysProps.remove(ChildMain.DISPLAY_MINIMIZED_WINDOW_PROP_NAME);
503 sysProps.remove(ChildMain.MINIMIZED_WINDOW_TITLE_PROP_NAME);
504 sysProps.remove(ChildMain.MINIMIZED_WINDOW_ICON_PROP_NAME);
505 sysProps.remove(ChildMain.DISPOSE_MINIMIZED_WINDOW_PROP_NAME);
506 if (!filteredWaitForChild && filteredDisplayMinimizedWindow) {
507 sysProps.put(ChildMain.DISPLAY_MINIMIZED_WINDOW_PROP_NAME, "");
508 if (filteredMinimizedWindowTitle != null)
509 sysProps.put(ChildMain.MINIMIZED_WINDOW_TITLE_PROP_NAME, filteredMinimizedWindowTitle);
510 else
511 sysProps.put(ChildMain.MINIMIZED_WINDOW_TITLE_PROP_NAME, getOwningTarget().getName());
512 if (filteredMinimizedWindowIcon != null)
513 sysProps.put(ChildMain.MINIMIZED_WINDOW_ICON_PROP_NAME, filteredMinimizedWindowIcon.getCanonicalPath());
514 // Set ChildMain.DISPOSE_MINIMIZED_WINDOW_PROP_NAME property
515 if (filteredDisposeMinimizedWindow)
516 sysProps.put(ChildMain.DISPOSE_MINIMIZED_WINDOW_PROP_NAME, "");
517 }
518
519 // Set ChildMain.OUTPUT_FILE_PROP_NAME property for child JVM
520 sysProps.remove(ChildMain.OUTPUT_FILE_PROP_NAME);
521 if (!filteredWaitForChild && filteredRedirect) {
522 if (filteredOutputFile != null) {
523 String outputFilePath = filteredOutputFile.getCanonicalPath();
524 // Verify that we can write to the output file
525 try {
526 File parentFile = new File(filteredOutputFile.getParent());
527 // To take care of non-existent log directories
528 if ( !parentFile.exists() ) {
529 //Trying to create non-existent parent directories
530 parentFile.mkdirs();
531 //If this fails createNewFile also fails
532 //We can give more exact error message, if we choose
533 }
534 filteredOutputFile.createNewFile();
535 } catch (IOException ioe) {
536 throw new BuildException(outputFilePath + " " + Launcher.getLocalizedString("output.file.not.creatable", this.getClass().getName()));
537 }
538 if (!filteredOutputFile.canWrite())
539 throw new BuildException(outputFilePath + " " + Launcher.getLocalizedString("output.file.not.writable", this.getClass().getName()));
540 sysProps.put(ChildMain.OUTPUT_FILE_PROP_NAME, outputFilePath);
541 if (filteredAppendOutput)
542 sysProps.put(ChildMain.APPEND_OUTPUT_PROP_NAME, "");
543 Launcher.getLog().println(Launcher.getLocalizedString("redirect.notice", this.getClass().getName()) + " " + outputFilePath);
544 } else {
545 throw new BuildException(Launcher.getLocalizedString("output.file.null", this.getClass().getName()));
546 }
547 }
548
549 // Create the heartbeatFile. This file is needed by the
550 // ParentListener class on Windows since the entire child JVM
551 // process will block on Windows machines using some versions of
552 // Unix shells such as MKS, etc.
553 File heartbeatFile = null;
554 FileOutputStream heartbeatOutputStream = null;
555 if (filteredWaitForChild) {
556 File tmpDir = null;
557 String tmpDirName = (String)sysProps.get("java.io.tmpdir");
558 if (tmpDirName != null)
559 tmpDir = new File(tmpDirName);
560 heartbeatFile = File.createTempFile(ChildMain.HEARTBEAT_FILE_PROP_NAME + ".", "", tmpDir);
561 // Open the heartbeat file for writing so that it the child JVM
562 // will not be able to delete it while this process is running
563 heartbeatOutputStream = new FileOutputStream(heartbeatFile);
564 sysProps.put(ChildMain.HEARTBEAT_FILE_PROP_NAME, heartbeatFile.getCanonicalPath());
565 }
566
567 // Assemble child command
568 String[] cmd = new String[5 + jvmArgs.size() + sysProps.size() + appArgs.size()];
569 int nextCmdArg = 0;
570 if (filteredDebug)
571 cmd[nextCmdArg++] = Launcher.getJDBCommand();
572 else
573 cmd[nextCmdArg++] = Launcher.getJavaCommand();
574 // Add jvmArgs to command
575 for (int i = 0; i < jvmArgs.size(); i++)
576 cmd[nextCmdArg++] = (String)jvmArgs.get(i);
577 // Add properties to command
578 Iterator sysPropsKeys = sysProps.keySet().iterator();
579 while (sysPropsKeys.hasNext()) {
580 String key = (String)sysPropsKeys.next();
581 if (key == null)
582 continue;
583 String value = (String)sysProps.get(key);
584 if (value == null)
585 value = "";
586 cmd[nextCmdArg++] = "-D" + key + "=" + value;
587 }
588 // Add classpath to command. Note that it is after the jvmArgs
589 // and system properties to prevent the user from sneaking in an
590 // alterate classpath through the jvmArgs.
591 cmd[nextCmdArg++] = "-classpath";
592 cmd[nextCmdArg++] = fullClasspath.toString();
593 // Add main class to command
594 int mainClassArg = nextCmdArg;
595 cmd[nextCmdArg++] = ChildMain.class.getName();
596 cmd[nextCmdArg++] = filteredMainClassName;
597 // Add args to command
598 for (int i = 0; i < appArgs.size(); i++)
599 {
600 cmd[nextCmdArg++] = (String)appArgs.get(i);
601 }
602 // Print command
603 if (filteredPrint) {
604 // Quote the command arguments
605 String osname = System.getProperty("os.name").toLowerCase();
606 StringBuffer buf = new StringBuffer(cmd.length * 100);
607 String quote = null;
608 String replaceQuote = null;
609 if (osname.indexOf("windows") >= 0) {
610 // Use double-quotes to quote on Windows
611 quote = "\"";
612 replaceQuote = quote + quote + quote;
613 } else {
614 // Use single-quotes to quote on Unix
615 quote = "'";
616 replaceQuote = quote + "\\" + quote + quote;
617 }
618 for (int i = 0; i < cmd.length; i++) {
619 // Pull ChildMain out of command as we want to print the
620 // real JVM command that can be executed by the user
621 if (i == mainClassArg)
622 continue;
623 if (i > 0)
624 buf.append(" ");
625 buf.append(quote);
626 StringTokenizer tokenizer = new StringTokenizer(cmd[i], quote, true);
627 while (tokenizer.hasMoreTokens()) {
628 String token = tokenizer.nextToken();
629 if (quote.equals(token))
630 buf.append(replaceQuote);
631 else
632 buf.append(token);
633 }
634 buf.append(quote);
635 }
636 // Print the quoted command
637 System.err.println(Launcher.getLocalizedString("executing.child.command", this.getClass().getName()) + ":");
638 System.err.println(buf.toString());
639 }
640
641 // Create a child JVM
642 if (Launcher.isStopped())
643 throw new BuildException();
644 Process proc = null;
645 synchronized (LaunchTask.childProcesses) {
646 proc = Runtime.getRuntime().exec(cmd);
647 // Add the synchronous child process
648 if (filteredWaitForChild) {
649 childProc = proc;
650 LaunchTask.childProcesses.add(proc);
651 }
652 }
653 if (filteredWaitForChild) {
654 StreamConnector stdout =
655 new StreamConnector(proc.getInputStream(), System.out);
656 StreamConnector stderr =
657 new StreamConnector(proc.getErrorStream(), System.err);
658 stdout.start();
659 stderr.start();
660 if (filteredUseSystemIn) {
661 StreamConnector stdin =
662 new StreamConnector(System.in, proc.getOutputStream());
663 stdin.start();
664 }
665 proc.waitFor();
666 // Let threads flush any unflushed output
667 stdout.join();
668 stderr.join();
669 if (heartbeatOutputStream != null)
670 heartbeatOutputStream.close();
671 if (heartbeatFile != null)
672 heartbeatFile.delete();
673 int exitValue = proc.exitValue();
674 if (filteredFailOnError && exitValue != 0)
675 throw new BuildException(Launcher.getLocalizedString("child.failed", this.getClass().getName()) + " " + exitValue);
676 }
677 // Need to check if the launching process has stopped because
678 // processes don't throw exceptions when they are terminated
679 if (Launcher.isStopped())
680 throw new BuildException();
681
682 } catch (BuildException be) {
683 throw be;
684 } catch (Exception e) {
685 if (Launcher.isStopped())
686 throw new BuildException(Launcher.getLocalizedString("launch.task.stopped", this.getClass().getName()));
687 else
688 throw new BuildException(e);
689 }
690
691 }
692
693 /**
694 * Set the useArgs flag. Setting this flag to true will cause this
695 * task to append all of the command line arguments used to start the
696 * {@link Launcher#start(String[])} method to the arguments
697 * passed to the child JVM.
698 *
699 * @param useArgs the useArgs flag
700 */
701 public void setUseargs(boolean useArgs) {
702
703 this.useArgs = useArgs;
704
705 }
706
707 /**
708 * Set the useSystemIn flag. Setting this flag to false will cause this
709 * task to not read System.in. This will cause the child JVM to never
710 * receive any bytes when it reads System.in. Setting this flag to false
711 * is useful in some Unix environments where processes cannot be put in
712 * the background when they read System.in.
713 *
714 * @param useSystemIn the useSystemIn flag
715 */
716 public void setUsesystemin(boolean useSystemIn) {
717
718 this.useSystemIn = useSystemIn;
719
720 }
721
722 /**
723 * Set the waitForChild flag. Setting this flag to true will cause this
724 * task to wait for the child JVM to finish executing before the task
725 * completes. Setting this flag to false will cause this task to complete
726 * immediately after it starts the execution of the child JVM. Setting it
727 * false emulates the "&" background operator in most Unix shells and is
728 * most of set to false when launching server or GUI applications.
729 *
730 * @param waitForChild the waitForChild flag
731 */
732 public void setWaitforchild(boolean waitForChild) {
733
734 this.waitForChild = waitForChild;
735
736 }
737
738 /**
739 * Set the class name.
740 *
741 * @param mainClassName the class to execute <code>main(String[])</code>
742 */
743 public void setClassname(String mainClassName) {
744
745 this.mainClassName = mainClassName;
746
747 }
748
749 /**
750 * Set the classpath.
751 *
752 * @param classpath the classpath
753 */
754 public void setClasspath(Path classpath) {
755
756 createClasspath().append(classpath);
757
758 }
759
760 /**
761 * Adds a reference to a classpath defined elsewhere.
762 *
763 * @param ref reference to the classpath
764 */
765 public void setClasspathref(Reference ref) {
766
767 createClasspath().setRefid(ref);
768
769 }
770
771 /**
772 * Set the debug flag. Setting this flag to true will cause this
773 * task to run the child JVM using the JDB debugger.
774 *
775 * @param debug the debug flag
776 */
777 public void setDebug(boolean debug) {
778
779 this.debug = debug;
780
781 }
782
783 /**
784 * Set the displayMinimizedWindow flag. Note that this flag has no effect
785 * on non-Windows platforms. On Windows platform, setting this flag to true
786 * will cause a minimized window to be displayed in the Windows task bar
787 * while the child process is executing. This flag is usually set to true
788 * for server applications that also have their "waitForChild" attribute
789 * set to false via the {@link #setWaitforchild(boolean)} method.
790 *
791 * @param displayMinimizedWindow true if a minimized window should be
792 * displayed in the Windows task bar while the child process is executing
793 */
794 public void setDisplayminimizedwindow(boolean displayMinimizedWindow) {
795
796 this.displayMinimizedWindow = displayMinimizedWindow;
797
798 }
799
800 /**
801 * Set the disposeMinimizedWindow flag. Note that this flag has no effect
802 * on non-Windows platforms. On Windows platform, setting this flag to true
803 * will cause any minimized window that is display by setting the
804 * "displayMinimizedWindow" attribute to true via the
805 * {@link #setDisplayminimizedwindow(boolean)} to be automatically
806 * disposed of when the child JVM's <code>main(String[])</code> returns.
807 * This flag is normally used for applications that don't explicitly call
808 * {@link System#exit(int)}. If an application does not explicitly call
809 * {@link System#exit(int)}, an minimized windows need to be disposed of
810 * for the child JVM to exit.
811 *
812 * @param disposeMinimizedWindow true if a minimized window in the Windows
813 * taskbar should be automatically disposed of after the child JVM's
814 * <code>main(String[])</code> returns
815 */
816 public void setDisposeminimizedwindow(boolean disposeMinimizedWindow) {
817
818 this.disposeMinimizedWindow = disposeMinimizedWindow;
819
820 }
821
822 /**
823 * Set the failOnError flag.
824 *
825 * @param failOnError true if the launch process should stop if the child
826 * JVM returns an exit value other than 0
827 */
828 public void setFailonerror(boolean failOnError) {
829
830 this.failOnError = failOnError;
831
832 }
833 /**
834 * Set the filter class name.
835 *
836 * @param filterClassName the class that implements the
837 * {@link LaunchFilter} interface
838 */
839 public void setFilterclassname(String filterClassName) {
840
841 this.filterClassName = filterClassName;
842
843 }
844
845 /**
846 * Set the filter class' classpath.
847 *
848 * @param filterClasspath the classpath for the filter class
849 */
850 public void setFilterclasspath(Path filterClasspath) {
851
852 createFilterclasspath().append(filterClasspath);
853
854 }
855
856 /**
857 * Set the title for the minimized window that will be displayed in the
858 * Windows taskbar. Note that this property has no effect on non-Windows
859 * platforms.
860 *
861 * @param minimizedWindowTitle the title to set for any minimized window
862 * that is displayed in the Windows taskbar
863 */
864 public void setMinimizedwindowtitle(String minimizedWindowTitle) {
865
866 this.minimizedWindowTitle = minimizedWindowTitle;
867
868 }
869
870 /**
871 * Set the icon file for the minimized window that will be displayed in the
872 * Windows taskbar. Note that this property has no effect on non-Windows
873 * platforms.
874 *
875 * @param minimizedWindowIcon the icon file to use for any minimized window
876 * that is displayed in the Windows taskbar
877 */
878 public void setMinimizedwindowicon(File minimizedWindowIcon) {
879
880 this.minimizedWindowIcon = minimizedWindowIcon;
881
882 }
883
884 /**
885 * Set the file that the child JVM's System.out and System.err will be
886 * redirected to. Output will only be redirected if the redirect flag
887 * is set to true via the {@link #setRedirectoutput(boolean)} method.
888 *
889 * @param outputFile a File to redirect System.out and System.err to
890 */
891 public void setOutput(File outputFile) {
892
893 this.outputFile = outputFile;
894
895 }
896
897 /**
898 * Set the print flag. Setting this flag to true will cause the full child
899 * JVM command to be printed to {@link System#out}.
900 *
901 * @param print the print flag
902 */
903 public void setPrint(boolean print) {
904
905 this.print = print;
906
907 }
908
909 /**
910 * Set the appendOutput flag. Setting this flag to true will cause the child
911 * JVM to append System.out and System.err to the file specified by the
912 * {@link #setOutput(File)} method. Setting this flag to false will cause
913 * the child to overwrite the file.
914 *
915 * @param appendOutput true if output should be appended to the output file
916 */
917 public void setAppendoutput(boolean appendOutput) {
918
919 this.appendOutput = appendOutput;
920
921 }
922
923 /**
924 * Set the redirect flag. Setting this flag to true will cause the child
925 * JVM's System.out and System.err to be redirected to file set using the
926 * {@link #setOutput(File)} method. Setting this flag to false will
927 * cause no redirection.
928 *
929 * @param redirect true if System.out and System.err should be redirected
930 */
931 public void setRedirectoutput(boolean redirect) {
932
933 this.redirect = redirect;
934
935 }
936
937 /**
938 * Set the requireTools flag. Setting this flag to true will cause the
939 * JVM's tools.jar to be added to the child JVM's classpath. This
940 * sets an explicit requirement that the user use a JDK instead of a
941 * JRE. Setting this flag to false explicitly allows the user to use
942 * a JRE.
943 *
944 * @param requireTools true if a JDK is required and false if only a JRE
945 * is required
946 */
947 public void setRequiretools(boolean requireTools) {
948
949 this.requireTools = requireTools;
950
951 }
952
953 /**
954 * Determine if the "if" condition flag for a nested element meets all
955 * criteria for use.
956 *
957 * @param ifCondition the "if" condition flag for a nested element
958 * @return true if the nested element should be process and false if it
959 * should be ignored
960 */
961 private boolean testIfCondition(String ifCondition) {
962
963 if (ifCondition == null || "".equals(ifCondition))
964 return true;
965 return project.getProperty(ifCondition) != null;
966
967 }
968
969 /**
970 * Determine if the "unless" condition flag for a nested element meets all
971 * criteria for use.
972 *
973 * @param unlessCondition the "unless" condition flag for a nested element
974 * @return true if the nested element should be process and false if it
975 * should be ignored
976 */
977 private boolean testUnlessCondition(String unlessCondition) {
978
979 if (unlessCondition == null || "".equals(unlessCondition))
980 return true;
981 return project.getProperty(unlessCondition) == null;
982
983 }
984
985 }