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. import java.io.File;
  17. import java.io.FileInputStream;
  18. import java.io.FileNotFoundException;
  19. import java.lang.reflect.Method;
  20. import java.net.MalformedURLException;
  21. import java.net.URL;
  22. import java.net.URLClassLoader;
  23. import java.net.URLDecoder;
  24. import java.util.ArrayList;
  25. import java.util.Properties;
  26. import java.util.StringTokenizer;
  27. /**
  28. * This class is used as a wrapper for loading the
  29. * org.apache.commons.launcher.Launcher class and invoking its
  30. * <code>main(String[])</code> method. This particular
  31. * class is primary used by the Windows 95, 98, ME, and 2000 platforms to
  32. * overcome the difficulty of putting a jar file directly into the JVM's
  33. * classpath when using batch scripts on these platforms.
  34. * <p>
  35. * Specifically, the problem on thse platforms is when Windows uses the PATH
  36. * environment variable to find and run a batch script, %0 will resolve
  37. * incorrectly in that batch script.
  38. * <p>
  39. * The way to work around this Windows limitation is to do the following:
  40. * <ol>
  41. * <li>Put this class' class file - LauncherBootstrap.class - in the same
  42. * directory as the batch script. Do not put this class file in a jar file.
  43. * <li>Put the jar file containing the launcher's classes in the same
  44. * directory as the batch script and this class' class file. Be sure that
  45. * that the jar file is named "commons-launcher.jar".
  46. * <li>Make the Java command in the batch script invoke Java use the following
  47. * classpath arguments. Be sure to include the quotes to ensure that paths
  48. * containing spaces are handled properly:
  49. * <code>-classpath %0\..;"%PATH%"</code>
  50. * </ol>
  51. *
  52. * @author Patrick Luby
  53. */
  54. public class LauncherBootstrap {
  55. //---------------------------------------------------------- Static Fields
  56. /**
  57. * Ant classpath property name
  58. */
  59. public final static String ANT_CLASSPATH_PROP_NAME = "ant.class.path";
  60. /**
  61. * Jar file name
  62. */
  63. public final static String LAUNCHER_JAR_FILE_NAME = "commons-launcher.jar";
  64. /**
  65. * Properties file name
  66. */
  67. public final static String LAUNCHER_PROPS_FILE_NAME = "launcher.properties";
  68. /**
  69. * Class name to load
  70. */
  71. public final static String LAUNCHER_MAIN_CLASS_NAME = "org.apache.commons.launcher.Launcher";
  72. /**
  73. * Cached Laucher class.
  74. */
  75. private static Class launcherClass = null;
  76. //---------------------------------------------------------- Static Methods
  77. /**
  78. * The main method.
  79. *
  80. * @param args command line arguments
  81. */
  82. public static void main(String[] args) {
  83. try {
  84. // Try to find the LAUNCHER_JAR_FILE_NAME file in the class
  85. // loader's and JVM's classpath.
  86. URL coreURL = LauncherBootstrap.class.getResource("/" + LauncherBootstrap.LAUNCHER_JAR_FILE_NAME);
  87. if (coreURL == null)
  88. throw new FileNotFoundException(LauncherBootstrap.LAUNCHER_JAR_FILE_NAME);
  89. // Coerce the coreURL's directory into a file
  90. File coreDir = new File(URLDecoder.decode(coreURL.getFile())).getCanonicalFile().getParentFile();
  91. // Try to find the LAUNCHER_PROPS_FILE_NAME file in the same
  92. // directory as this class
  93. File propsFile = new File(coreDir, LauncherBootstrap.LAUNCHER_PROPS_FILE_NAME);
  94. if (!propsFile.canRead())
  95. throw new FileNotFoundException(propsFile.getPath());
  96. // Load the properties in the LAUNCHER_PROPS_FILE_NAME
  97. Properties props = new Properties();
  98. FileInputStream fis = new FileInputStream(propsFile);
  99. props.load(fis);
  100. fis.close();
  101. // Create a class loader that contains the Launcher, Ant, and
  102. // JAXP classes.
  103. URL[] antURLs = LauncherBootstrap.fileListToURLs((String)props.get(LauncherBootstrap.ANT_CLASSPATH_PROP_NAME));
  104. URL[] urls = new URL[1 + antURLs.length];
  105. urls[0] = coreURL;
  106. for (int i = 0; i < antURLs.length; i++)
  107. urls[i + 1] = antURLs[i];
  108. ClassLoader parentLoader = Thread.currentThread().getContextClassLoader();
  109. URLClassLoader loader = null;
  110. if (parentLoader != null)
  111. loader = new URLClassLoader(urls, parentLoader);
  112. else
  113. loader = new URLClassLoader(urls);
  114. // Load the LAUNCHER_MAIN_CLASS_NAME class
  115. launcherClass = loader.loadClass(LAUNCHER_MAIN_CLASS_NAME);
  116. // Get the LAUNCHER_MAIN_CLASS_NAME class' getLocalizedString()
  117. // method as we need it for printing the usage statement
  118. Method getLocalizedStringMethod = launcherClass.getDeclaredMethod("getLocalizedString", new Class[]{ String.class });
  119. // Invoke the LAUNCHER_MAIN_CLASS_NAME class' start() method.
  120. // If the ant.class.path property is not set correctly in the
  121. // LAUNCHER_PROPS_FILE_NAME, this will throw an exception.
  122. Method startMethod = launcherClass.getDeclaredMethod("start", new Class[]{ String[].class });
  123. int returnValue = ((Integer)startMethod.invoke(null, new Object[]{ args })).intValue();
  124. // Always exit cleanly after invoking the start() method
  125. System.exit(returnValue);
  126. } catch (Throwable t) {
  127. t.printStackTrace();
  128. System.exit(1);
  129. }
  130. }
  131. /**
  132. * Convert a ":" separated list of URL file fragments into an array of URL
  133. * objects. Note that any all URL file fragments must conform to the format
  134. * required by the "file" parameter in the
  135. * {@link URL(String, String, String)} constructor.
  136. *
  137. * @param fileList the ":" delimited list of URL file fragments to be
  138. * converted
  139. * @return an array of URL objects
  140. * @throws MalformedURLException if the fileList parameter contains any
  141. * malformed URLs
  142. */
  143. private static URL[] fileListToURLs(String fileList)
  144. throws MalformedURLException
  145. {
  146. if (fileList == null || "".equals(fileList))
  147. return new URL[0];
  148. // Parse the path string
  149. ArrayList list = new ArrayList();
  150. StringTokenizer tokenizer = new StringTokenizer(fileList, ":");
  151. URL bootstrapURL = LauncherBootstrap.class.getResource("/" + LauncherBootstrap.class.getName() + ".class");
  152. while (tokenizer.hasMoreTokens())
  153. list.add(new URL(bootstrapURL, tokenizer.nextToken()));
  154. return (URL[])list.toArray(new URL[list.size()]);
  155. }
  156. }