View Javadoc

1   package org.codehaus.classworlds;
2   
3   /*
4    $Id: EmbeddedLauncher.java,v 1.1.1.1 2004/07/01 13:59:19 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.FileInputStream;
50  import java.io.InputStream;
51  import java.lang.reflect.InvocationTargetException;
52  import java.lang.reflect.Method;
53  import java.lang.reflect.Modifier;
54  
55  /***
56   * Command-line invokable application launcher.
57   * <p/>
58   * <p/>
59   * This launcher class assists in the creation of classloaders and <code>ClassRealm</code>s
60   * from a configuration file and the launching of the application's <code>main</code>
61   * method from the correct class loaded through the correct classloader.
62   * </p>
63   * <p/>
64   * <p/>
65   * The path to the configuration file is specified using the <code>classworlds.conf</code>
66   * system property, typically specified using the <code>-D</code> switch to
67   * <code>java</code>.
68   * </p>
69   *
70   * @author <a href="mailto:bob@eng.werken.com">bob mcwhirter</a>
71   * @version $Id: EmbeddedLauncher.java,v 1.1.1.1 2004/07/01 13:59:19 jvanzyl Exp $
72   */
73  public class EmbeddedLauncher
74      extends Launcher
75  {
76      private static String LAUNCH_METHOD = "execute";
77  
78      public EmbeddedLauncher()
79      {
80          super();
81      }
82  
83      // ------------------------------------------------------------
84      //     Instance methods
85      // ------------------------------------------------------------
86  
87      /***
88       * Set the application's main entrypoint.
89       *
90       * @param mainClassName The main class name.
91       * @param mainRealmName The realm to load the class from.
92       */
93      public void setAppMain( String mainClassName,
94                              String mainRealmName )
95      {
96          this.mainClassName = mainClassName;
97          this.mainRealmName = mainRealmName;
98      }
99  
100     /***
101      * Retrieve the main entry realm name.
102      *
103      * @return The main entry realm name.
104      */
105     public String getMainRealmName()
106     {
107         return this.mainRealmName;
108     }
109 
110     /***
111      * Retrieve the main entry class name.
112      *
113      * @return The main entry class name.
114      */
115     public String getMainClassName()
116     {
117         return this.mainClassName;
118     }
119 
120     /***
121      * Retrieve the main entry class.
122      *
123      * @return The main entry class.
124      * @throws ClassNotFoundException If the class cannot be found.
125      * @throws NoSuchRealmException   If the specified main entry realm does not exist.
126      */
127     public Class getMainClass()
128         throws ClassNotFoundException, NoSuchRealmException
129     {
130         return getMainRealm().loadClass( getMainClassName() );
131     }
132 
133     /***
134      * Retrieve the main entry realm.
135      *
136      * @return The main entry realm.
137      * @throws NoSuchRealmException If the specified main entry realm does not exist.
138      */
139     public ClassRealm getMainRealm()
140         throws NoSuchRealmException
141     {
142         return getWorld().getRealm( getMainRealmName() );
143     }
144 
145     /***
146      * Retrieve the enhanced main entry method.
147      *
148      * @return The enhanced main entry method.
149      * @throws ClassNotFoundException If the main entry class cannot be found.
150      * @throws NoSuchMethodException  If the main entry method cannot be found.
151      * @throws NoSuchRealmException   If the main entry realm cannot be found.
152      */
153     protected Method getEnhancedMainMethod()
154         throws ClassNotFoundException, NoSuchMethodException, NoSuchRealmException
155     {
156         Method[] methods = getMainClass().getMethods();
157 
158         for ( int i = 0; i < methods.length; ++i )
159         {
160             final Method method = methods[i];
161 
162             if ( !LAUNCH_METHOD.equals( method.getName() ) )
163             {
164                 continue;
165             }
166 
167             int modifiers = method.getModifiers();
168 
169             if ( !( Modifier.isPublic( modifiers ) ) )
170             {
171                 continue;
172             }
173 
174             if ( method.getReturnType() != Void.TYPE )
175             {
176                 continue;
177             }
178 
179             Class[] paramTypes = method.getParameterTypes();
180 
181             if ( paramTypes.length != 2 )
182             {
183                 continue;
184             }
185 
186             if ( paramTypes[0] != String[].class )
187             {
188                 continue;
189             }
190 
191             if ( paramTypes[1] != ClassWorld.class )
192             {
193                 continue;
194             }
195 
196             return method;
197         }
198 
199         throw new NoSuchMethodException( "public void execute(ClassWorld world)" );
200     }
201 
202     /***
203      * Attempt to launch the application through the enhanced main method.
204      * <p/>
205      * <p/>
206      * This will seek a method with the exact signature of:
207      * </p>
208      * <p/>
209      * <pre>
210      *  public static void main(String[] args, ClassWorld world)
211      *  </pre>
212      *
213      * @throws ClassNotFoundException If the main entry class cannot be found.
214      * @throws IllegalAccessException If the method cannot be accessed.
215      * @throws java.lang.reflect.InvocationTargetException
216      *                                If the target of the invokation is
217      *                                invalid.
218      * @throws NoSuchMethodException  If the main entry method cannot be found.
219      * @throws NoSuchRealmException   If the main entry realm cannot be found.
220      */
221     protected void launchX()
222         throws ClassNotFoundException, IllegalAccessException,
223         InvocationTargetException, NoSuchMethodException, NoSuchRealmException
224     {
225         ClassRealm mainRealm = getMainRealm();
226         Class mainClass = getMainClass();
227         Method mainMethod = getEnhancedMainMethod();
228 
229         Thread.currentThread().setContextClassLoader( mainRealm.getClassLoader() );
230 
231         mainMethod.invoke( mainClass, new Object[]{getWorld()} );
232     }
233 
234     // ------------------------------------------------------------
235     //     Class methods
236     // ------------------------------------------------------------
237 
238     public void launch()
239         throws Exception
240     {
241         String classworldsConf = System.getProperty( CLASSWORLDS_CONF );
242 
243         InputStream is = null;
244 
245         if ( classworldsConf != null )
246         {
247             is = new FileInputStream( classworldsConf );
248         }
249         else
250         {
251             ClassLoader cl = Thread.currentThread().getContextClassLoader();
252 
253             if ( "true".equals( System.getProperty( "classworlds.bootstrapped" ) ) )
254             {
255                 is = cl.getResourceAsStream( UBERJAR_CONF_DIR + CLASSWORLDS_CONF );
256             }
257             else
258             {
259                 is = cl.getResourceAsStream( CLASSWORLDS_CONF );
260             }
261         }
262 
263         if ( is == null )
264         {
265             throw new Exception( "classworlds configuration not specified nor found "
266                                  + "in the classpath" );
267         }
268 
269         configure( is );
270 
271         try
272         {
273             launchX();
274         }
275         catch ( InvocationTargetException e )
276         {
277             // Decode ITE (if we can)
278             Throwable t = e.getTargetException();
279             if ( t instanceof Exception )
280             {
281                 throw (Exception) t;
282             }
283             if ( t instanceof Error )
284             {
285                 throw (Error) t;
286             }
287 
288             // Else just toss the ITE
289             throw e;
290         }
291     }
292 }