KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > commons > launcher > Launcher


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

16
17 package org.apache.commons.launcher;
18
19 import java.io.File JavaDoc;
20 import java.io.IOException JavaDoc;
21 import java.io.PrintStream JavaDoc;
22 import java.net.URL JavaDoc;
23 import java.net.URLClassLoader JavaDoc;
24 import java.net.URLDecoder JavaDoc;
25 import java.util.ResourceBundle JavaDoc;
26
27 import org.apache.commons.launcher.types.ArgumentSet;
28 import org.apache.commons.launcher.types.JVMArgumentSet;
29 import org.apache.commons.launcher.types.SysPropertySet;
30 import org.apache.tools.ant.Main;
31 import org.apache.tools.ant.Project;
32 import org.apache.tools.ant.ProjectHelper;
33 import org.apache.tools.ant.taskdefs.Ant;
34 import org.apache.tools.ant.taskdefs.Available;
35 import org.apache.tools.ant.taskdefs.CallTarget;
36 import org.apache.tools.ant.taskdefs.ConditionTask;
37 import org.apache.tools.ant.taskdefs.Exit;
38 import org.apache.tools.ant.taskdefs.Property;
39 import org.apache.tools.ant.taskdefs.Mkdir;
40 import org.apache.tools.ant.taskdefs.Copy;
41 import org.apache.tools.ant.taskdefs.Delete;
42 import org.apache.tools.ant.types.Description;
43 import org.apache.tools.ant.types.FileList;
44 import org.apache.tools.ant.types.FileSet;
45 import org.apache.tools.ant.types.Path;
46 import org.apache.tools.ant.types.PatternSet;
47
48 /**
49  * A class that is used to launch a Java process. The primary purpose of this
50  * class is to eliminate the need for a batch or shell script to launch a Java
51  * process. Some situations where elimination of a batch or shell script may be
52  * desirable are:
53  * <ul>
54  * <li>You want to avoid having to determining where certain application paths
55  * are e.g. your application's home directory, etc. Determining this
56  * dynamically in a Windows batch scripts is very tricky on some versions of
57  * Windows or when softlinks are used on Unix platforms.
58  * <li>You need to enforce certain properties e.g. java.endorsed.dirs when
59  * running with JDK 1.4.
60  * <li>You want to allow users to pass in custom JVM arguments or system
61  * properties without having to parse and reorder arguments in your script.
62  * This can be tricky and/or messy in batch and shell scripts.
63  * <li>You want to bootstrap Java properties from a configuration file instead
64  * hard-coding them in your batch and shell scripts.
65  * <li>You want to provide localized error messages which is very tricky to do
66  * in batch and shell scripts.
67  * </ul>
68  *
69  * @author Patrick Luby
70  */

