1 package org.codehaus.classworlds;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
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 import java.net.URL;
57
58 /***
59 * Command-line invokable application launcher.
60 * <p/>
61 * <p/>
62 * This launcher class assists in the creation of classloaders and <code>ClassRealm</code>s
63 * from a configuration file and the launching of the application's <code>main</code>
64 * method from the correct class loaded through the correct classloader.
65 * </p>
66 * <p/>
67 * <p/>
68 * The path to the configuration file is specified using the <code>classworlds.conf</code>
69 * system property, typically specified using the <code>-D</code> switch to
70 * <code>java</code>.
71 * </p>
72 *
73 * @author <a href="mailto:bob@eng.werken.com">bob mcwhirter</a>
74 * @version $Id: Launcher.java,v 1.5 2004/09/19 17:41:44 dandiep Exp $
75 */
76 public class Launcher
77 {
78 protected static final String CLASSWORLDS_CONF = "classworlds.conf";
79
80 protected static final String UBERJAR_CONF_DIR = "WORLDS-INF/conf/";
81
82 protected String mainClassName;
83
84 protected String mainRealmName;
85
86 protected ClassWorld world;
87
88 private int exitCode = 0;
89
90 public Launcher()
91 {
92 }
93
94 public int getExitCode()
95 {
96 return exitCode;
97 }
98
99 public void setAppMain( String mainClassName, String mainRealmName )
100 {
101 this.mainClassName = mainClassName;
102
103 this.mainRealmName = mainRealmName;
104 }
105
106 public String getMainRealmName()
107 {
108 return this.mainRealmName;
109 }
110
111 public String getMainClassName()
112 {
113 return this.mainClassName;
114 }
115
116 public void setWorld( ClassWorld world )
117 {
118 this.world = world;
119 }
120
121 public ClassWorld getWorld()
122 {
123 return this.world;
124 }
125
126 /***
127 * Configure from a file.
128 *
129 * @param is The config input stream.
130 * @throws IOException If an error occurs reading the config file.
131 * @throws MalformedURLException If the config file contains invalid URLs.
132 * @throws ConfigurationException If the config file is corrupt.
133 * @throws DuplicateRealmException If the config file defines two realms
134 * with the same id.
135 * @throws NoSuchRealmException If the config file defines a main entry
136 * point in a non-existent realm.
137 */
138 public void configure( InputStream is )
139 throws IOException, MalformedURLException, ConfigurationException,
140 DuplicateRealmException, NoSuchRealmException
141 {
142 Configurator configurator = new Configurator( this );
143
144 configurator.configure( is );
145 }
146
147 /***
148 * Retrieve the main entry class.
149 *
150 * @return The main entry class.
151 * @throws ClassNotFoundException If the class cannot be found.
152 * @throws NoSuchRealmException If the specified main entry realm does not exist.
153 */
154 public Class getMainClass()
155 throws ClassNotFoundException, NoSuchRealmException
156 {
157 return getMainRealm().loadClass( getMainClassName() );
158 }
159
160 /***
161 * Retrieve the main entry realm.
162 *
163 * @return The main entry realm.
164 * @throws NoSuchRealmException If the specified main entry realm does not exist.
165 */
166 public ClassRealm getMainRealm()
167 throws NoSuchRealmException
168 {
169 return getWorld().getRealm( getMainRealmName() );
170 }
171
172 /***
173 * Retrieve the enhanced main entry method.
174 *
175 * @return The enhanced main entry method.
176 * @throws ClassNotFoundException If the main entry class cannot be found.
177 * @throws NoSuchMethodException If the main entry method cannot be found.
178 * @throws NoSuchRealmException If the main entry realm cannot be found.
179 */
180 protected Method getEnhancedMainMethod()
181 throws ClassNotFoundException, NoSuchMethodException, NoSuchRealmException
182 {
183 Method[] methods = getMainClass().getMethods();
184 Class cwClass = getMainRealm().loadClass( ClassWorld.class.getName() );
185
186 Method m = getMainClass().getMethod( "main", new Class[] { String[].class, cwClass } );
187
188 int modifiers = m.getModifiers();
189
190 if ( Modifier.isStatic( modifiers ) && Modifier.isPublic( modifiers ) )
191 {
192 if ( m.getReturnType() == Integer.TYPE || m.getReturnType() == Void.TYPE )
193 {
194 return m;
195 }
196 }
197
198 throw new NoSuchMethodException( "public static void main(String[] args, ClassWorld world)" );
199 }
200
201 /***
202 * Retrieve the main entry method.
203 *
204 * @return The main entry method.
205 * @throws ClassNotFoundException If the main entry class cannot be found.
206 * @throws NoSuchMethodException If the main entry method cannot be found.
207 * @throws NoSuchRealmException If the main entry realm cannot be found.
208 */
209 protected Method getMainMethod()
210 throws ClassNotFoundException, NoSuchMethodException, NoSuchRealmException
211 {
212 Method m = getMainClass().getMethod( "main", new Class[] { String[].class } );
213
214 int modifiers = m.getModifiers();
215
216 if ( Modifier.isStatic( modifiers ) && Modifier.isPublic( modifiers ) )
217 {
218 if ( m.getReturnType() == Integer.TYPE || m.getReturnType() == Void.TYPE )
219 {
220 return m;
221 }
222 }
223
224 throw new NoSuchMethodException( "public static void main(String[] args) in " + getMainClass() );
225 }
226
227 /***
228 * Launch the application.
229 *
230 * @param args The application args.
231 * @throws ClassNotFoundException If the main entry class cannot be found.
232 * @throws IllegalAccessException If the method cannot be accessed.
233 * @throws InvocationTargetException If the target of the invokation is invalid.
234 * @throws NoSuchMethodException If the main entry method cannot be found.
235 * @throws NoSuchRealmException If the main entry realm cannot be found.
236 */
237 public void launch( String[] args )
238 throws ClassNotFoundException, IllegalAccessException,
239 InvocationTargetException, NoSuchMethodException, NoSuchRealmException
240 {
241 try
242 {
243 launchEnhanced( args );
244
245 return;
246 }
247 catch ( NoSuchMethodException e )
248 {
249
250 }
251
252 launchStandard( args );
253 }
254
255 /***
256 * Attempt to launch the application through the enhanced main method.
257 * <p/>
258 * <p/>
259 * This will seek a method with the exact signature of:
260 * </p>
261 * <p/>
262 * <pre>
263 * public static void main(String[] args, ClassWorld world)
264 * </pre>
265 *
266 * @param args The application args.
267 * @throws ClassNotFoundException If the main entry class cannot be found.
268 * @throws IllegalAccessException If the method cannot be accessed.
269 * @throws InvocationTargetException If the target of the invokation is
270 * invalid.
271 * @throws NoSuchMethodException If the main entry method cannot be found.
272 * @throws NoSuchRealmException If the main entry realm cannot be found.
273 */
274 protected void launchEnhanced( String[] args )
275 throws ClassNotFoundException, IllegalAccessException,
276 InvocationTargetException, NoSuchMethodException, NoSuchRealmException
277 {
278 ClassRealm mainRealm = getMainRealm();
279
280 Class mainClass = getMainClass();
281
282 Method mainMethod = getEnhancedMainMethod();
283
284 ClassLoader cl = mainRealm.getClassLoader();
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329 protected void launchStandard( String[] args )
330 throws ClassNotFoundException, IllegalAccessException,
331 InvocationTargetException, NoSuchMethodException, NoSuchRealmException
332 {
333 ClassRealm mainRealm = getMainRealm();
334
335 Class mainClass = getMainClass();
336
337 Method mainMethod = getMainMethod();
338
339 Thread.currentThread().setContextClassLoader( mainRealm.getClassLoader() );
340
341 Object ret = mainMethod.invoke( mainClass, new Object[]{args} );
342 if ( ret instanceof Integer )
343 {
344 exitCode = ( ( Integer ) ret ).intValue();
345 }
346 }
347
348
349
350
351
352 /***
353 * Launch the launcher from the command line.
354 * Will exit using System.exit with an exit code of 0 for success, 100 if there was an unknown exception,
355 * or some other code for an application error.
356 *
357 * @param args The application command-line arguments.
358 */
359 public static void main( String[] args )
360 {
361 try
362 {
363 int exitCode = mainWithExitCode( args );
364 System.exit( exitCode );
365 }
366 catch ( Exception e )
367 {
368 e.printStackTrace();
369 System.exit( 100 );
370 }
371 }
372
373 /***
374 * Launch the launcher.
375 *
376 * @param args The application command-line arguments.
377 * @return an integer exit code
378 * @throws Exception If an error occurs.
379 */
380 public static int mainWithExitCode( String[] args )
381 throws Exception
382 {
383 String classworldsConf = System.getProperty( CLASSWORLDS_CONF );
384
385 InputStream is = null;
386
387 Launcher launcher = new Launcher();
388
389 if ( classworldsConf != null )
390 {
391 is = new FileInputStream( classworldsConf );
392 }
393 else
394 {
395 ClassLoader cl = Thread.currentThread().getContextClassLoader();
396
397 if ( "true".equals( System.getProperty( "classworlds.bootstrapped" ) ) )
398 {
399 is = cl.getResourceAsStream( UBERJAR_CONF_DIR + CLASSWORLDS_CONF );
400 }
401 else
402 {
403 is = cl.getResourceAsStream( CLASSWORLDS_CONF );
404 }
405 }
406
407 if ( is == null )
408 {
409 throw new Exception( "classworlds configuration not specified nor found in the classpath" );
410 }
411
412 launcher.configure( is );
413
414 try
415 {
416 launcher.launch( args );
417 }
418 catch ( InvocationTargetException e )
419 {
420 ClassRealm realm = launcher.getWorld().getRealm( launcher.getMainRealmName() );
421
422 URL[] constituents = realm.getConstituents();
423
424 System.out.println( "---------------------------------------------------" );
425
426 for ( int i = 0; i < constituents.length; i++ )
427 {
428 System.out.println( "constituent[" + i + "]: " + constituents[i] );
429 }
430
431 System.out.println( "---------------------------------------------------" );
432
433
434 Throwable t = e.getTargetException();
435
436 if ( t instanceof Exception )
437 {
438 throw (Exception) t;
439 }
440 if ( t instanceof Error )
441 {
442 throw (Error) t;
443 }
444
445
446 throw e;
447 }
448
449 return launcher.getExitCode();
450 }
451 }