001: /*---------------------------------------------------------------------------*\
002: $Id: Bootstrap.java 7041 2007-09-09 01:04:47Z bmc $
003: ---------------------------------------------------------------------------
004: This software is released under a BSD-style license:
005:
006: Copyright (c) 2004-2007 Brian M. Clapper. All rights reserved.
007:
008: Redistribution and use in source and binary forms, with or without
009: modification, are permitted provided that the following conditions are
010: met:
011:
012: 1. Redistributions of source code must retain the above copyright notice,
013: this list of conditions and the following disclaimer.
014:
015: 2. The end-user documentation included with the redistribution, if any,
016: must include the following acknowlegement:
017:
018: "This product includes software developed by Brian M. Clapper
019: (bmc@clapper.org, http://www.clapper.org/bmc/). That software is
020: copyright (c) 2004-2007 Brian M. Clapper."
021:
022: Alternately, this acknowlegement may appear in the software itself,
023: if wherever such third-party acknowlegements normally appear.
024:
025: 3. Neither the names "clapper.org", "curn", nor any of the names of the
026: project contributors may be used to endorse or promote products
027: derived from this software without prior written permission. For
028: written permission, please contact bmc@clapper.org.
029:
030: 4. Products derived from this software may not be called "curn", nor may
031: "clapper.org" appear in their names without prior written permission
032: of Brian M. Clapper.
033:
034: THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
035: WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
036: MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
037: NO EVENT SHALL BRIAN M. CLAPPER BE LIABLE FOR ANY DIRECT, INDIRECT,
038: INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
039: NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
040: DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
041: THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
042: (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
043: THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
044: \*---------------------------------------------------------------------------*/
045:
046: package org.clapper.curn;
047:
048: import java.lang.reflect.Method;
049: import java.lang.reflect.Modifier;
050: import java.lang.reflect.InvocationTargetException;
051:
052: import java.net.URL;
053: import java.net.URLClassLoader;
054: import java.net.MalformedURLException;
055:
056: import java.io.File;
057:
058: import java.util.ArrayList;
059:
060: /**
061: * <p>Main program that bootstraps <i>curn</i> by adding new elements to the
062: * classpath on the fly. This utility takes a list of jar files, zip files
063: * and/or directories. It loads them all into a class loader and, at the
064: * same time, searches any directories (not recursively) for jars and zip
065: * files. It then invokes the tool specified on the command line. Usage:</p>
066: *
067: * <pre>
068: * java org.clapper.curn.Bootstrap [jar|zip|dir] ... -- programClassName [args]
069: * </pre>
070: *
071: * <p>This utility performs the following parameter substitutions on the
072: * <tt>[jar|zip|dir]</tt> parameters:</p>
073: *
074: * <table border="1">
075: * <tr valign="top" align="left">
076: * <th>Parameter</th>
077: * <th>Substituted with</th>
078: * </tr>
079: * <tr valign="top">
080: * <td><tt>@user.home</tt></td>
081: * <td>The value of the "user.home" Java system property (i.e., the
082: * user's home directory, if any).</td>
083: * </tr>
084: * <tr valign="top">
085: * <td><tt>@user.name</tt></td>
086: * <td>The value of the "user.name" Java system property (i.e., the
087: * invoking user's name, if known).</td>
088: * </tr>
089: * <tr valign="top">
090: * <td><tt>@java.home</tt></td>
091: * <td>The value of the "java.home" Java system property (i.e., the
092: * location of the Java JRE).</td>
093: * </tr>
094: * <tr valign="top">
095: * <td><tt>@pwd</tt></td>
096: * <td>The current working directory (i.e., the value of the "user.dir"
097: * Java system property).</td>
098: * </tr>
099: * </table>
100: *
101: * @version <tt>$Revision: 7041 $</tt>
102: *
103: * @author Copyright © 2006 Brian M. Clapper
104: */
105: public class Bootstrap {
106: /*----------------------------------------------------------------------*\
107: Inner Classes
108: \*----------------------------------------------------------------------*/
109:
110: /*----------------------------------------------------------------------*\
111: Constructor
112: \*----------------------------------------------------------------------*/
113:
114: /**
115: * Can't be instantiated.
116: */
117: private Bootstrap() {
118: }
119:
120: /*----------------------------------------------------------------------*\
121: Main Program
122: \*----------------------------------------------------------------------*/
123:
124: /**
125: * Main program
126: */
127: public static void main(final String[] args) throws Throwable {
128: try {
129: // Use as few classes as possible.
130:
131: int i = 0;
132: int endOfArgsIndex = 0;
133:
134: while ((i < args.length) && (!args[i].equals("--")))
135: i++;
136:
137: if (i == args.length) {
138: System.err.println(args[i]);
139: usage();
140: System.exit(1);
141: }
142:
143: endOfArgsIndex = i;
144: File[] searchItems = new File[endOfArgsIndex];
145: for (i = 0; i < endOfArgsIndex; i++) {
146: String path = args[i].replace("@user.home",
147: getProperty("user.home")).replace("@user.name",
148: getProperty("user.name")).replace("@java.home",
149: getProperty("java.home")).replace("@pwd",
150: getProperty("user.dir"));
151: searchItems[i] = new File(path);
152: }
153:
154: // Save the command class name and arguments.
155:
156: i++;
157: String commandClassName = args[i++];
158: String commandArgs[] = null;
159:
160: if (i < args.length) {
161: commandArgs = new String[args.length - i];
162: System.arraycopy(args, i, commandArgs, 0,
163: commandArgs.length);
164: }
165:
166: // Expand the search items.
167:
168: ArrayList<File> expandedSearchItems = new ArrayList<File>();
169: expandSearchItems(searchItems, expandedSearchItems);
170:
171: // Add entire set of expanded items to the class path.
172:
173: String classPath = System.getProperty("java.class.path");
174: String pathSep = (classPath.endsWith(File.pathSeparator) ? ""
175: : File.pathSeparator);
176: StringBuilder newClassPath = new StringBuilder();
177: newClassPath.append(classPath);
178: for (File f : expandedSearchItems) {
179: newClassPath.append(pathSep);
180: newClassPath.append(f.getPath());
181: pathSep = File.pathSeparator;
182: }
183:
184: System.setProperty("java.class.path", newClassPath
185: .toString());
186:
187: // Create the class loader.
188:
189: ClassLoader classLoader = createClassLoader(expandedSearchItems);
190:
191: // Load and run the utility.
192:
193: loadAndRun(commandClassName, commandArgs, classLoader);
194: }
195:
196: catch (ArrayIndexOutOfBoundsException ex) {
197: usage();
198: System.exit(1);
199: }
200: }
201:
202: /*----------------------------------------------------------------------*\
203: Private Methods
204: \*----------------------------------------------------------------------*/
205:
206: private static void usage() {
207: System.out.println("Usage: java " + Bootstrap.class
208: + " [jar|zip|directory] ... -- "
209: + "programClassName [args]");
210: }
211:
212: private static ClassLoader createClassLoader(
213: final ArrayList<File> searchItems)
214: throws MalformedURLException {
215: ArrayList<URL> urlList = new ArrayList<URL>();
216:
217: for (File f : searchItems) {
218: // URLClassLoader wants directory URLs to end in "/".
219:
220: if (f.isDirectory()) {
221: String fileName = f.getName();
222: if (!fileName.endsWith("/"))
223: f = new File(fileName + "/");
224: }
225:
226: urlList.add(f.toURI().toURL());
227: }
228:
229: /*
230: // Add the class path.
231:
232: String classpath = System.getProperty ("java.class.path");
233: if (classpath != null)
234: {
235: StringTokenizer tok = new StringTokenizer (classpath,
236: File.pathSeparator);
237: while (tok.hasMoreTokens())
238: urlList.add (new File (tok.nextToken()).toURL());
239: }
240: */
241:
242: return new URLClassLoader(urlList.toArray(new URL[urlList
243: .size()]), ClassLoader.getSystemClassLoader());
244: }
245:
246: private static void expandSearchItems(final File[] searchItems,
247: final ArrayList<File> expandedItems)
248: throws MalformedURLException {
249: for (int i = 0; i < searchItems.length; i++) {
250: File f = searchItems[i];
251: String fileName = f.getName();
252:
253: if (!f.exists())
254: continue;
255:
256: if (f.isDirectory()) {
257: File[] items = f.listFiles();
258: if (items != null)
259: expandSearchItems(items, expandedItems);
260:
261: expandedItems.add(f);
262: }
263:
264: else if (fileName.endsWith(".jar")
265: || fileName.endsWith(".zip")) {
266: expandedItems.add(f);
267: }
268: }
269: }
270:
271: private static void loadAndRun(final String commandClassName,
272: final String[] args, final ClassLoader classLoader)
273: throws BootstrapException {
274: Class<?> cls;
275: try {
276: cls = classLoader.loadClass(commandClassName);
277: }
278:
279: catch (ClassNotFoundException ex) {
280: throw new BootstrapException("Can't load command class "
281: + commandClassName, ex);
282: }
283: Method mainMethod;
284: try {
285: mainMethod = cls.getMethod("main",
286: new Class[] { String[].class });
287: }
288:
289: catch (SecurityException ex) {
290: throw new BootstrapException("Can't get method "
291: + commandClassName + ".main()", ex);
292: }
293:
294: catch (NoSuchMethodException ex) {
295: throw new BootstrapException("Can't findmethod "
296: + commandClassName + ".main()", ex);
297: }
298:
299: if ((mainMethod.getModifiers() & Modifier.STATIC) == 0) {
300: throw new BootstrapException(commandClassName
301: + ".main() is not static");
302: }
303:
304: try {
305: Thread.currentThread().setContextClassLoader(classLoader);
306: mainMethod.invoke(null, new Object[] { args });
307: }
308:
309: catch (InvocationTargetException ex) {
310: throw new BootstrapException("Cannot invoke "
311: + commandClassName + ".main()", ex);
312: }
313:
314: catch (IllegalAccessException ex) {
315: throw new BootstrapException("Cannot invoke "
316: + commandClassName + ".main()", ex);
317: }
318: }
319:
320: private static String getProperty(final String name) {
321: String val = System.getProperty(name);
322:
323: return (val == null) ? "" : val;
324: }
325: }
|