71 public class Launcher implements Runnable JavaDoc {
72
73     //----------------------------------------------------------- Static Fields
74

75
76     /**
77      * Cached bootstrap file.
78      */

79     private static File JavaDoc bootstrapFile = null;
80
81     /**
82      * Cached java command
83      */

84     private static String JavaDoc javaCmd = null;
85
86     /**
87      * Cached JDB command
88      */

89     private static String JavaDoc jdbCmd = null;
90
91     /**
92      * Default XML file name
93      */

94     private final static String JavaDoc DEFAULT_XML_FILE_NAME = "launcher.xml";
95
96     /**
97      * Shared lock.
98      */

99     private static Object JavaDoc lock = new Object JavaDoc();
100
101     /**
102      * Cached log
103      */

104     private static PrintStream JavaDoc log = System.err;
105
106     /**
107      * Cached resourceBundle
108      */

109     private static ResourceBundle JavaDoc resourceBundle = null;
110
111     /**
112      * The started status flag.
113      */

114     private static boolean started = false;
115
116     /**
117      * The stopped status flag.
118      */

119     private static boolean stopped = false;
120
121     /**
122      * List of supported Ant tasks.
123      */

124     public final static Object JavaDoc[] SUPPORTED_ANT_TASKS = new Object JavaDoc[] {
125             LaunchTask.TASK_NAME, LaunchTask.class,
126             "ant", Ant.class,
127             "antcall", CallTarget.class,
128             "available", Available.class,
129             "condition", ConditionTask.class,
130             "fail", Exit.class,
131             "property", Property.class,
132             "mkdir", Mkdir.class,
133             "delete", Delete.class,
134             "copy", Copy.class
135         };
136
137     /**
138      * List of supported Ant types.
139      */

140     public final static Object JavaDoc[] SUPPORTED_ANT_TYPES = new Object JavaDoc[] {
141             ArgumentSet.TYPE_NAME, ArgumentSet.class,
142             JVMArgumentSet.TYPE_NAME, JVMArgumentSet.class,
143             SysPropertySet.TYPE_NAME, SysPropertySet.class,
144             "description", Description.class,
145             "fileset", FileSet.class,
146             "filelist", FileList.class,
147             "path", Path.class,
148             "patternset", PatternSet.class
149         };
150
151     /**
152      * Cached tools classpath.
153      */

154     private static String JavaDoc toolsClasspath = null;
155
156     /**
157      * The verbose flag
158      */

159     private static boolean verbose = false;
160
161     //---------------------------------------------------------- Static Methods
162

163
164     /**
165      * Get the started flag.
166      *
167      * @return the value of the started flag
168      */

169     public static synchronized boolean isStarted() {
170
171         return Launcher.started;
172
173     }
174
175     /**
176      * Get the stopped flag.
177      *
178      * @return the value of the stopped flag
179      */

180     public static synchronized boolean isStopped() {
181
182         return Launcher.stopped;
183
184     }
185
186     /**
187      * Start the launching process. This method is essential the
188      * <code>main(String[])<code> method for this class except that this method
189      * never invokes {@link System#exit(int)}. This method is designed for
190      * applications that wish to invoke this class directly from within their
191      * application's code.
192      *
193      * @param args command line arguments
194      * @return the exit value of the last synchronous child JVM that was
195      * launched or 1 if any other error occurs
196      * @throws IllegalArgumentException if any error parsing the args parameter
197      * occurs
198      */

199     public static int start(String JavaDoc[] args) throws IllegalArgumentException JavaDoc {
200
201         // Check make sure that neither this method or the stop() method is
202
// already running since we do not support concurrency
203
synchronized (Launcher.lock) {
204             if (Launcher.isStarted() || Launcher.isStopped())
205                 return 1;
206             Launcher.setStarted(true);
207         }
208
209         int returnValue = 0;
210         ClassLoader JavaDoc parentLoader = null;
211         Thread JavaDoc shutdownHook = new Thread JavaDoc(new Launcher());
212         Runtime JavaDoc runtime = Runtime.getRuntime();
213
214         try {
215
216             // Cache the current class loader for this thread and set the class
217
// loader before running Ant. Note that we only set the class loader
218
// if we are running a Java version earlier than 1.4 as on 1.4 this
219
// causes unnecessary loading of the XML parser classes.
220
parentLoader = Thread.currentThread().getContextClassLoader();
221             boolean lessThan14 = true;
222             try {
223                 Class.forName("java.lang.CharSequence");
224                 lessThan14 = false;
225             } catch (ClassNotFoundException JavaDoc cnfe) {
226                 // If this class does not exist, then we are not running Java 1.4
227
}
228             if (lessThan14)
229                 Thread.currentThread().setContextClassLoader(Launcher.class.getClassLoader());
230
231             Project project = new Project();
232
233             // Set the project's class loader
234
project.setCoreLoader(Launcher.class.getClassLoader());
235
236             // Initialize the project. Note that we don't invoke the
237
// Project.init() method directly as this will cause all of
238
// the myriad of Task subclasses to load which is a big
239
// performance hit. Instead, we load only the
240
// Launcher.SUPPORTED_ANT_TASKS and Launcher.SUPPORTED_ANT_TYPES
241
// into the project that the Launcher supports.
242
for (int i = 0; i < Launcher.SUPPORTED_ANT_TASKS.length; i++) {
243                 // The even numbered elements should be the task name
244
String JavaDoc taskName = (String JavaDoc)Launcher.SUPPORTED_ANT_TASKS[i];
245                 // The odd numbered elements should be the task class
246
Class JavaDoc taskClass = (Class JavaDoc)Launcher.SUPPORTED_ANT_TASKS[++i];
247                 project.addTaskDefinition(taskName, taskClass);
248             }
249             for (int i = 0; i < Launcher.SUPPORTED_ANT_TYPES.length; i++) {
250                 // The even numbered elements should be the type name
251
String JavaDoc typeName = (String JavaDoc)Launcher.SUPPORTED_ANT_TYPES[i];
252                 // The odd numbered elements should be the type class
253
Class JavaDoc typeClass = (Class JavaDoc)Launcher.SUPPORTED_ANT_TYPES[++i];
254                 project.addDataTypeDefinition(typeName, typeClass);
255             }
256
257             // Add all system properties as project properties
258
project.setSystemProperties();
259
260             // Parse the arguments
261
int currentArg = 0;
262
263             // Set default XML file
264
File JavaDoc launchFile = new File JavaDoc(Launcher.getBootstrapDir(), Launcher.DEFAULT_XML_FILE_NAME);
265
266             // Get standard launcher arguments
267
for ( ; currentArg < args.length; currentArg++) {
268                 // If we find a "-" argument or an argument without a
269
// leading "-", there are no more standard launcher arguments
270
if ("-".equals(args[currentArg])) {
271                     currentArg++;
272                     break;
273                 } else if (args[currentArg].length() > 0 && !"-".equals(args[currentArg].substring(0, 1))) {
274                     break;
275                 } else if ("-help".equals(args[currentArg])) {
276                     throw new IllegalArgumentException JavaDoc();
277                 } else if ("-launchfile".equals(args[currentArg])) {
278                     if (currentArg + 1 < args.length){
279                         String JavaDoc fileArg = args[++currentArg];
280                         launchFile = new File JavaDoc(fileArg);
281                         if (!launchFile.isAbsolute())
282                             launchFile = new File JavaDoc(Launcher.getBootstrapDir(), fileArg);
283                     } else {
284                         throw new IllegalArgumentException JavaDoc(args[currentArg] + " " + Launcher.getLocalizedString("missing.arg"));
285                     }
286                 } else if ("-executablename".equals(args[currentArg])) {
287                     if (currentArg + 1 < args.length)
288                         System.setProperty(ChildMain.EXECUTABLE_PROP_NAME, args[++currentArg]);
289                     else
290                         throw new IllegalArgumentException JavaDoc(args[currentArg] + " " + Launcher.getLocalizedString("missing.arg"));
291                 } else if ("-verbose".equals(args[currentArg])) {
292                     Launcher.setVerbose(true);
293                 } else {
294                     throw new IllegalArgumentException JavaDoc(args[currentArg] + " " + Launcher.getLocalizedString("invalid.arg"));
295                 }
296             }
297
298             // Get target
299
String JavaDoc target = null;
300             if (currentArg < args.length)
301                 target = args[currentArg++];
302             else
303                 throw new IllegalArgumentException JavaDoc(Launcher.getLocalizedString("missing.target"));
304
305             // Get user properties
306
for ( ; currentArg < args.length; currentArg++) {
307                 // If we don't find any more "-" or "-D" arguments, there are no
308
// more user properties
309
if ("-".equals(args[currentArg])) {
310                     currentArg++;
311                     break;
312                 } else if (args[currentArg].length() <= 2 || !"-D".equals(args[currentArg].substring(0, 2))) {
313                     break;
314                 }
315                 int delimiter = args[currentArg].indexOf('=', 2);
316                 String JavaDoc key = null;
317                 String JavaDoc value = null;
318                 if (delimiter >= 2) {
319                     key = args[currentArg].substring(2, delimiter);
320                     value = args[currentArg].substring(delimiter + 1);
321                 } else {
322                     // Unfortunately, MS-DOS batch scripts will split an
323
// "-Dname=value" argument into "-Dname" and "value"
324
// arguments. So, we need to assume that the next
325
// argument is the property value unless it appears
326
// to be a different type of argument.
327
key = args[currentArg].substring(2);
328                     if (currentArg + 1 < args.length &&
329                         !"-D".equals(args[currentArg + 1].substring(0, 2)))
330                     {
331                         value = args[++currentArg];
332                     } else {
333                         value = "";
334                     }
335                 }
336                 project.setUserProperty(key, value);
337             }
338
339             // Treat all remaining arguments as application arguments
340
String JavaDoc[] appArgs = new String JavaDoc[args.length - currentArg];
341             for (int i = 0; i < appArgs.length; i++) {
342                 appArgs[i] = args[i + currentArg];
343                 project.setUserProperty(LaunchTask.ARG_PROP_NAME + Integer.toString(i), appArgs[i]);
344             }
345
346             // Set standard Ant user properties
347
project.setUserProperty("ant.version", Main.getAntVersion());
348             project.setUserProperty("ant.file", launchFile.getCanonicalPath());
349             project.setUserProperty("ant.java.version", System.getProperty("java.specification.version"));
350
351             // Set the buildfile
352
ProjectHelper.configureProject(project, launchFile);
353
354             // Check that the target exists
355
if (!project.getTargets().containsKey(target))
356                 throw new IllegalArgumentException JavaDoc(target + " " + Launcher.getLocalizedString("invalid.target"));
357
358             // Execute the target
359
try {
360                 runtime.addShutdownHook(shutdownHook);
361             } catch (NoSuchMethodError JavaDoc nsme) {
362                 // Early JVMs do not support this method
363
}
364             project.executeTarget(target);
365
366         } catch (Throwable JavaDoc t) {
367             // Log any errors
368
returnValue = 1;
369             String JavaDoc message = t.getMessage();
370             if (t instanceof IllegalArgumentException JavaDoc) {
371                 Launcher.error(message, true);
372             } else {
373                 if (Launcher.verbose)
374                     Launcher.error(t);
375                 else
376                     Launcher.error(message, false);
377             }
378         } finally {
379             synchronized (Launcher.lock) {
380                 // Remove the shutdown hook
381
try {
382                     runtime.removeShutdownHook(shutdownHook);
383                 } catch (NoSuchMethodError JavaDoc nsme) {
384                     // Early JVMs do not support this method
385
}
386                 // Reset the class loader after running Ant
387
Thread.currentThread().setContextClassLoader(parentLoader);
388                 // Reset stopped flag
389
Launcher.setStarted(false);
390                 // Notify the stop() method that we have set the class loader
391
Launcher.lock.notifyAll();
392             }
393         }
394
395         // Override return value with exit value of last synchronous child JVM
396
Process JavaDoc[] childProcesses = LaunchTask.getChildProcesses();
397         if (childProcesses.length > 0)
398             returnValue = childProcesses[childProcesses.length - 1].exitValue();
399
400         return returnValue;
401
402     }
403
404     /**
405      * Interrupt the {@link #start(String[])} method. This is done
406      * by forcing the current or next scheduled invocation of the
407      * {@link LaunchTask#execute()} method to throw an exception. In addition,
408      * this method will terminate any synchronous child processes that any
409      * instances of the {@link LaunchTask} class have launched. Note, however,
410      * that this method will <b>not</b> terminate any asynchronous child
411      * processes that have been launched. Accordingly, applications that use
412      * this method are encouraged to always set the LaunchTask.TASK_NAME task's
413      * "waitForChild" attribute to "true" to ensure that the
414      * application that you want to control can be terminated via this method.
415      * After this method has been executed, it will not return until is safe to
416      * execute the {@link #start(String[])} method.
417      *
418      * @return true if this method completed without error and false if an
419      * error occurred or the launch process is already stopped
420      */

421     public static boolean stop() {
422
423         synchronized (Launcher.lock) {
424             // Check the stopped flag to avoid concurrent execution of this
425
// method
426
if (Launcher.isStopped())
427                 return false;
428
429             // Make sure that the start() method is running. If not, just
430
// return as there is nothing to do.
431
if (Launcher.isStarted())
432                 Launcher.setStopped(true);
433             else
434                 return false;
435         }
436
437         boolean returnValue = true;
438
439         try {
440
441             // Kill all of the synchronous child processes
442
killChildProcesses();
443
444             // Wait for the start() method to reset the start flag
445
synchronized (Launcher.lock) {
446                 if (Launcher.isStarted())
447                     Launcher.lock.wait();
448             }
449
450             // Make sure that the start() method has really finished
451
if (Launcher.isStarted())
452                 returnValue = true;
453
454         } catch (Throwable JavaDoc t) {
455             // Log any errors
456
returnValue = false;
457             String JavaDoc message = t.getMessage();
458             if (Launcher.verbose)
459                 Launcher.error(t);
460             else
461                 Launcher.error(message, false);
462         } finally {
463             // Reset stopped flag
464
Launcher.setStopped(false);
465         }
466
467         return returnValue;
468
469     }
470
471     /**
472      * Print a detailed error message and exit.
473      *
474      * @param message the message to be printed
475      * @param usage if true, print a usage statement after the message
476      */

477     public static void error(String JavaDoc message, boolean usage) {
478
479         if (message != null)
480             Launcher.getLog().println(Launcher.getLocalizedString("error") + ": " + message);
481         if (usage)
482             Launcher.getLog().println(Launcher.getLocalizedString("usage"));
483
484     }
485
486     /**
487      * Print a detailed error message and exit.
488      *
489      * @param message the exception whose stack trace is to be printed.
490      */

491     public static void error(Throwable JavaDoc t) {
492
493         String JavaDoc message = t.getMessage();
494         if (!Launcher.verbose && message != null)
495             Launcher.getLog().println(Launcher.getLocalizedString("error") + ": " + message);
496         else
497             t.printStackTrace(Launcher.getLog());
498
499     }
500
501     /**
502      * Get the canonical directory of the class or jar file that this class was
503      * loaded. This method can be used to calculate the root directory of an
504      * installation.
505      *
506      * @return the canonical directory of the class or jar file that this class
507      * file was loaded from
508      * @throws IOException if the canonical directory or jar file
509      * cannot be found
510      */

511     public static File JavaDoc getBootstrapDir() throws IOException JavaDoc {
512
513         File JavaDoc file = Launcher.getBootstrapFile();
514         if (file.isDirectory())
515             return file;
516         else
517             return file.getParentFile();
518
519     }
520
521     /**
522      * Get the canonical directory or jar file that this class was loaded
523      * from.
524      *
525      * @return the canonical directory or jar file that this class
526      * file was loaded from
527      * @throws IOException if the canonical directory or jar file
528      * cannot be found
529      */

530     public static File JavaDoc getBootstrapFile() throws IOException JavaDoc {
531
532         if (bootstrapFile == null) {
533
534             // Get a URL for where this class was loaded from
535
String JavaDoc classResourceName = "/" + Launcher.class.getName().replace('.', '/') + ".class";
536             URL JavaDoc resource = Launcher.class.getResource(classResourceName);
537             if (resource == null)
538                 throw new IOException JavaDoc(Launcher.getLocalizedString("bootstrap.file.not.found") + ": " + Launcher.class.getName());
539             String JavaDoc resourcePath = null;
540             String JavaDoc embeddedClassName = null;
541             boolean isJar = false;
542             String JavaDoc protocol = resource.getProtocol();
543             if ((protocol != null) &&
544                 (protocol.indexOf("jar") >= 0)) {
545                 isJar = true;
546             }
547             if (isJar) {
548                 resourcePath = URLDecoder.decode(resource.getFile());
549                 embeddedClassName = "!" + classResourceName;
550             } else {
551                 resourcePath = URLDecoder.decode(resource.toExternalForm());
552                 embeddedClassName = classResourceName;
553             }
554             int sep = resourcePath.lastIndexOf(embeddedClassName);
555             if (sep >= 0)
556                 resourcePath = resourcePath.substring(0, sep);
557
558             // Now that we have a URL, make sure that it is a "file" URL
559
// as we need to coerce the URL into a File object
560
if (resourcePath.indexOf("file:") == 0)
561                 resourcePath = resourcePath.substring(5);
562             else
563                 throw new IOException JavaDoc(Launcher.getLocalizedString("bootstrap.file.not.found") + ": " + Launcher.class.getName());
564
565             // Coerce the URL into a file and check that it exists. Note that
566
// the JVM <code>File(String)</code> constructor automatically
567
// flips all '/' characters to '\' on Windows and there are no
568
// valid escape characters so we sould not have to worry about
569
// URL encoded slashes.
570
File JavaDoc file = new File JavaDoc(resourcePath);
571             if (!file.exists() || !file.canRead())
572                 throw new IOException JavaDoc(Launcher.getLocalizedString("bootstrap.file.not.found") + ": " + Launcher.class.getName());
573             bootstrapFile = file.getCanonicalFile();
574
575         }
576
577         return bootstrapFile;
578
579     }
580
581     /**
582      * Get the full path of the Java command to execute.
583      *
584      * @return a string suitable for executing a child JVM
585      */

586     public static synchronized String JavaDoc getJavaCommand() {
587
588         if (javaCmd == null) {
589
590             String JavaDoc osname = System.getProperty("os.name").toLowerCase();
591             String JavaDoc commandName = null;
592             if (osname.indexOf("windows") >= 0) {
593                 // Always use javaw.exe on Windows so that we aren't bound to an
594
// MS-DOS window
595
commandName = "javaw.exe";
596             } else {
597                 commandName = "java";
598             }
599             javaCmd = System.getProperty("java.home") + File.separator + "bin" + File.separator + commandName;
600
601         }
602
603         return javaCmd;
604
605     }
606
607     /**
608      * Get the full path of the JDB command to execute.
609      *
610      * @return a string suitable for executing a child JDB debugger
611      */

612     public static synchronized String JavaDoc getJDBCommand() {
613
614         if (jdbCmd == null) {
615
616             String JavaDoc osname = System.getProperty("os.name").toLowerCase();
617             String JavaDoc commandName = null;
618             if (osname.indexOf("windows") >= 0)
619                 commandName = "jdb.exe";
620             else
621                 commandName = "jdb";
622             jdbCmd = new File JavaDoc(System.getProperty("java.home")).getParent() + File.separator + "bin" + File.separator + commandName;
623
624         }
625
626         return jdbCmd;
627
628     }
629
630     /**
631      * Get the PrintStream that all output should printed to. The default
632      * PrintStream returned in System.err.
633      *
634      * @return the PrintStream instance to print output to
635      */

636     public static synchronized PrintStream JavaDoc getLog() {
637
638         return Launcher.log;
639
640     }
641
642     /**
643      * Set the classpath to the current JVM's tools classes.
644      *
645      * @return a string suitable for use as a JVM's -classpath argument
646      * @throws IOException if the tools classes cannot be found
647      */

648     public static synchronized String JavaDoc getToolsClasspath() throws IOException JavaDoc {
649
650         if (toolsClasspath == null) {
651
652             File JavaDoc javaHome = null;
653             javaHome = new File JavaDoc(System.getProperty("java.home")).getCanonicalFile();
654             Class JavaDoc clazz = null;
655             String JavaDoc[] toolsPaths = new String JavaDoc[2];
656             toolsPaths[0] = javaHome.getParent() + File.separator +
657                 "lib" + File.separator + "tools.jar";
658             toolsPaths[1] = javaHome.getPath() + File.separator +
659                 "lib" + File.separator + "tools.jar";
660             File JavaDoc toolsFile = null;
661             for (int i = 0; i < toolsPaths.length; i++) {
662                 ClassLoader JavaDoc loader = ClassLoader.getSystemClassLoader();
663                 toolsFile = new File JavaDoc(toolsPaths[i]);
664                 // Check if the jar file exists and is readable
665
if (!toolsFile.isFile() || !toolsFile.canRead())
666                     toolsFile = null;
667                 if (toolsFile != null) {
668                     try {
669                         URL JavaDoc toolsURL = toolsFile.toURL();
670                         loader = new URLClassLoader JavaDoc(new URL JavaDoc[]{toolsURL}, loader);
671                     } catch (Exception JavaDoc e) {
672                         toolsFile = null;
673                     }
674                 }
675                 // Try to load the javac class just to be sure. Note that we
676
// use the system class loader if the file does not exist to
677
// handle cases like Mac OS X where the tools.jar classes are
678
// loaded by the bootstrap class loader.
679
try {
680                     clazz = loader.loadClass("sun.tools.javac.Main");
681                     if (clazz != null)
682                         break;
683                 } catch (Exception JavaDoc e) {}
684             }
685
686             if (clazz == null)
687                 throw new IOException JavaDoc(Launcher.getLocalizedString("sdk.tools.not.found"));
688
689             // Save classpath.
690
if (toolsFile != null)
691                 toolsClasspath = toolsFile.getPath();
692             else
693                 toolsClasspath = "";
694
695         }
696
697         return toolsClasspath;
698
699     }
700
701     /**
702      * Get a localized property. This method will search for localized
703      * properties and will resolve ${...} style macros in the localized string.
704      *
705      * @param key the localized property to retrieve
706      * @return the localized and resolved property value
707      */

708     public static String JavaDoc getLocalizedString(String JavaDoc key) {
709
710         return Launcher.getLocalizedString(key, Launcher.class.getName());
711
712     }
713
714     /**
715      * Get a localized property. This method will search for localized
716      * properties and will resolve ${...} style macros in the localized string.
717      *
718      * @param key the localized property to retrieve
719      * @param className the name of the class to retrieve the property for
720      * @return the localized and resolved property value
721      */

722     public static String JavaDoc getLocalizedString(String JavaDoc key, String JavaDoc className) {
723
724         try {
725             ResourceBundle JavaDoc resourceBundle = ResourceBundle.getBundle(className);
726             return Launcher.resolveString(resourceBundle.getString(key));
727         } catch (Exception JavaDoc e) {
728             // We should at least make it clear that the property is not
729
// defined in the properties file
730
return "<" + key + " property>";
731         }
732
733     }
734
735     /**
736      * Resolve ${...} style macros in strings. This method will replace any
737      * embedded ${...} strings in the specified unresolved parameter with the
738      * value of the system property in the enclosed braces. Note that any '$'
739      * characters can be escaped by putting '$$' in the specified parameter.
740      * In additional, the following special macros will be resolved:
741      * <ul>
742      * <li><code>${launcher.executable.name}</code> will be substituted with the
743      * value of the "org.apache.commons.launcher.executableName" system
744      * property, the "-executablename" command line argument, or, if both of
745      * those are undefined, with the absolute path to the Java executable plus
746      * its classpath and main class name arguments
747      * <li><code>${launcher.bootstrap.file}</code> will get substituted with
748      * the value returned by {@link #getBootstrapFile()}
749      * <li><code>${launcher.bootstrap.dir}</code> will get substituted with
750      * the value returned by {@link #getBootstrapDir()}
751      *
752      * @param unresolved the string to be resolved
753      * @return the resolved String
754      * @throws IOException if any error occurs
755      */

756     private static String JavaDoc resolveString(String JavaDoc unresolved) throws IOException JavaDoc {
757
758         if (unresolved == null)
759             return null;
760
761         // Substitute system property strings
762
StringBuffer JavaDoc buf = new StringBuffer JavaDoc();
763         int tokenEnd = 0;
764         int tokenStart = 0;
765         char token = '$';
766         boolean escapeChar = false;
767         boolean firstToken = true;
768         boolean lastToken = false;
769
770         while (!lastToken) {
771
772             tokenEnd = unresolved.indexOf(token, tokenStart);
773
774             // Determine if this is the first token
775
if (firstToken) {
776                 firstToken = false;
777                 // Skip if first token is zero length
778
if (tokenEnd - tokenStart == 0) {
779                     tokenStart = ++tokenEnd;
780                     continue;
781                 }
782             }
783             // Determine if this is the last token
784
if (tokenEnd < 0) {
785                 lastToken = true;
786                 tokenEnd = unresolved.length();
787             }
788
789             if (escapeChar) {
790
791                 // Don't parse the string
792
buf.append(token + unresolved.substring(tokenStart, tokenEnd));
793                 escapeChar = !escapeChar;
794
795             } else {
796
797                 // Parse the string
798
int openProp = unresolved.indexOf('{', tokenStart);
799                 int closeProp = unresolved.indexOf('}', tokenStart + 1);
800                 String JavaDoc prop = null;
801
802                 // We must have a '{' in the first character and a closing
803
// '}' after that
804
if (openProp != tokenStart ||
805                     closeProp < tokenStart + 1 ||
806                     closeProp >= tokenEnd)
807                 {
808                     buf.append(unresolved.substring(tokenStart, tokenEnd));
809                 } else {
810                     // Property found
811
String JavaDoc propName = unresolved.substring(tokenStart + 1, closeProp);
812                     if ("launcher.executable.name".equals(propName)) {
813                         prop = System.getProperty(ChildMain.EXECUTABLE_PROP_NAME);
814                         if (prop != null) {
815                             // Quote the property
816
prop = "\"" + prop + "\"";
817                         } else {
818                             // Set property to fully quoted Java command line
819
String JavaDoc classpath = Launcher.getBootstrapFile().getPath();
820                             prop = "\"" + System.getProperty("java.home") + File.separator + "bin" + File.separator + "java\" -classpath \"" + classpath + "\" LauncherBootstrap";
821                         }
822                     } else if ("launcher.bootstrap.file".equals(propName)) {
823                         prop = Launcher.getBootstrapFile().getPath();
824                     } else if ("launcher.bootstrap.dir".equals(propName)) {
825                         prop = Launcher.getBootstrapDir().getPath();
826                     } else {
827                         prop = System.getProperty(unresolved.substring(tokenStart + 1, closeProp));
828                     }
829                     if (prop == null)
830                         prop = "";
831                     buf.append(prop + unresolved.substring(++closeProp, tokenEnd));
832                 }
833
834             }
835
836             // If this is a blank token, then the next starts with the
837
// token character. So, treat this token as an escape
838
// character for the next token.
839
if (tokenEnd - tokenStart == 0)
840                 escapeChar = !escapeChar;
841
842             tokenStart = ++tokenEnd;
843
844         }
845
846         return buf.toString();
847
848     }
849
850     /**
851      * Set the PrintStream that all output should printed to.
852      *
853      * @param a PrintStream instance to print output to
854      */

855     public static synchronized void setLog(PrintStream JavaDoc log) {
856
857         if (log != null)
858             Launcher.log = log;
859         else
860             Launcher.log = System.err;
861
862     }
863
864     /**
865      * Set the started flag.
866      *
867      * @param started the value of the started flag
868      */

869     private static synchronized void setStarted(boolean started) {
870
871         Launcher.started = started;
872
873     }
874
875     /**
876      * Set the stopped flag.
877      *
878      * @param stopped the value of the stopped flag
879      */

880     private static synchronized void setStopped(boolean stopped) {
881
882         Launcher.stopped = stopped;
883
884     }
885
886     /**
887      * Set the verbose flag.
888      *
889      * @param verbose the value of the verbose flag
890      */

891     public static synchronized void setVerbose(boolean verbose) {
892
893         Launcher.verbose = verbose;
894
895     }
896
897     /**
898      * Iterate through the list of synchronous child process launched by
899      * all of the {@link LaunchTask} instances.
900      */

901     public static void killChildProcesses() {
902
903         Process JavaDoc[] procs = LaunchTask.getChildProcesses();
904         for (int i = 0; i < procs.length; i++)
905             procs[i].destroy();
906
907     }
908
909     //----------------------------------------------------------------- Methods
910

911     /**
912      * Wrapper to allow the {@link #killChildProcesses()} method to be
913      * invoked in a shutdown hook.
914      */

915     public void run() {
916
917         Launcher.killChildProcesses();
918
919     }
920
921 }
922
Popular Tags