View Javadoc

1   //
2   //  ========================================================================
3   //  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
4   //  ------------------------------------------------------------------------
5   //  All rights reserved. This program and the accompanying materials
6   //  are made available under the terms of the Eclipse Public License v1.0
7   //  and Apache License v2.0 which accompanies this distribution.
8   //
9   //      The Eclipse Public License is available at
10  //      http://www.eclipse.org/legal/epl-v10.html
11  //
12  //      The Apache License v2.0 is available at
13  //      http://www.opensource.org/licenses/apache2.0.php
14  //
15  //  You may elect to redistribute this code under either of these licenses.
16  //  ========================================================================
17  //
18  
19  package org.eclipse.jetty.osgi.boot.utils.internal;
20  
21  import java.lang.reflect.Field;
22  import java.lang.reflect.Method;
23  import java.util.List;
24  
25  import org.eclipse.jetty.osgi.boot.utils.BundleClassLoaderHelper;
26  import org.eclipse.jetty.util.log.Log;
27  import org.eclipse.jetty.util.log.Logger;
28  import org.osgi.framework.Bundle;
29  
30  /**
31   * DefaultBundleClassLoaderHelper
32   * 
33   * 
34   * Default implementation of the BundleClassLoaderHelper. Uses introspection to
35   * support equinox-3.5 and felix-2.0.0
36   */
37  public class DefaultBundleClassLoaderHelper implements BundleClassLoaderHelper
38  {
39      private static final Logger LOG = Log.getLogger(BundleClassLoaderHelper.class);
40      private static enum OSGiContainerType {EquinoxOld, EquinoxLuna, FelixOld, Felix403};
41      private static OSGiContainerType osgiContainer;
42      private static Class Equinox_BundleHost_Class;
43      private static Class Equinox_EquinoxBundle_Class;
44      private static Class Felix_BundleImpl_Class;
45      private static Class Felix_BundleWiring_Class;
46      //old equinox
47      private static Method Equinox_BundleHost_getBundleLoader_method;
48      private static Method Equinox_BundleLoader_createClassLoader_method;
49      //new equinox
50      private static Method Equinox_EquinoxBundle_getModuleClassLoader_Method;
51    
52      //new felix
53      private static Method Felix_BundleImpl_Adapt_Method;
54      //old felix
55      private static Field Felix_BundleImpl_m_Modules_Field;
56      private static Field Felix_ModuleImpl_m_ClassLoader_Field;
57      private static Method Felix_BundleWiring_getClassLoader_Method;
58      
59      
60      private static void checkContainerType (Bundle bundle)
61      {
62          if (osgiContainer != null)
63              return;
64          
65          try
66          {
67              Equinox_BundleHost_Class = bundle.getClass().getClassLoader().loadClass("org.eclipse.osgi.framework.internal.core.BundleHost");
68              osgiContainer = OSGiContainerType.EquinoxOld;
69              return;
70          }
71          catch (ClassNotFoundException e)
72          {
73              LOG.ignore(e);
74          }
75  
76          try
77          {
78              Equinox_EquinoxBundle_Class = bundle.getClass().getClassLoader().loadClass("org.eclipse.osgi.internal.framework.EquinoxBundle");
79              osgiContainer = OSGiContainerType.EquinoxLuna;
80              return;
81          }
82          catch (ClassNotFoundException e)
83          {
84              LOG.ignore(e);
85          }
86          
87          try
88          {       
89              //old felix or new felix?
90              Felix_BundleImpl_Class = bundle.getClass().getClassLoader().loadClass("org.apache.felix.framework.BundleImpl");  
91              try
92              {
93                  Felix_BundleImpl_Adapt_Method = Felix_BundleImpl_Class.getDeclaredMethod("adapt", new Class[] {Class.class});
94                  osgiContainer = OSGiContainerType.Felix403;
95                  return;
96              }
97              catch (NoSuchMethodException e)
98              {
99                  osgiContainer = OSGiContainerType.FelixOld;
100                 return;
101             }
102         }
103         catch (ClassNotFoundException e)
104         {
105             LOG.warn("Unknown OSGi container type");
106             return;
107         }
108         
109     }
110 
111   
112     
113     
114 
115     /**
116      * Assuming the bundle is started.
117      * 
118      * @param bundle
119      * @return classloader object
120      */
121     public ClassLoader getBundleClassLoader(Bundle bundle)
122     {
123         String bundleActivator = (String) bundle.getHeaders().get("Bundle-Activator");
124    
125         if (bundleActivator == null)
126         {
127             bundleActivator = (String) bundle.getHeaders().get("Jetty-ClassInBundle");
128         }
129         if (bundleActivator != null)
130         {
131             try
132             {
133                 return bundle.loadClass(bundleActivator).getClassLoader();
134             }
135             catch (ClassNotFoundException e)
136             {
137                 LOG.warn(e);
138             }
139         }
140         
141         // resort to introspection     
142         return getBundleClassLoaderForContainer(bundle);
143     }
144     
145     /**
146      * @param bundle
147      * @return
148      */
149     private ClassLoader getBundleClassLoaderForContainer (Bundle bundle)
150     {
151         checkContainerType (bundle);
152         if (osgiContainer == null)
153         {
154             LOG.warn("No classloader for unknown OSGi container type");
155             return null;
156         }
157         
158         switch (osgiContainer)
159         {
160             case EquinoxOld:
161             case EquinoxLuna:
162             {
163                 return internalGetEquinoxBundleClassLoader(bundle);
164             }
165 
166             case FelixOld:
167             case Felix403:
168             {
169                 return internalGetFelixBundleClassLoader(bundle); 
170             }
171             default:
172             {
173                 LOG.warn("No classloader found for bundle "+bundle.getSymbolicName());
174                 return null;
175 
176             }
177         }
178     }
179     
180     
181 
182     /**
183      * @param bundle
184      * @return
185      */
186     private static ClassLoader internalGetEquinoxBundleClassLoader(Bundle bundle)
187     {
188         if (osgiContainer == OSGiContainerType.EquinoxOld)
189         {
190             try
191             {
192                 if (Equinox_BundleHost_getBundleLoader_method == null)
193                 {
194                     Equinox_BundleHost_getBundleLoader_method = 
195                             Equinox_BundleHost_Class.getDeclaredMethod("getBundleLoader", new Class[] {});
196                     Equinox_BundleHost_getBundleLoader_method.setAccessible(true);
197                 }
198                 Object bundleLoader = Equinox_BundleHost_getBundleLoader_method.invoke(bundle, new Object[] {});
199                 if (Equinox_BundleLoader_createClassLoader_method == null && bundleLoader != null)
200                 {
201                     Equinox_BundleLoader_createClassLoader_method = 
202                             bundleLoader.getClass().getClassLoader().loadClass("org.eclipse.osgi.internal.loader.BundleLoader").getDeclaredMethod("createClassLoader", new Class[] {});
203                     Equinox_BundleLoader_createClassLoader_method.setAccessible(true);
204                 }
205                 return (ClassLoader) Equinox_BundleLoader_createClassLoader_method.invoke(bundleLoader, new Object[] {});
206             }
207             catch (ClassNotFoundException t)
208             {
209                 LOG.warn(t);
210                 return null;
211             }
212             catch (Throwable t)
213             {
214                 LOG.warn(t);
215                 return null;
216             }
217         }
218         
219         if (osgiContainer == OSGiContainerType.EquinoxLuna)
220         {
221             try
222             {
223                 if (Equinox_EquinoxBundle_getModuleClassLoader_Method == null)
224                     Equinox_EquinoxBundle_getModuleClassLoader_Method = Equinox_EquinoxBundle_Class.getDeclaredMethod("getModuleClassLoader", new Class[] {Boolean.TYPE});
225 
226                 Equinox_EquinoxBundle_getModuleClassLoader_Method.setAccessible(true);
227                 return (ClassLoader)Equinox_EquinoxBundle_getModuleClassLoader_Method.invoke(bundle, new Object[] {Boolean.FALSE});
228             }
229             catch (Exception e)
230             {
231                 LOG.warn(e);
232                 return null;
233             }
234         }
235         
236         LOG.warn("No classloader for equinox platform for bundle "+bundle.getSymbolicName());
237         return null;
238     }
239 
240    
241 
242 
243     /**
244      * @param bundle
245      * @return
246      */
247     private static ClassLoader internalGetFelixBundleClassLoader(Bundle bundle)
248     {
249         
250         if (osgiContainer == OSGiContainerType.Felix403)
251         {
252             try
253             {
254                 if (Felix_BundleWiring_Class == null)
255                     Felix_BundleWiring_Class = bundle.getClass().getClassLoader().loadClass("org.osgi.framework.wiring.BundleWiring");
256 
257 
258                 Felix_BundleImpl_Adapt_Method.setAccessible(true);
259 
260                 if (Felix_BundleWiring_getClassLoader_Method == null)
261                 {
262                     Felix_BundleWiring_getClassLoader_Method = Felix_BundleWiring_Class.getDeclaredMethod("getClassLoader");
263                     Felix_BundleWiring_getClassLoader_Method.setAccessible(true);
264                 }
265 
266 
267                 Object wiring = Felix_BundleImpl_Adapt_Method.invoke(bundle, new Object[] {Felix_BundleWiring_Class});
268                 return (ClassLoader)Felix_BundleWiring_getClassLoader_Method.invoke(wiring);
269             }
270             catch (Exception e)
271             {
272                 LOG.warn(e);
273                 return null;
274             }
275         }
276 
277 
278         if (osgiContainer == OSGiContainerType.FelixOld)
279         {     
280             try
281             {
282                 if (Felix_BundleImpl_m_Modules_Field == null)
283                 {
284                     Felix_BundleImpl_m_Modules_Field = Felix_BundleImpl_Class.getDeclaredField("m_modules");
285                     Felix_BundleImpl_m_Modules_Field.setAccessible(true);
286                 }
287 
288                 // Figure out which version of the modules is exported
289                 Object currentModuleImpl;
290 
291                 try
292                 {
293                     Object[] moduleArray = (Object[]) Felix_BundleImpl_m_Modules_Field.get(bundle);
294                     currentModuleImpl = moduleArray[moduleArray.length - 1];
295                 }
296                 catch (Throwable t2)
297                 {
298                     try
299                     {
300                         List<Object> moduleArray = (List<Object>) Felix_BundleImpl_m_Modules_Field.get(bundle);
301                         currentModuleImpl = moduleArray.get(moduleArray.size() - 1);
302                     }
303                     catch (Exception e)
304                     {
305                         LOG.warn(e);
306                         return null;
307                     }
308                 }
309 
310                 if (Felix_ModuleImpl_m_ClassLoader_Field == null && currentModuleImpl != null)
311                 {
312                     try
313                     {
314                         Felix_ModuleImpl_m_ClassLoader_Field = bundle.getClass().getClassLoader().loadClass("org.apache.felix.framework.ModuleImpl").getDeclaredField("m_classLoader");
315                         Felix_ModuleImpl_m_ClassLoader_Field.setAccessible(true);
316                     }
317                     catch (Exception e)
318                     {
319                         LOG.warn(e);
320                         return null;
321                     }
322                 }
323 
324                 // first make sure that the classloader is ready:
325                 // the m_classLoader field must be initialized by the
326                 // ModuleImpl.getClassLoader() private method.
327                 ClassLoader cl = null;
328                 try
329                 {
330                     cl = (ClassLoader) Felix_ModuleImpl_m_ClassLoader_Field.get(currentModuleImpl);
331                     if (cl != null)
332                         return cl;
333                 }
334                 catch (Exception e)
335                 {
336                     LOG.warn(e);
337                     return null;
338                 }
339 
340                 // looks like it was not ready:
341                 // the m_classLoader field must be initialized by the
342                 // ModuleImpl.getClassLoader() private method.
343                 // this call will do that.
344                 try
345                 {
346                     bundle.loadClass("java.lang.Object");
347                     cl = (ClassLoader) Felix_ModuleImpl_m_ClassLoader_Field.get(currentModuleImpl);
348                     return cl;
349                 }
350                 catch (Exception e)
351                 {
352                     LOG.warn(e);
353                     return null;
354                 }
355             }  
356             catch (Exception e)
357             {
358                 LOG.warn(e);
359                 return null;
360             }
361         }
362         
363         LOG.warn("No classloader for felix platform for bundle "+bundle.getSymbolicName());
364         return null;
365     }
366 }