1 package org.codehaus.classworlds;
2
3 /*
4 $Id: Launcher.java,v 1.4 2003/09/22 16:12:54 jvanzyl Exp $
5
6 Copyright 2002 (C) The Werken Company. All Rights Reserved.
7
8 Redistribution and use of this software and associated documentation
9 ("Software"), with or without modification, are permitted provided
10 that the following conditions are met:
11
12 1. Redistributions of source code must retain copyright
13 statements and notices. Redistributions must also contain a
14 copy of this document.
15
16 2. Redistributions in binary form must reproduce the
17 above copyright notice, this list of conditions and the
18 following disclaimer in the documentation and/or other
19 materials provided with the distribution.
20
21 3. The name "classworlds" must not be used to endorse or promote
22 products derived from this Software without prior written
23 permission of The Werken Company. For written permission,
24 please contact bob@werken.com.
25
26 4. Products derived from this Software may not be called "classworlds"
27 nor may "classworlds" appear in their names without prior written
28 permission of The Werken Company. "classworlds" is a registered
29 trademark of The Werken Company.
30
31 5. Due credit should be given to The Werken Company.
32 (http://classworlds.werken.com/).
33
34 THIS SOFTWARE IS PROVIDED BY THE WERKEN COMPANY AND CONTRIBUTORS
35 ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
36 NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
37 FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
38 THE WERKEN COMPANY OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
39 INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
40 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
41 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
42 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
43 STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
44 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
45 OF THE POSSIBILITY OF SUCH DAMAGE.
46
47 */
48
49 import java.io.IOException;
50 import java.io.InputStream;
51 import java.io.FileInputStream;
52 import java.lang.reflect.Method;
53 import java.lang.reflect.Modifier;
54 import java.lang.reflect.InvocationTargetException;
55 import java.net.MalformedURLException;
56
57 /*** Command-line invokable application launcher.
58 *
59 * <p>
60 * This launcher class assists in the creation of classloaders and <code>ClassRealm</code>s
61 * from a configuration file and the launching of the application's <code>main</code>
62 * method from the correct class loaded through the correct classloader.
63 * </p>
64 *
65 * <p>
66 * The path to the configuration file is specified using the <code>classworlds.conf</code>
67 * system property, typically specified using the <code>-D</code> switch to
68 * <code>java</code>.
69 * </p>
70 *
71 * @author <a href="mailto:bob@eng.werken.com">bob mcwhirter</a>
72 *
73 * @version $Id: Launcher.java,v 1.4 2003/09/22 16:12:54 jvanzyl Exp $
74 */
75 public class Launcher
76 {
77 // ------------------------------------------------------------
78 // Constants
79 // ------------------------------------------------------------
80
81 /*** Default config file name. */
82 private static final String CLASSWORLDS_CONF = "classworlds.conf";
83
84 /*** Default config dir name. */
85 private static final String UBERJAR_CONF_DIR = "WORLDS-INF/conf/";
86
87 // ------------------------------------------------------------
88 // Instance members
89 // ------------------------------------------------------------
90
91 /*** Main class name. */
92 private String mainClassName;
93
94 /*** Main realm name. */
95 private String mainRealmName;
96
97 /*** App's world. */
98 private ClassWorld world;
99
100 // ------------------------------------------------------------
101 // Constructors
102 // ------------------------------------------------------------
103
104 /*** Construct.
105 */
106 public Launcher()
107 {
108 // intentionally left blank
109 }
110
111 // ------------------------------------------------------------
112 // Instance methods
113 // ------------------------------------------------------------
114
115 /*** Set the application's main entrypoint.
116 *
117 * @param mainClassName The main class name.
118 * @param mainRealmName The realm to load the class from.
119 */
120 public void setAppMain(String mainClassName,
121 String mainRealmName)
122 {
123 this.mainClassName = mainClassName;
124 this.mainRealmName = mainRealmName;
125 }
126
127 /*** Retrieve the main entry realm name.
128 *
129 * @return The main entry realm name.
130 */
131 public String getMainRealmName()
132 {
133 return this.mainRealmName;
134 }
135
136 /*** Retrieve the main entry class name.
137 *
138 * @return The main entry class name.
139 */
140 public String getMainClassName()
141 {
142 return this.mainClassName;
143 }
144
145 /*** Set this launcher's <code>ClassWorld</code>.
146 *
147 * @param world The world.
148 */
149 public void setWorld(ClassWorld world)
150 {
151 this.world = world;
152 }
153
154 /*** Retrieve this launcher's <code>ClassWorld</code>.
155 *
156 * @return The world.
157 */
158 public ClassWorld getWorld()
159 {
160 return this.world;
161 }
162
163 /*** Configure from a file.
164 *
165 * @param is The config input stream.
166 *
167 * @throws IOException If an error occurs reading the config file.
168 * @throws MalformedURLException If the config file contains invalid URLs.
169 * @throws ConfigurationException If the config file is corrupt.
170 * @throws DuplicateRealmException If the config file defines two realms
171 * with the same id.
172 * @throws NoSuchRealmException If the config file defines a main entry
173 * point in a non-existent realm.
174 */
175 public void configure(InputStream is)
176 throws IOException, MalformedURLException, ConfigurationException,
177 DuplicateRealmException, NoSuchRealmException
178 {
179 Configurator configurator = new Configurator(this);
180
181 configurator.configure(is);
182 }
183
184 /*** Retrieve the main entry class.
185 *
186 * @return The main entry class.
187 *
188 * @throws ClassNotFoundException If the class cannot be found.
189 * @throws NoSuchRealmException If the specified main entry realm does not exist.
190 */
191 public Class getMainClass()
192 throws ClassNotFoundException, NoSuchRealmException
193 {
194 return getMainRealm().loadClass(getMainClassName());
195 }
196
197 /*** Retrieve the main entry realm.
198 *
199 * @return The main entry realm.
200 *
201 * @throws NoSuchRealmException If the specified main entry realm does not exist.
202 */
203 public ClassRealm getMainRealm()
204 throws NoSuchRealmException
205 {
206 return getWorld().getRealm(getMainRealmName());
207 }
208
209 /*** Retrieve the enhanced main entry method.
210 *
211 * @return The enhanced main entry method.
212 *
213 * @throws ClassNotFoundException If the main entry class cannot be found.
214 * @throws NoSuchMethodException If the main entry method cannot be found.
215 * @throws NoSuchRealmException If the main entry realm cannot be found.
216 */
217 protected Method getEnhancedMainMethod()
218 throws ClassNotFoundException, NoSuchMethodException, NoSuchRealmException
219 {
220 Method[] methods = getMainClass().getMethods();
221
222 for (int i = 0; i < methods.length; ++i)
223 {
224 final Method method = methods[i];
225
226 if (!"main".equals(method.getName()))
227 {
228 continue;
229 }
230
231 int modifiers = method.getModifiers();
232
233 if (!(Modifier.isStatic(modifiers)
234 &&
235 Modifier.isPublic(modifiers)))
236 {
237 continue;
238 }
239
240 if (method.getReturnType() != Void.TYPE)
241 {
242 continue;
243 }
244
245 Class[] paramTypes = method.getParameterTypes();
246
247 if (paramTypes.length != 2)
248 {
249 continue;
250 }
251
252 if (paramTypes[0] != String[].class)
253 {
254 continue;
255 }
256
257 if (paramTypes[1] != ClassWorld.class)
258 {
259 continue;
260 }
261
262 return method;
263 }
264
265 throw new NoSuchMethodException("public static void main(String[] args, ClassWorld world)");
266 }
267
268 /*** Retrieve the main entry method.
269 *
270 * @return The main entry method.
271 *
272 * @throws ClassNotFoundException If the main entry class cannot be found.
273 * @throws NoSuchMethodException If the main entry method cannot be found.
274 * @throws NoSuchRealmException If the main entry realm cannot be found.
275 */
276 protected Method getMainMethod()
277 throws ClassNotFoundException, NoSuchMethodException, NoSuchRealmException
278 {
279 Method[] methods = getMainClass().getMethods();
280
281 for (int i = 0; i < methods.length; ++i)
282 {
283 if (!"main".equals(methods[i].getName()))
284 {
285 continue;
286 }
287
288 int modifiers = methods[i].getModifiers();
289
290 if (!(Modifier.isStatic(modifiers)
291 &&
292 Modifier.isPublic(modifiers)))
293 {
294 continue;
295 }
296
297 if (methods[i].getReturnType() != Void.TYPE)
298 {
299 continue;
300 }
301
302 Class[] paramTypes = methods[i].getParameterTypes();
303
304 if (paramTypes.length != 1)
305 {
306 continue;
307 }
308
309 if (paramTypes[0] != String[].class)
310 {
311 continue;
312 }
313
314 return methods[i];
315 }
316
317 throw new NoSuchMethodException("public static void main(String[] args) in " + getMainClass() );
318 }
319
320 /*** Launch the application.
321 *
322 * @param args The application args.
323 *
324 * @throws ClassNotFoundException If the main entry class cannot be found.
325 * @throws IllegalAccessException If the method cannot be accessed.
326 * @throws InvocationTargetException If the target of the invokation is invalid.
327 * @throws NoSuchMethodException If the main entry method cannot be found.
328 * @throws NoSuchRealmException If the main entry realm cannot be found.
329 */
330 public void launch(String[] args)
331 throws ClassNotFoundException, IllegalAccessException,
332 InvocationTargetException, NoSuchMethodException, NoSuchRealmException
333 {
334 try
335 {
336 launchEnhanced(args);
337 return;
338 }
339 catch (NoSuchMethodException e)
340 {
341 // ignore
342 }
343
344 launchStandard(args);
345 }
346
347 /*** Attempt to launch the application through the enhanced main method.
348 *
349 * <p>
350 * This will seek a method with the exact signature of:
351 * </p>
352 *
353 * <pre>
354 * public static void main(String[] args, ClassWorld world)
355 * </pre>
356 *
357 * @param args The application args.
358 *
359 * @throws ClassNotFoundException If the main entry class cannot be found.
360 * @throws IllegalAccessException If the method cannot be accessed.
361 * @throws InvocationTargetException If the target of the invokation is
362 * invalid.
363 * @throws NoSuchMethodException If the main entry method cannot be found.
364 * @throws NoSuchRealmException If the main entry realm cannot be found.
365 */
366 protected void launchEnhanced(String[] args)
367 throws ClassNotFoundException, IllegalAccessException,
368 InvocationTargetException, NoSuchMethodException, NoSuchRealmException
369 {
370 ClassRealm mainRealm = getMainRealm();
371 Class mainClass = getMainClass();
372 Method mainMethod = getEnhancedMainMethod();
373
374 Thread.currentThread().setContextClassLoader(mainRealm.getClassLoader());
375
376 mainMethod.invoke(mainClass,
377 new Object[]{args,
378 getWorld()});
379 }
380
381 /*** Attempt to launch the application through the standard main method.
382 *
383 * <p>
384 * This will seek a method with the exact signature of:
385 * </p>
386 *
387 * <pre>
388 * public static void main(String[] args)
389 * </pre>
390 *
391 * @param args The application args.
392 *
393 * @throws ClassNotFoundException If the main entry class cannot be found.
394 * @throws IllegalAccessException If the method cannot be accessed.
395 * @throws InvocationTargetException If the target of the invokation is
396 * invalid.
397 * @throws NoSuchMethodException If the main entry method cannot be found.
398 * @throws NoSuchRealmException If the main entry realm cannot be found.
399 */
400 protected void launchStandard(String[] args)
401 throws ClassNotFoundException, IllegalAccessException,
402 InvocationTargetException, NoSuchMethodException, NoSuchRealmException
403 {
404 ClassRealm mainRealm = getMainRealm();
405 Class mainClass = getMainClass();
406 Method mainMethod = getMainMethod();
407
408 Thread.currentThread().setContextClassLoader(mainRealm.getClassLoader());
409
410 mainMethod.invoke( mainClass,
411 new Object[] { args } );
412 }
413
414 // ------------------------------------------------------------
415 // Class methods
416 // ------------------------------------------------------------
417
418 /*** Launch the launcher.
419 *
420 * @param args The application command-line arguments.
421 *
422 * @throws Exception If an error occurs.
423 */
424 public static void main(String[] args)
425 throws Exception
426 {
427 String classworldsConf = System.getProperty(CLASSWORLDS_CONF);
428
429 InputStream is = null;
430
431 Launcher launcher = new Launcher();
432
433 if ( classworldsConf != null )
434 {
435 is = new FileInputStream( classworldsConf );
436 }
437 else
438 {
439 ClassLoader cl = Thread.currentThread().getContextClassLoader();
440
441 if ( "true".equals( System.getProperty( "classworlds.bootstrapped" ) ) )
442 {
443 is = cl.getResourceAsStream( UBERJAR_CONF_DIR + CLASSWORLDS_CONF );
444 }
445 else
446 {
447 is = cl.getResourceAsStream(CLASSWORLDS_CONF);
448 }
449 }
450
451 if (is == null)
452 {
453 throw new Exception( "classworlds configuration not specified nor found "
454 + "in the classpath" );
455 }
456
457 launcher.configure( is );
458
459 try
460 {
461 launcher.launch(args);
462 }
463 catch (InvocationTargetException e)
464 {
465 // Decode ITE (if we can)
466 Throwable t = e.getTargetException();
467 if (t instanceof Exception)
468 {
469 throw (Exception)t;
470 }
471 if (t instanceof Error)
472 {
473 throw (Error)t;
474 }
475
476 // Else just toss the ITE
477 throw e;
478 }
479 }
480 }
This page was automatically generated by Maven