- /*
- * Copyright 1999-2004 The Apache Software Foundation.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
- package org.apache.commons.launcher;
-
- import java.io.File;
- import java.io.IOException;
- import java.io.PrintStream;
- import java.net.URL;
- import java.net.URLClassLoader;
- import java.net.URLDecoder;
- import java.util.ResourceBundle;
-
- import org.apache.commons.launcher.types.ArgumentSet;
- import org.apache.commons.launcher.types.JVMArgumentSet;
- import org.apache.commons.launcher.types.SysPropertySet;
- import org.apache.tools.ant.Main;
- import org.apache.tools.ant.Project;
- import org.apache.tools.ant.ProjectHelper;
- import org.apache.tools.ant.taskdefs.Ant;
- import org.apache.tools.ant.taskdefs.Available;
- import org.apache.tools.ant.taskdefs.CallTarget;
- import org.apache.tools.ant.taskdefs.ConditionTask;
- import org.apache.tools.ant.taskdefs.Exit;
- import org.apache.tools.ant.taskdefs.Property;
- import org.apache.tools.ant.taskdefs.Mkdir;
- import org.apache.tools.ant.taskdefs.Copy;
- import org.apache.tools.ant.taskdefs.Delete;
- import org.apache.tools.ant.types.Description;
- import org.apache.tools.ant.types.FileList;
- import org.apache.tools.ant.types.FileSet;
- import org.apache.tools.ant.types.Path;
- import org.apache.tools.ant.types.PatternSet;
-
- /**
- * A class that is used to launch a Java process. The primary purpose of this
- * class is to eliminate the need for a batch or shell script to launch a Java
- * process. Some situations where elimination of a batch or shell script may be
- * desirable are:
- * <ul>
- * <li>You want to avoid having to determining where certain application paths
- * are e.g. your application's home directory, etc. Determining this
- * dynamically in a Windows batch scripts is very tricky on some versions of
- * Windows or when softlinks are used on Unix platforms.
- * <li>You need to enforce certain properties e.g. java.endorsed.dirs when
- * running with JDK 1.4.
- * <li>You want to allow users to pass in custom JVM arguments or system
- * properties without having to parse and reorder arguments in your script.
- * This can be tricky and/or messy in batch and shell scripts.
- * <li>You want to bootstrap Java properties from a configuration file instead
- * hard-coding them in your batch and shell scripts.
- * <li>You want to provide localized error messages which is very tricky to do
- * in batch and shell scripts.
- * </ul>
- *
- * @author Patrick Luby
- */
- public class Launcher implements Runnable {
-
- //----------------------------------------------------------- Static Fields
-
-
- /**
- * Cached bootstrap file.
- */
- private static File bootstrapFile = null;
-
- /**
- * Cached java command
- */
- private static String javaCmd = null;
-
- /**
- * Cached JDB command
- */
- private static String jdbCmd = null;
-
- /**
- * Default XML file name
- */
- private final static String DEFAULT_XML_FILE_NAME = "launcher.xml";
-
- /**
- * Shared lock.
- */
- private static Object lock = new Object();
-
- /**
- * Cached log
- */
- private static PrintStream log = System.err;
-
- /**
- * Cached resourceBundle
- */
- private static ResourceBundle resourceBundle = null;
-
- /**
- * The started status flag.
- */
- private static boolean started = false;
-
- /**
- * The stopped status flag.
- */
- private static boolean stopped = false;
-
- /**
- * List of supported Ant tasks.
- */
- public final static Object[] SUPPORTED_ANT_TASKS = new Object[] {
- LaunchTask.TASK_NAME, LaunchTask.class,
- "ant", Ant.class,
- "antcall", CallTarget.class,
- "available", Available.class,
- "condition", ConditionTask.class,
- "fail", Exit.class,
- "property", Property.class,
- "mkdir", Mkdir.class,
- "delete", Delete.class,
- "copy", Copy.class
- };
-
- /**
- * List of supported Ant types.
- */
- public final static Object[] SUPPORTED_ANT_TYPES = new Object[] {
- ArgumentSet.TYPE_NAME, ArgumentSet.class,
- JVMArgumentSet.TYPE_NAME, JVMArgumentSet.class,
- SysPropertySet.TYPE_NAME, SysPropertySet.class,
- "description", Description.class,
- "fileset", FileSet.class,
- "filelist", FileList.class,
- "path", Path.class,
- "patternset", PatternSet.class
- };
-
- /**
- * Cached tools classpath.
- */
- private static String toolsClasspath = null;
-
- /**
- * The verbose flag
- */
- private static boolean verbose = false;
-
- //---------------------------------------------------------- Static Methods
-
-
- /**
- * Get the started flag.
- *
- * @return the value of the started flag
- */
- public static synchronized boolean isStarted() {
-
- return Launcher.started;
-
- }
-
- /**
- * Get the stopped flag.
- *
- * @return the value of the stopped flag
- */
- public static synchronized boolean isStopped() {
-
- return Launcher.stopped;
-
- }
-
- /**
- * Start the launching process. This method is essential the
- * <code>main(String[])<code> method for this class except that this method
- * never invokes {@link System#exit(int)}. This method is designed for
- * applications that wish to invoke this class directly from within their
- * application's code.
- *
- * @param args command line arguments
- * @return the exit value of the last synchronous child JVM that was
- * launched or 1 if any other error occurs
- * @throws IllegalArgumentException if any error parsing the args parameter
- * occurs
- */
- public static int start(String[] args) throws IllegalArgumentException {
-
- // Check make sure that neither this method or the stop() method is
- // already running since we do not support concurrency
- synchronized (Launcher.lock) {
- if (Launcher.isStarted() || Launcher.isStopped())
- return 1;
- Launcher.setStarted(true);
- }
-
- int returnValue = 0;
- ClassLoader parentLoader = null;
- Thread shutdownHook = new Thread(new Launcher());
- Runtime runtime = Runtime.getRuntime();
-
- try {
-
- // Cache the current class loader for this thread and set the class
- // loader before running Ant. Note that we only set the class loader
- // if we are running a Java version earlier than 1.4 as on 1.4 this
- // causes unnecessary loading of the XML parser classes.
- parentLoader = Thread.currentThread().getContextClassLoader();
- boolean lessThan14 = true;
- try {
- Class.forName("java.lang.CharSequence");
- lessThan14 = false;
- } catch (ClassNotFoundException cnfe) {
- // If this class does not exist, then we are not running Java 1.4
- }
- if (lessThan14)
- Thread.currentThread().setContextClassLoader(Launcher.class.getClassLoader());
-
- Project project = new Project();
-
- // Set the project's class loader
- project.setCoreLoader(Launcher.class.getClassLoader());
-
- // Initialize the project. Note that we don't invoke the
- // Project.init() method directly as this will cause all of
- // the myriad of Task subclasses to load which is a big
- // performance hit. Instead, we load only the
- // Launcher.SUPPORTED_ANT_TASKS and Launcher.SUPPORTED_ANT_TYPES
- // into the project that the Launcher supports.
- for (int i = 0; i < Launcher.SUPPORTED_ANT_TASKS.length; i++) {
- // The even numbered elements should be the task name
- String taskName = (String)Launcher.SUPPORTED_ANT_TASKS[i];
- // The odd numbered elements should be the task class
- Class taskClass = (Class)Launcher.SUPPORTED_ANT_TASKS[++i];
- project.addTaskDefinition(taskName, taskClass);
- }
- for (int i = 0; i < Launcher.SUPPORTED_ANT_TYPES.length; i++) {
- // The even numbered elements should be the type name
- String typeName = (String)Launcher.SUPPORTED_ANT_TYPES[i];
- // The odd numbered elements should be the type class
- Class typeClass = (Class)Launcher.SUPPORTED_ANT_TYPES[++i];
- project.addDataTypeDefinition(typeName, typeClass);
- }
-
- // Add all system properties as project properties
- project.setSystemProperties();
-
- // Parse the arguments
- int currentArg = 0;
-
- // Set default XML file
- File launchFile = new File(Launcher.getBootstrapDir(), Launcher.DEFAULT_XML_FILE_NAME);
-
- // Get standard launcher arguments
- for ( ; currentArg < args.length; currentArg++) {
- // If we find a "-" argument or an argument without a
- // leading "-", there are no more standard launcher arguments
- if ("-".equals(args[currentArg])) {
- currentArg++;
- break;
- } else if (args[currentArg].length() > 0 && !"-".equals(args[currentArg].substring(0, 1))) {
- break;
- } else if ("-help".equals(args[currentArg])) {
- throw new IllegalArgumentException();
- } else if ("-launchfile".equals(args[currentArg])) {
- if (currentArg + 1 < args.length){
- String fileArg = args[++currentArg];
- launchFile = new File(fileArg);
- if (!launchFile.isAbsolute())
- launchFile = new File(Launcher.getBootstrapDir(), fileArg);
- } else {
- throw new IllegalArgumentException(args[currentArg] + " " + Launcher.getLocalizedString("missing.arg"));
- }
- } else if ("-executablename".equals(args[currentArg])) {
- if (currentArg + 1 < args.length)
- System.setProperty(ChildMain.EXECUTABLE_PROP_NAME, args[++currentArg]);
- else
- throw new IllegalArgumentException(args[currentArg] + " " + Launcher.getLocalizedString("missing.arg"));
- } else if ("-verbose".equals(args[currentArg])) {
- Launcher.setVerbose(true);
- } else {
- throw new IllegalArgumentException(args[currentArg] + " " + Launcher.getLocalizedString("invalid.arg"));
- }
- }
-
- // Get target
- String target = null;
- if (currentArg < args.length)
- target = args[currentArg++];
- else
- throw new IllegalArgumentException(Launcher.getLocalizedString("missing.target"));
-
- // Get user properties
- for ( ; currentArg < args.length; currentArg++) {
- // If we don't find any more "-" or "-D" arguments, there are no
- // more user properties
- if ("-".equals(args[currentArg])) {
- currentArg++;
- break;
- } else if (args[currentArg].length() <= 2 || !"-D".equals(args[currentArg].substring(0, 2))) {
- break;
- }
- int delimiter = args[currentArg].indexOf('=', 2);
- String key = null;
- String value = null;
- if (delimiter >= 2) {
- key = args[currentArg].substring(2, delimiter);
- value = args[currentArg].substring(delimiter + 1);
- } else {
- // Unfortunately, MS-DOS batch scripts will split an
- // "-Dname=value" argument into "-Dname" and "value"
- // arguments. So, we need to assume that the next
- // argument is the property value unless it appears
- // to be a different type of argument.
- key = args[currentArg].substring(2);
- if (currentArg + 1 < args.length &&
- !"-D".equals(args[currentArg + 1].substring(0, 2)))
- {
- value = args[++currentArg];
- } else {
- value = "";
- }
- }
- project.setUserProperty(key, value);
- }
-
- // Treat all remaining arguments as application arguments
- String[] appArgs = new String[args.length - currentArg];
- for (int i = 0; i < appArgs.length; i++) {
- appArgs[i] = args[i + currentArg];
- project.setUserProperty(LaunchTask.ARG_PROP_NAME + Integer.toString(i), appArgs[i]);
- }
-
- // Set standard Ant user properties
- project.setUserProperty("ant.version", Main.getAntVersion());
- project.setUserProperty("ant.file", launchFile.getCanonicalPath());
- project.setUserProperty("ant.java.version", System.getProperty("java.specification.version"));
-
- // Set the buildfile
- ProjectHelper.configureProject(project, launchFile);
-
- // Check that the target exists
- if (!project.getTargets().containsKey(target))
- throw new IllegalArgumentException(target + " " + Launcher.getLocalizedString("invalid.target"));
-
- // Execute the target
- try {
- runtime.addShutdownHook(shutdownHook);
- } catch (NoSuchMethodError nsme) {
- // Early JVMs do not support this method
- }
- project.executeTarget(target);
-
- } catch (Throwable t) {
- // Log any errors
- returnValue = 1;
- String message = t.getMessage();
- if (t instanceof IllegalArgumentException) {
- Launcher.error(message, true);
- } else {
- if (Launcher.verbose)
- Launcher.error(t);
- else
- Launcher.error(message, false);
- }
- } finally {
- synchronized (Launcher.lock) {
- // Remove the shutdown hook
- try {
- runtime.removeShutdownHook(shutdownHook);
- } catch (NoSuchMethodError nsme) {
- // Early JVMs do not support this method
- }
- // Reset the class loader after running Ant
- Thread.currentThread().setContextClassLoader(parentLoader);
- // Reset stopped flag
- Launcher.setStarted(false);
- // Notify the stop() method that we have set the class loader
- Launcher.lock.notifyAll();
- }
- }
-
- // Override return value with exit value of last synchronous child JVM
- Process[] childProcesses = LaunchTask.getChildProcesses();
- if (childProcesses.length > 0)
- returnValue = childProcesses[childProcesses.length - 1].exitValue();
-
- return returnValue;
-
- }
-
- /**
- * Interrupt the {@link #start(String[])} method. This is done
- * by forcing the current or next scheduled invocation of the
- * {@link LaunchTask#execute()} method to throw an exception. In addition,
- * this method will terminate any synchronous child processes that any
- * instances of the {@link LaunchTask} class have launched. Note, however,
- * that this method will <b>not</b> terminate any asynchronous child
- * processes that have been launched. Accordingly, applications that use
- * this method are encouraged to always set the LaunchTask.TASK_NAME task's
- * "waitForChild" attribute to "true" to ensure that the
- * application that you want to control can be terminated via this method.
- * After this method has been executed, it will not return until is safe to
- * execute the {@link #start(String[])} method.
- *
- * @return true if this method completed without error and false if an
- * error occurred or the launch process is already stopped
- */
- public static boolean stop() {
-
- synchronized (Launcher.lock) {
- // Check the stopped flag to avoid concurrent execution of this
- // method
- if (Launcher.isStopped())
- return false;
-
- // Make sure that the start() method is running. If not, just
- // return as there is nothing to do.
- if (Launcher.isStarted())
- Launcher.setStopped(true);
- else
- return false;
- }
-
- boolean returnValue = true;
-
- try {
-
- // Kill all of the synchronous child processes
- killChildProcesses();
-
- // Wait for the start() method to reset the start flag
- synchronized (Launcher.lock) {
- if (Launcher.isStarted())
- Launcher.lock.wait();
- }
-
- // Make sure that the start() method has really finished
- if (Launcher.isStarted())
- returnValue = true;
-
- } catch (Throwable t) {
- // Log any errors
- returnValue = false;
- String message = t.getMessage();
- if (Launcher.verbose)
- Launcher.error(t);
- else
- Launcher.error(message, false);
- } finally {
- // Reset stopped flag
- Launcher.setStopped(false);
- }
-
- return returnValue;
-
- }
-
- /**
- * Print a detailed error message and exit.
- *
- * @param message the message to be printed
- * @param usage if true, print a usage statement after the message
- */
- public static void error(String message, boolean usage) {
-
- if (message != null)
- Launcher.getLog().println(Launcher.getLocalizedString("error") + ": " + message);
- if (usage)
- Launcher.getLog().println(Launcher.getLocalizedString("usage"));
-
- }
-
- /**
- * Print a detailed error message and exit.
- *
- * @param message the exception whose stack trace is to be printed.
- */
- public static void error(Throwable t) {
-
- String message = t.getMessage();
- if (!Launcher.verbose && message != null)
- Launcher.getLog().println(Launcher.getLocalizedString("error") + ": " + message);
- else
- t.printStackTrace(Launcher.getLog());
-
- }
-
- /**
- * Get the canonical directory of the class or jar file that this class was
- * loaded. This method can be used to calculate the root directory of an
- * installation.
- *
- * @return the canonical directory of the class or jar file that this class
- * file was loaded from
- * @throws IOException if the canonical directory or jar file
- * cannot be found
- */
- public static File getBootstrapDir() throws IOException {
-
- File file = Launcher.getBootstrapFile();
- if (file.isDirectory())
- return file;
- else
- return file.getParentFile();
-
- }
-
- /**
- * Get the canonical directory or jar file that this class was loaded
- * from.
- *
- * @return the canonical directory or jar file that this class
- * file was loaded from
- * @throws IOException if the canonical directory or jar file
- * cannot be found
- */
- public static File getBootstrapFile() throws IOException {
-
- if (bootstrapFile == null) {
-
- // Get a URL for where this class was loaded from
- String classResourceName = "/" + Launcher.class.getName().replace('.', '/') + ".class";
- URL resource = Launcher.class.getResource(classResourceName);
- if (resource == null)
- throw new IOException(Launcher.getLocalizedString("bootstrap.file.not.found") + ": " + Launcher.class.getName());
- String resourcePath = null;
- String embeddedClassName = null;
- boolean isJar = false;
- String protocol = resource.getProtocol();
- if ((protocol != null) &&
- (protocol.indexOf("jar") >= 0)) {
- isJar = true;
- }
- if (isJar) {
- resourcePath = URLDecoder.decode(resource.getFile());
- embeddedClassName = "!" + classResourceName;
- } else {
- resourcePath = URLDecoder.decode(resource.toExternalForm());
- embeddedClassName = classResourceName;
- }
- int sep = resourcePath.lastIndexOf(embeddedClassName);
- if (sep >= 0)
- resourcePath = resourcePath.substring(0, sep);
-
- // Now that we have a URL, make sure that it is a "file" URL
- // as we need to coerce the URL into a File object
- if (resourcePath.indexOf("file:") == 0)
- resourcePath = resourcePath.substring(5);
- else
- throw new IOException(Launcher.getLocalizedString("bootstrap.file.not.found") + ": " + Launcher.class.getName());
-
- // Coerce the URL into a file and check that it exists. Note that
- // the JVM <code>File(String)</code> constructor automatically
- // flips all '/' characters to '\' on Windows and there are no
- // valid escape characters so we sould not have to worry about
- // URL encoded slashes.
- File file = new File(resourcePath);
- if (!file.exists() || !file.canRead())
- throw new IOException(Launcher.getLocalizedString("bootstrap.file.not.found") + ": " + Launcher.class.getName());
- bootstrapFile = file.getCanonicalFile();
-
- }
-
- return bootstrapFile;
-
- }
-
- /**
- * Get the full path of the Java command to execute.
- *
- * @return a string suitable for executing a child JVM
- */
- public static synchronized String getJavaCommand() {
-
- if (javaCmd == null) {
-
- String osname = System.getProperty("os.name").toLowerCase();
- String commandName = null;
- if (osname.indexOf("windows") >= 0) {
- // Always use javaw.exe on Windows so that we aren't bound to an
- // MS-DOS window
- commandName = "javaw.exe";
- } else {
- commandName = "java";
- }
- javaCmd = System.getProperty("java.home") + File.separator + "bin" + File.separator + commandName;
-
- }
-
- return javaCmd;
-
- }
-
- /**
- * Get the full path of the JDB command to execute.
- *
- * @return a string suitable for executing a child JDB debugger
- */
- public static synchronized String getJDBCommand() {
-
- if (jdbCmd == null) {
-
- String osname = System.getProperty("os.name").toLowerCase();
- String commandName = null;
- if (osname.indexOf("windows") >= 0)
- commandName = "jdb.exe";
- else
- commandName = "jdb";
- jdbCmd = new File(System.getProperty("java.home")).getParent() + File.separator + "bin" + File.separator + commandName;
-
- }
-
- return jdbCmd;
-
- }
-
- /**
- * Get the PrintStream that all output should printed to. The default
- * PrintStream returned in System.err.
- *
- * @return the PrintStream instance to print output to
- */
- public static synchronized PrintStream getLog() {
-
- return Launcher.log;
-
- }
-
- /**
- * Set the classpath to the current JVM's tools classes.
- *
- * @return a string suitable for use as a JVM's -classpath argument
- * @throws IOException if the tools classes cannot be found
- */
- public static synchronized String getToolsClasspath() throws IOException {
-
- if (toolsClasspath == null) {
-
- File javaHome = null;
- javaHome = new File(System.getProperty("java.home")).getCanonicalFile();
- Class clazz = null;
- String[] toolsPaths = new String[2];
- toolsPaths[0] = javaHome.getParent() + File.separator +
- "lib" + File.separator + "tools.jar";
- toolsPaths[1] = javaHome.getPath() + File.separator +
- "lib" + File.separator + "tools.jar";
- File toolsFile = null;
- for (int i = 0; i < toolsPaths.length; i++) {
- ClassLoader loader = ClassLoader.getSystemClassLoader();
- toolsFile = new File(toolsPaths[i]);
- // Check if the jar file exists and is readable
- if (!toolsFile.isFile() || !toolsFile.canRead())
- toolsFile = null;
- if (toolsFile != null) {
- try {
- URL toolsURL = toolsFile.toURL();
- loader = new URLClassLoader(new URL[]{toolsURL}, loader);
- } catch (Exception e) {
- toolsFile = null;
- }
- }
- // Try to load the javac class just to be sure. Note that we
- // use the system class loader if the file does not exist to
- // handle cases like Mac OS X where the tools.jar classes are
- // loaded by the bootstrap class loader.
- try {
- clazz = loader.loadClass("sun.tools.javac.Main");
- if (clazz != null)
- break;
- } catch (Exception e) {}
- }
-
- if (clazz == null)
- throw new IOException(Launcher.getLocalizedString("sdk.tools.not.found"));
-
- // Save classpath.
- if (toolsFile != null)
- toolsClasspath = toolsFile.getPath();
- else
- toolsClasspath = "";
-
- }
-
- return toolsClasspath;
-
- }
-
- /**
- * Get a localized property. This method will search for localized
- * properties and will resolve ${...} style macros in the localized string.
- *
- * @param key the localized property to retrieve
- * @return the localized and resolved property value
- */
- public static String getLocalizedString(String key) {
-
- return Launcher.getLocalizedString(key, Launcher.class.getName());
-
- }
-
- /**
- * Get a localized property. This method will search for localized
- * properties and will resolve ${...} style macros in the localized string.
- *
- * @param key the localized property to retrieve
- * @param className the name of the class to retrieve the property for
- * @return the localized and resolved property value
- */
- public static String getLocalizedString(String key, String className) {
-
- try {
- ResourceBundle resourceBundle = ResourceBundle.getBundle(className);
- return Launcher.resolveString(resourceBundle.getString(key));
- } catch (Exception e) {
- // We should at least make it clear that the property is not
- // defined in the properties file
- return "<" + key + " property>";
- }
-
- }
-
- /**
- * Resolve ${...} style macros in strings. This method will replace any
- * embedded ${...} strings in the specified unresolved parameter with the
- * value of the system property in the enclosed braces. Note that any '$'
- * characters can be escaped by putting '$$' in the specified parameter.
- * In additional, the following special macros will be resolved:
- * <ul>
- * <li><code>${launcher.executable.name}</code> will be substituted with the
- * value of the "org.apache.commons.launcher.executableName" system
- * property, the "-executablename" command line argument, or, if both of
- * those are undefined, with the absolute path to the Java executable plus
- * its classpath and main class name arguments
- * <li><code>${launcher.bootstrap.file}</code> will get substituted with
- * the value returned by {@link #getBootstrapFile()}
- * <li><code>${launcher.bootstrap.dir}</code> will get substituted with
- * the value returned by {@link #getBootstrapDir()}
- *
- * @param unresolved the string to be resolved
- * @return the resolved String
- * @throws IOException if any error occurs
- */
- private static String resolveString(String unresolved) throws IOException {
-
- if (unresolved == null)
- return null;
-
- // Substitute system property strings
- StringBuffer buf = new StringBuffer();
- int tokenEnd = 0;
- int tokenStart = 0;
- char token = '$';
- boolean escapeChar = false;
- boolean firstToken = true;
- boolean lastToken = false;
-
- while (!lastToken) {
-
- tokenEnd = unresolved.indexOf(token, tokenStart);
-
- // Determine if this is the first token
- if (firstToken) {
- firstToken = false;
- // Skip if first token is zero length
- if (tokenEnd - tokenStart == 0) {
- tokenStart = ++tokenEnd;
- continue;
- }
- }
- // Determine if this is the last token
- if (tokenEnd < 0) {
- lastToken = true;
- tokenEnd = unresolved.length();
- }
-
- if (escapeChar) {
-
- // Don't parse the string
- buf.append(token + unresolved.substring(tokenStart, tokenEnd));
- escapeChar = !escapeChar;
-
- } else {
-
- // Parse the string
- int openProp = unresolved.indexOf('{', tokenStart);
- int closeProp = unresolved.indexOf('}', tokenStart + 1);
- String prop = null;
-
- // We must have a '{' in the first character and a closing
- // '}' after that
- if (openProp != tokenStart ||
- closeProp < tokenStart + 1 ||
- closeProp >= tokenEnd)
- {
- buf.append(unresolved.substring(tokenStart, tokenEnd));
- } else {
- // Property found
- String propName = unresolved.substring(tokenStart + 1, closeProp);
- if ("launcher.executable.name".equals(propName)) {
- prop = System.getProperty(ChildMain.EXECUTABLE_PROP_NAME);
- if (prop != null) {
- // Quote the property
- prop = "\"" + prop + "\"";
- } else {
- // Set property to fully quoted Java command line
- String classpath = Launcher.getBootstrapFile().getPath();
- prop = "\"" + System.getProperty("java.home") + File.separator + "bin" + File.separator + "java\" -classpath \"" + classpath + "\" LauncherBootstrap";
- }
- } else if ("launcher.bootstrap.file".equals(propName)) {
- prop = Launcher.getBootstrapFile().getPath();
- } else if ("launcher.bootstrap.dir".equals(propName)) {
- prop = Launcher.getBootstrapDir().getPath();
- } else {
- prop = System.getProperty(unresolved.substring(tokenStart + 1, closeProp));
- }
- if (prop == null)
- prop = "";
- buf.append(prop + unresolved.substring(++closeProp, tokenEnd));
- }
-
- }
-
- // If this is a blank token, then the next starts with the
- // token character. So, treat this token as an escape
- // character for the next token.
- if (tokenEnd - tokenStart == 0)
- escapeChar = !escapeChar;
-
- tokenStart = ++tokenEnd;
-
- }
-
- return buf.toString();
-
- }
-
- /**
- * Set the PrintStream that all output should printed to.
- *
- * @param a PrintStream instance to print output to
- */
- public static synchronized void setLog(PrintStream log) {
-
- if (log != null)
- Launcher.log = log;
- else
- Launcher.log = System.err;
-
- }
-
- /**
- * Set the started flag.
- *
- * @param started the value of the started flag
- */
- private static synchronized void setStarted(boolean started) {
-
- Launcher.started = started;
-
- }
-
- /**
- * Set the stopped flag.
- *
- * @param stopped the value of the stopped flag
- */
- private static synchronized void setStopped(boolean stopped) {
-
- Launcher.stopped = stopped;
-
- }
-
- /**
- * Set the verbose flag.
- *
- * @param verbose the value of the verbose flag
- */
- public static synchronized void setVerbose(boolean verbose) {
-
- Launcher.verbose = verbose;
-
- }
-
- /**
- * Iterate through the list of synchronous child process launched by
- * all of the {@link LaunchTask} instances.
- */
- public static void killChildProcesses() {
-
- Process[] procs = LaunchTask.getChildProcesses();
- for (int i = 0; i < procs.length; i++)
- procs[i].destroy();
-
- }
-
- //----------------------------------------------------------------- Methods
-
- /**
- * Wrapper to allow the {@link #killChildProcesses()} method to be
- * invoked in a shutdown hook.
- */
- public void run() {
-
- Launcher.killChildProcesses();
-
- }
-
- }