Coverage Report - org.apache.commons.launcher.LaunchTask
 
Classes in this File Line Coverage Branch Coverage Complexity
LaunchTask
0%
0/344
0%
0/148
4.065
 
 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  0
 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  0
     private static ArrayList childProcesses = new ArrayList();
 81  
 
 82  
     //------------------------------------------------------------------ Fields
 83  
 
 84  
     /**
 85  
      * Cached appendOutput flag.
 86  
      */
 87  0
     private boolean appendOutput = false;
 88  
 
 89  
     /**
 90  
      * Cached synchronously executing child process.
 91  
      */
 92  0
     private Process childProc = null;
 93  
 
 94  
     /**
 95  
      * Cached classpath.
 96  
      */
 97  0
     private Path classpath = null;
 98  
 
 99  
     /**
 100  
      * Cached debug flag.
 101  
      */
 102  0
     private boolean debug = false;
 103  
 
 104  
     /**
 105  
      * Cached displayMinimizedWindow flag.
 106  
      */
 107  0
     private boolean displayMinimizedWindow = false;
 108  
 
 109  
     /**
 110  
      * Cached disposeMinimizedWindow flag.
 111  
      */
 112  0
     private boolean disposeMinimizedWindow = true;
 113  
 
 114  
     /**
 115  
      * Cached failOnError flag.
 116  
      */
 117  0
     private boolean failOnError = false;
 118  
 
 119  
     /**
 120  
      * Cached filter instance.
 121  
      */
 122  0
     private LaunchFilter filter = null;
 123  
 
 124  
     /**
 125  
      * Cached filterClassName.
 126  
      */
 127  0
     private String filterClassName = null;
 128  
 
 129  
     /**
 130  
      * Cached filterClasspath.
 131  
      */
 132  0
     private Path filterClasspath = null;
 133  
 
 134  
     /**
 135  
      * Cached main class name.
 136  
      */
 137  0
     private String mainClassName = null;
 138  
 
 139  
     /**
 140  
      * Cached minimizedWindowIcon.
 141  
      */
 142  0
     private File minimizedWindowIcon = null;
 143  
 
 144  
     /**
 145  
      * Cached minimizedWindowTitle.
 146  
      */
 147  0
     private String minimizedWindowTitle = null;
 148  
 
 149  
     /**
 150  
      * Cached output file.
 151  
      */
 152  0
     private File outputFile = null;
 153  
 
 154  
     /**
 155  
      * Cached print flag.
 156  
      */
 157  0
     private boolean print = false;
 158  
 
 159  
     /**
 160  
      * Cached redirect flag.
 161  
      */
 162  0
     private boolean redirect = false;
 163  
 
 164  
     /**
 165  
      * Cached requireTools flag.
 166  
      */
 167  0
     private boolean requireTools = false;
 168  
 
 169  
     /**
 170  
      * Cached arg elements
 171  
      */
 172  0
     private ArgumentSet taskArgumentSet = new ArgumentSet();
 173  
 
 174  
     /**
 175  
      * Cached jvmarg elements
 176  
      */
 177  0
     private JVMArgumentSet taskJVMArgumentSet = new JVMArgumentSet();
 178  
 
 179  
     /**
 180  
      * Cached sysproperty elements
 181  
      */
 182  0
     private SysPropertySet taskSysPropertySet = new SysPropertySet();
 183  
 
 184  
     /**
 185  
      * Cached useArgs flag.
 186  
      */
 187  0
     private boolean useArgs = true;
 188  
 
 189  
     /**
 190  
      * Cached useSystemIn flag.
 191  
      */
 192  0
     private boolean useSystemIn = true;
 193  
 
 194  
     /**
 195  
      * Cached waitForChild flag.
 196  
      */
 197  0
     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  0
         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  0
         taskArgumentSet.addArg(arg);
 225  
 
 226  0
     }
 227  
 
 228  
     /**
 229  
      * Add a nested argset element.
 230  
      *
 231  
      * @param set the argset element
 232  
      */
 233  
     public void addArgset(ArgumentSet set) {
 234  
 
 235  0
         taskArgumentSet.addArgset(set);
 236  
 
 237  0
     }
 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  0
         taskJVMArgumentSet.addJvmarg(jvmArg);
 250  
 
 251  0
     }
 252  
 
 253  
     /**
 254  
      * Add a nested jvmargset element.
 255  
      *
 256  
      * @param set the jvmargset element
 257  
      */
 258  
     public void addJvmargset(JVMArgumentSet set) {
 259  
 
 260  0
         taskJVMArgumentSet.addJvmargset(set);
 261  
 
 262  0
     }
 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  0
         taskSysPropertySet.addSysproperty(var);
 275  
 
 276  0
     }
 277  
 
 278  
     /**
 279  
      * Add a nested syspropertyset element.
 280  
      *
 281  
      * @param set the syspropertyset element
 282  
      */
 283  
     public void addSyspropertyset(SysPropertySet set) {
 284  
 
 285  0
         taskSysPropertySet.addSyspropertyset(set);
 286  
 
 287  0
     }
 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  0
         if (classpath == null)
 297  0
             classpath = new Path(project);
 298  0
         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  0
         if (filterClasspath == null)
 311  0
             filterClasspath = new Path(project);
 312  0
         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  0
             if (!Launcher.isStarted())
 330  0
                 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  0
             if (Launcher.isStopped())
 334  0
                 throw new BuildException();
 335  
 
 336  0
             if (mainClassName == null)
 337  0
                 throw new BuildException(Launcher.getLocalizedString("classname.null", this.getClass().getName()));
 338  
 
 339  
             // Copy all of the nested jvmarg elements into the jvmArgs object
 340  0
             ArrayList taskJVMArgs = taskJVMArgumentSet.getList();
 341  0
             ArrayList jvmArgs = new ArrayList(taskJVMArgs.size());
 342  0
             for (int i = 0; i < taskJVMArgs.size(); i++) {
 343  0
                 ConditionalArgument value = (ConditionalArgument)taskJVMArgs.get(i);
 344  
                 // Test "if" and "unless" conditions
 345  0
                 if (testIfCondition(value.getIf()) && testUnlessCondition(value.getUnless())) {
 346  0
                     String[] list = value.getParts();
 347  0
                     for (int j = 0; j < list.length; j++)
 348  0
                         jvmArgs.add(list[j]);
 349  
                 }
 350  
             }
 351  
 
 352  
             // Copy all of the nested sysproperty elements into the sysProps
 353  
             // object
 354  0
             ArrayList taskSysProps = taskSysPropertySet.getList();
 355  0
             HashMap sysProps = new HashMap(taskSysProps.size());
 356  0
             for (int i = 0; i < taskSysProps.size(); i++) {
 357  0
                 ConditionalVariable variable = (ConditionalVariable)taskSysProps.get(i);
 358  
                 // Test "if" and "unless" conditions
 359  0
                 if (testIfCondition(variable.getIf()) && testUnlessCondition(variable.getUnless()))
 360  0
                     sysProps.put(variable.getKey(), variable.getValue());
 361  
             }
 362  
 
 363  
             // Copy all of the nested arg elements into the appArgs object
 364  0
             ArrayList taskArgs = taskArgumentSet.getList();
 365  0
             ArrayList appArgs = new ArrayList(taskArgs.size());
 366  0
             for (int i = 0; i < taskArgs.size(); i++) {
 367  0
                 ConditionalArgument value = (ConditionalArgument)taskArgs.get(i);
 368  
                 // Test "if" and "unless" conditions
 369  0
                 if (testIfCondition(value.getIf()) && testUnlessCondition(value.getUnless())) {
 370  0
                     String[] list = value.getParts();
 371  0
                     for (int j = 0; j < list.length; j++)
 372  0
                         appArgs.add(list[j]);
 373  
                 }
 374  
             }
 375  
 
 376  
             // Add the Launcher's command line arguments to the appArgs object
 377  0
             if (useArgs) {
 378  0
                 int currentArg = 0;
 379  0
                 String arg = null;
 380  0
                 while ((arg = project.getUserProperty(LaunchTask.ARG_PROP_NAME + Integer.toString(currentArg++))) != null)
 381  0
                     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  0
             String filteredClasspath = null;
 387  0
             if (classpath != null)
 388  0
                 filteredClasspath = classpath.toString();
 389  0
             String filteredMainClassName = mainClassName;
 390  0
             boolean filteredRedirect = redirect;
 391  0
             File filteredOutputFile = outputFile;
 392  0
             boolean filteredAppendOutput = appendOutput;
 393  0
             boolean filteredDebug = debug;
 394  0
             boolean filteredDisplayMinimizedWindow = displayMinimizedWindow;
 395  0
             boolean filteredDisposeMinimizedWindow = disposeMinimizedWindow;
 396  0
             boolean filteredFailOnError = failOnError;
 397  0
             String filteredMinimizedWindowTitle = minimizedWindowTitle;
 398  0
             File filteredMinimizedWindowIcon = minimizedWindowIcon;
 399  0
             boolean filteredPrint = print;
 400  0
             boolean filteredRequireTools = requireTools;
 401  0
             boolean filteredUseSystemIn = useSystemIn;
 402  0
             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  0
             if (filterClassName != null) {
 408  0
                  if (filter == null) {
 409  
                      try {
 410  0
                          ClassLoader loader = this.getClass().getClassLoader();
 411  0
                          if (filterClasspath != null) {
 412  
                              // Construct a class loader to load the class
 413  0
                              String[] fileList = filterClasspath.list();
 414  0
                              URL[] urls = new URL[fileList.length];
 415  0
                              for (int i = 0; i < fileList.length; i++)
 416  0
                                  urls[i] = new File(fileList[i]).toURL();
 417  0
                              loader = new URLClassLoader(urls, loader);
 418  
                          }
 419  0
                          Class filterClass = loader.loadClass(filterClassName);
 420  0
                          filter = (LaunchFilter)filterClass.newInstance();
 421  
                          // Execute filter and save any changes
 422  0
                          LaunchCommand command = new LaunchCommand();
 423  0
                          command.setJvmargs(jvmArgs);
 424  0
                          command.setSysproperties(sysProps);
 425  0
                          command.setArgs(appArgs);
 426  0
                          command.setClasspath(filteredClasspath);
 427  0
                          command.setClassname(filteredMainClassName);
 428  0
                          command.setRedirectoutput(filteredRedirect);
 429  0
                          command.setOutput(filteredOutputFile);
 430  0
                          command.setAppendoutput(filteredAppendOutput);
 431  0
                          command.setDebug(filteredDebug);
 432  0
                          command.setDisplayminimizedwindow(filteredDisplayMinimizedWindow);
 433  0
                          command.setDisposeminimizedwindow(filteredDisposeMinimizedWindow);
 434  0
                          command.setFailonerror(filteredFailOnError);
 435  0
                          command.setMinimizedwindowtitle(filteredMinimizedWindowTitle);
 436  0
                          command.setMinimizedwindowicon(filteredMinimizedWindowIcon);
 437  0
                          command.setPrint(filteredPrint);
 438  0
                          command.setRequiretools(filteredRequireTools);
 439  0
                          command.setUsesystemin(filteredUseSystemIn);
 440  0
                          command.setWaitforchild(filteredWaitForChild);
 441  0
                          filter.filter(command);
 442  0
                          jvmArgs = command.getJvmargs();
 443  0
                          sysProps = command.getSysproperties();
 444  0
                          appArgs = command.getArgs();
 445  0
                          filteredClasspath = command.getClasspath();
 446  0
                          filteredMainClassName = command.getClassname();
 447  0
                          filteredRedirect = command.getRedirectoutput();
 448  0
                          filteredOutputFile = command.getOutput();
 449  0
                          filteredAppendOutput = command.getAppendoutput();
 450  0
                          filteredDebug = command.getDebug();
 451  0
                          filteredDisplayMinimizedWindow = command.getDisplayminimizedwindow();
 452  0
                          filteredDisposeMinimizedWindow = command.getDisposeminimizedwindow();
 453  0
                          filteredFailOnError = command.getFailonerror();
 454  0
                          filteredMinimizedWindowTitle = command.getMinimizedwindowtitle();
 455  0
                          filteredMinimizedWindowIcon = command.getMinimizedwindowicon();
 456  0
                          filteredPrint = command.getPrint();
 457  0
                          filteredRequireTools = command.getRequiretools();
 458  0
                          filteredUseSystemIn = command.getUsesystemin();
 459  0
                          filteredWaitForChild = command.getWaitforchild();
 460  
                          // Check changes
 461  0
                          if (filteredMainClassName == null)
 462  0
                              throw new BuildException(Launcher.getLocalizedString("classname.null", this.getClass().getName()));
 463  0
                          if (jvmArgs == null)
 464  0
                              jvmArgs = new ArrayList();
 465  0
                          if (sysProps == null)
 466  0
                              sysProps = new HashMap();
 467  0
                          if (appArgs == null)
 468  0
                              appArgs = new ArrayList();
 469  0
                      } catch (BuildException be) {
 470  0
                          throw new BuildException(filterClassName + " " + Launcher.getLocalizedString("filter.exception", this.getClass().getName()), be);
 471  0
                      } catch (ClassCastException cce) {
 472  0
                          throw new BuildException(filterClassName + " " + Launcher.getLocalizedString("filter.not.filter", this.getClass().getName()));
 473  0
                      } catch (Exception e) {
 474  0
                          throw new BuildException(e);
 475  0
                      }
 476  
                  }
 477  
             }
 478  
 
 479  
             // Force child JVM into foreground if running using JDB
 480  0
             if (filteredDebug) {
 481  0
                 filteredWaitForChild = true;
 482  0
                 filteredUseSystemIn = true;
 483  
             }
 484  
 
 485  
             // Prepend standard paths to classpath
 486  0
             StringBuffer fullClasspath = new StringBuffer(Launcher.getBootstrapFile().getPath());
 487  0
             if (filteredRequireTools) {
 488  0
                 fullClasspath.append(File.pathSeparator);
 489  0
                 fullClasspath.append(Launcher.getToolsClasspath());
 490  
             }
 491  0
             if (filteredClasspath != null) {
 492  0
                 fullClasspath.append(File.pathSeparator);
 493  0
                 fullClasspath.append(filteredClasspath);
 494  
             }
 495  
 
 496  
             // Set ChildMain.WAIT_FOR_CHILD_PROP_NAME property for child JVM
 497  0
             sysProps.remove(ChildMain.WAIT_FOR_CHILD_PROP_NAME);
 498  0
             if (filteredWaitForChild)
 499  0
                 sysProps.put(ChildMain.WAIT_FOR_CHILD_PROP_NAME, "");
 500  
 
 501  
             // Set minimized window properties for child JVM
 502  0
             sysProps.remove(ChildMain.DISPLAY_MINIMIZED_WINDOW_PROP_NAME);
 503  0
             sysProps.remove(ChildMain.MINIMIZED_WINDOW_TITLE_PROP_NAME);
 504  0
             sysProps.remove(ChildMain.MINIMIZED_WINDOW_ICON_PROP_NAME);
 505  0
             sysProps.remove(ChildMain.DISPOSE_MINIMIZED_WINDOW_PROP_NAME);
 506  0
             if (!filteredWaitForChild && filteredDisplayMinimizedWindow) {
 507  0
                 sysProps.put(ChildMain.DISPLAY_MINIMIZED_WINDOW_PROP_NAME, "");
 508  0
                 if (filteredMinimizedWindowTitle != null)
 509  0
                     sysProps.put(ChildMain.MINIMIZED_WINDOW_TITLE_PROP_NAME, filteredMinimizedWindowTitle);
 510  
                 else
 511  0
                     sysProps.put(ChildMain.MINIMIZED_WINDOW_TITLE_PROP_NAME, getOwningTarget().getName());
 512  0
                 if (filteredMinimizedWindowIcon != null)
 513  0
                     sysProps.put(ChildMain.MINIMIZED_WINDOW_ICON_PROP_NAME, filteredMinimizedWindowIcon.getCanonicalPath());
 514  
                 // Set ChildMain.DISPOSE_MINIMIZED_WINDOW_PROP_NAME property
 515  0
                 if (filteredDisposeMinimizedWindow)
 516  0
                     sysProps.put(ChildMain.DISPOSE_MINIMIZED_WINDOW_PROP_NAME, "");
 517  
             }
 518  
 
 519  
             // Set ChildMain.OUTPUT_FILE_PROP_NAME property for child JVM
 520  0
             sysProps.remove(ChildMain.OUTPUT_FILE_PROP_NAME);
 521  0
             if (!filteredWaitForChild && filteredRedirect) {
 522  0
                 if (filteredOutputFile != null) {
 523  0
                     String outputFilePath = filteredOutputFile.getCanonicalPath();
 524  
                     // Verify that we can write to the output file
 525  
                     try {
 526  0
                         File parentFile = new File(filteredOutputFile.getParent());
 527  
                         // To take care of non-existent log directories
 528  0
                         if ( !parentFile.exists() ) {
 529  
                             //Trying to create non-existent parent directories
 530  0
                             parentFile.mkdirs();
 531  
                             //If this fails createNewFile also fails
 532  
                             //We can give more exact error message, if we choose
 533  
                         }
 534  0
                         filteredOutputFile.createNewFile();
 535  0
                     } catch (IOException ioe) {
 536  0
                         throw new BuildException(outputFilePath + " " + Launcher.getLocalizedString("output.file.not.creatable", this.getClass().getName()));
 537  0
                     }
 538  0
                     if (!filteredOutputFile.canWrite())
 539  0
                         throw new BuildException(outputFilePath + " " + Launcher.getLocalizedString("output.file.not.writable", this.getClass().getName()));
 540  0
                     sysProps.put(ChildMain.OUTPUT_FILE_PROP_NAME, outputFilePath);
 541  0
                     if (filteredAppendOutput)
 542  0
                         sysProps.put(ChildMain.APPEND_OUTPUT_PROP_NAME, "");
 543  0
                     Launcher.getLog().println(Launcher.getLocalizedString("redirect.notice", this.getClass().getName()) + " " + outputFilePath);
 544  0
                 } else {
 545  0
                     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  0
             File heartbeatFile = null;
 554  0
             FileOutputStream heartbeatOutputStream = null;
 555  0
             if (filteredWaitForChild) {
 556  0
                 File tmpDir = null;
 557  0
                 String tmpDirName = (String)sysProps.get("java.io.tmpdir");
 558  0
                 if (tmpDirName != null)
 559  0
                     tmpDir = new File(tmpDirName);
 560  0
                 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  0
                 heartbeatOutputStream = new FileOutputStream(heartbeatFile);
 564  0
                 sysProps.put(ChildMain.HEARTBEAT_FILE_PROP_NAME, heartbeatFile.getCanonicalPath());
 565  
             }
 566  
 
 567  
             // Assemble child command
 568  0
             String[] cmd = new String[5 + jvmArgs.size() + sysProps.size() + appArgs.size()];
 569  0
             int nextCmdArg = 0;
 570  0
             if (filteredDebug)
 571  0
                 cmd[nextCmdArg++] = Launcher.getJDBCommand();
 572  
             else
 573  0
                 cmd[nextCmdArg++] = Launcher.getJavaCommand();
 574  
             // Add jvmArgs to command
 575  0
             for (int i = 0; i < jvmArgs.size(); i++)
 576  0
                 cmd[nextCmdArg++] = (String)jvmArgs.get(i);
 577  
             // Add properties to command
 578  0
             Iterator sysPropsKeys = sysProps.keySet().iterator();
 579  0
             while (sysPropsKeys.hasNext()) {
 580  0
                 String key = (String)sysPropsKeys.next();
 581  0
                 if (key == null)
 582  0
                     continue;
 583  0
                 String value = (String)sysProps.get(key);
 584  0
                 if (value == null)
 585  0
                     value = "";
 586  0
                 cmd[nextCmdArg++] = "-D" + key + "=" + value;
 587  0
             }
 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  0
             cmd[nextCmdArg++] = "-classpath";
 592  0
             cmd[nextCmdArg++] = fullClasspath.toString();
 593  
             // Add main class to command
 594  0
             int mainClassArg = nextCmdArg;
 595  0
             cmd[nextCmdArg++] = ChildMain.class.getName();
 596  0
             cmd[nextCmdArg++] = filteredMainClassName;
 597  
             // Add args to command
 598  0
             for (int i = 0; i < appArgs.size(); i++)
 599  
             {
 600  0
                 cmd[nextCmdArg++] = (String)appArgs.get(i);
 601  
             }
 602  
             // Print command
 603  0
             if (filteredPrint) {
 604  
                 // Quote the command arguments
 605  0
                 String osname = System.getProperty("os.name").toLowerCase();
 606  0
                 StringBuffer buf = new StringBuffer(cmd.length * 100);
 607  0
                 String quote = null;
 608  0
                 String replaceQuote = null;
 609  0
                 if (osname.indexOf("windows") >= 0) {
 610  
                     // Use double-quotes to quote on Windows
 611  0
                     quote = "\"";
 612  0
                     replaceQuote = quote + quote + quote;
 613  
                 } else {
 614  
                     // Use single-quotes to quote on Unix
 615  0
                     quote = "'";
 616  0
                     replaceQuote = quote + "\\" + quote + quote;
 617  
                 }
 618  0
                 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  0
                     if (i == mainClassArg)
 622  0
                         continue;
 623  0
                     if (i > 0)
 624  0
                         buf.append(" ");
 625  0
                     buf.append(quote);
 626  0
                     StringTokenizer tokenizer = new StringTokenizer(cmd[i], quote, true);
 627  0
                     while (tokenizer.hasMoreTokens()) {
 628  0
                         String token = tokenizer.nextToken();
 629  0
                         if (quote.equals(token))
 630  0
                             buf.append(replaceQuote);
 631  
                         else
 632  0
                             buf.append(token);
 633  0
                     }
 634  0
                     buf.append(quote);
 635  
                 }
 636  
                 // Print the quoted command
 637  0
                 System.err.println(Launcher.getLocalizedString("executing.child.command", this.getClass().getName()) + ":");
 638  0
                 System.err.println(buf.toString());
 639  
             }
 640  
 
 641  
             // Create a child JVM
 642  0
             if (Launcher.isStopped())
 643  0
                 throw new BuildException();
 644  0
             Process proc = null;
 645  0
             synchronized (LaunchTask.childProcesses) {
 646  0
                 proc = Runtime.getRuntime().exec(cmd);
 647  
                 // Add the synchronous child process
 648  0
                 if (filteredWaitForChild) {
 649  0
                     childProc = proc;
 650  0
                     LaunchTask.childProcesses.add(proc);
 651  
                 }
 652  0
             }
 653  0
             if (filteredWaitForChild) {
 654  0
                 StreamConnector stdout =
 655  
                     new StreamConnector(proc.getInputStream(), System.out);
 656  0
                 StreamConnector stderr =
 657  
                     new StreamConnector(proc.getErrorStream(), System.err);
 658  0
                 stdout.start();
 659  0
                 stderr.start();
 660  0
                 if (filteredUseSystemIn) {
 661  0
                     StreamConnector stdin =
 662  
                         new StreamConnector(System.in, proc.getOutputStream());
 663  0
                     stdin.start();
 664  
                 }
 665  0
                 proc.waitFor();
 666  
                 // Let threads flush any unflushed output
 667  0
                 stdout.join();
 668  0
                 stderr.join();
 669  0
                 if (heartbeatOutputStream != null)
 670  0
                     heartbeatOutputStream.close();
 671  0
                 if (heartbeatFile != null)
 672  0
                     heartbeatFile.delete();
 673  0
                 int exitValue = proc.exitValue();
 674  0
                 if (filteredFailOnError && exitValue != 0)
 675  0
                     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  0
             if (Launcher.isStopped())
 680  0
                 throw new BuildException();
 681  
 
 682  0
         } catch (BuildException be) {
 683  0
             throw be;
 684  0
         } catch (Exception e) {
 685  0
             if (Launcher.isStopped())
 686  0
                 throw new BuildException(Launcher.getLocalizedString("launch.task.stopped", this.getClass().getName()));
 687  
             else 
 688  0
                 throw new BuildException(e);
 689  0
         }
 690  
 
 691  0
     }
 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  0
         this.useArgs = useArgs;
 704  
 
 705  0
     }
 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  0
         this.useSystemIn = useSystemIn;
 719  
 
 720  0
     }
 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  0
         this.waitForChild = waitForChild;
 735  
 
 736  0
     }
 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  0
         this.mainClassName = mainClassName;
 746  
 
 747  0
     }
 748  
 
 749  
     /**
 750  
      * Set the classpath.
 751  
      *
 752  
      * @param classpath the classpath
 753  
      */
 754  
     public void setClasspath(Path classpath) {
 755  
 
 756  0
         createClasspath().append(classpath);
 757  
 
 758  0
     }
 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  0
         createClasspath().setRefid(ref);
 768  
 
 769  0
     }
 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  0
         this.debug = debug;
 780  
 
 781  0
     }
 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  0
         this.displayMinimizedWindow = displayMinimizedWindow;
 797  
 
 798  0
     }
 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  0
         this.disposeMinimizedWindow = disposeMinimizedWindow;
 819  
 
 820  0
     }
 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  0
         this.failOnError = failOnError;
 831  
 
 832  0
     }
 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  0
         this.filterClassName = filterClassName;
 842  
 
 843  0
     }
 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  0
         createFilterclasspath().append(filterClasspath);
 853  
 
 854  0
     }
 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  0
         this.minimizedWindowTitle = minimizedWindowTitle;
 867  
 
 868  0
     }
 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  0
         this.minimizedWindowIcon = minimizedWindowIcon;
 881  
 
 882  0
     }
 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  0
         this.outputFile = outputFile;
 894  
 
 895  0
     }
 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  0
         this.print = print;
 906  
 
 907  0
     }
 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  0
         this.appendOutput = appendOutput;
 920  
 
 921  0
     }
 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  0
         this.redirect = redirect;
 934  
 
 935  0
     }
 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  0
         this.requireTools = requireTools;
 950  
 
 951  0
     }
 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  0
         if (ifCondition == null || "".equals(ifCondition))
 964  0
             return true;
 965  0
         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  0
         if (unlessCondition == null || "".equals(unlessCondition))
 980  0
             return true;
 981  0
         return project.getProperty(unlessCondition) == null;
 982  
 
 983  
     }
 984  
 
 985  
 }