View Javadoc

1   //
2   //  ========================================================================
3   //  Copyright (c) 1995-2016 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   * <p>
33   * Default implementation of the BundleClassLoaderHelper. Uses introspection to
34   * support equinox-3.5 and felix-2.0.0
35   */
36  public class DefaultBundleClassLoaderHelper implements BundleClassLoaderHelper
37  {
38      private static final Logger LOG = Log.getLogger(BundleClassLoaderHelper.class);
39      private static enum OSGiContainerType {EquinoxOld, EquinoxLuna, FelixOld, Felix403, Concierge};
40      private static OSGiContainerType osgiContainer;
41      private static Class Equinox_BundleHost_Class;
42      private static Class Equinox_EquinoxBundle_Class;
43      private static Class Felix_BundleImpl_Class;
44      private static Class Felix_BundleWiring_Class;
45      //old equinox
46      private static Method Equinox_BundleHost_getBundleLoader_method;
47      private static Method Equinox_BundleLoader_createClassLoader_method;
48      //new equinox
49      private static Method Equinox_EquinoxBundle_getModuleClassLoader_Method;
50    
51      //new felix
52      private static Method Felix_BundleImpl_Adapt_Method;
53      //old felix
54      private static Field Felix_BundleImpl_m_Modules_Field;
55      private static Field Felix_ModuleImpl_m_ClassLoader_Field;
56      private static Method Felix_BundleWiring_getClassLoader_Method;
57      
58      // Concierge
59      private static Class Concierge_BundleImpl_Class;
60      private static Class Concierge_BundleWiring_Class;
61      private static Method Concierge_BundleImpl_Adapt_Method;
62      private static Method Concierge_BundleWiring_getClassLoader_Method;
63      
64      
65      private static void checkContainerType (Bundle bundle)
66      {
67          if (osgiContainer != null)
68              return;
69          
70          try
71          {
72              Equinox_BundleHost_Class = bundle.getClass().getClassLoader().loadClass("org.eclipse.osgi.framework.internal.core.BundleHost");
73              osgiContainer = OSGiContainerType.EquinoxOld;
74              return;
75          }
76          catch (ClassNotFoundException e)
77          {
78              LOG.ignore(e);
79          }
80  
81          try
82          {
83              Equinox_EquinoxBundle_Class = bundle.getClass().getClassLoader().loadClass("org.eclipse.osgi.internal.framework.EquinoxBundle");
84              osgiContainer = OSGiContainerType.EquinoxLuna;
85              return;
86          }
87          catch (ClassNotFoundException e)
88          {
89              LOG.ignore(e);
90          }
91          
92          try
93          {       
94              //old felix or new felix?
95              Felix_BundleImpl_Class = bundle.getClass().getClassLoader().loadClass("org.apache.felix.framework.BundleImpl");  
96              try
97              {
98                  Felix_BundleImpl_Adapt_Method = Felix_BundleImpl_Class.getDeclaredMethod("adapt", new Class[] {Class.class});
99                  osgiContainer = OSGiContainerType.Felix403;
100                 return;
101             }
102             catch (NoSuchMethodException e)
103             {
104                 osgiContainer = OSGiContainerType.FelixOld;
105                 return;
106             }
107         }
108         catch (ClassNotFoundException e)
109         {
110             LOG.ignore(e);
111         }
112         
113         try
114         {
115             Concierge_BundleImpl_Class = bundle.getClass().getClassLoader().loadClass("org.eclipse.concierge.BundleImpl");
116             osgiContainer = OSGiContainerType.Concierge;
117             return;
118         }
119         catch (ClassNotFoundException e)
120         {
121             LOG.ignore(e);
122         }
123 
124         LOG.warn("Unknown OSGi container type");
125         return;
126     }
127 
128   
129     
130     
131 
132     /**
133      * Assuming the bundle is started.
134      * 
135      * @param bundle the bundle
136      * @return classloader object
137      */
138     public ClassLoader getBundleClassLoader(Bundle bundle)
139     {
140         String bundleActivator = (String) bundle.getHeaders().get("Bundle-Activator");
141    
142         if (bundleActivator == null)
143         {
144             bundleActivator = (String) bundle.getHeaders().get("Jetty-ClassInBundle");
145         }
146         if (bundleActivator != null)
147         {
148             try
149             {
150                 return bundle.loadClass(bundleActivator).getClassLoader();
151             }
152             catch (ClassNotFoundException e)
153             {
154                 LOG.warn(e);
155             }
156         }
157         
158         // resort to introspection     
159         return getBundleClassLoaderForContainer(bundle);
160     }
161     
162     /**
163      * @param bundle
164      * @return
165      */
166     private ClassLoader getBundleClassLoaderForContainer (Bundle bundle)
167     {
168         checkContainerType (bundle);
169         if (osgiContainer == null)
170         {
171             LOG.warn("No classloader for unknown OSGi container type");
172             return null;
173         }
174         
175         switch (osgiContainer)
176         {
177             case EquinoxOld:
178             case EquinoxLuna:
179             {
180                 return internalGetEquinoxBundleClassLoader(bundle);
181             }
182 
183             case FelixOld:
184             case Felix403:
185             {
186                 return internalGetFelixBundleClassLoader(bundle); 
187             }
188 
189             case Concierge:
190             {
191                 return internalGetConciergeBundleClassLoader(bundle); 
192             }
193 
194             default:
195             {
196                 LOG.warn("No classloader found for bundle "+bundle.getSymbolicName());
197                 return null;
198 
199             }
200         }
201     }
202     
203     
204 
205     /**
206      * @param bundle
207      * @return
208      */
209     private static ClassLoader internalGetEquinoxBundleClassLoader(Bundle bundle)
210     {
211         if (osgiContainer == OSGiContainerType.EquinoxOld)
212         {
213             try
214             {
215                 if (Equinox_BundleHost_getBundleLoader_method == null)
216                 {
217                     Equinox_BundleHost_getBundleLoader_method = 
218                             Equinox_BundleHost_Class.getDeclaredMethod("getBundleLoader", new Class[] {});
219                     Equinox_BundleHost_getBundleLoader_method.setAccessible(true);
220                 }
221                 Object bundleLoader = Equinox_BundleHost_getBundleLoader_method.invoke(bundle, new Object[] {});
222                 if (Equinox_BundleLoader_createClassLoader_method == null && bundleLoader != null)
223                 {
224                     Equinox_BundleLoader_createClassLoader_method = 
225                             bundleLoader.getClass().getClassLoader().loadClass("org.eclipse.osgi.internal.loader.BundleLoader").getDeclaredMethod("createClassLoader", new Class[] {});
226                     Equinox_BundleLoader_createClassLoader_method.setAccessible(true);
227                 }
228                 return (ClassLoader) Equinox_BundleLoader_createClassLoader_method.invoke(bundleLoader, new Object[] {});
229             }
230             catch (ClassNotFoundException t)
231             {
232                 LOG.warn(t);
233                 return null;
234             }
235             catch (Throwable t)
236             {
237                 LOG.warn(t);
238                 return null;
239             }
240         }
241         
242         if (osgiContainer == OSGiContainerType.EquinoxLuna)
243         {
244             try
245             {
246                 if (Equinox_EquinoxBundle_getModuleClassLoader_Method == null)
247                     Equinox_EquinoxBundle_getModuleClassLoader_Method = Equinox_EquinoxBundle_Class.getDeclaredMethod("getModuleClassLoader", new Class[] {Boolean.TYPE});
248 
249                 Equinox_EquinoxBundle_getModuleClassLoader_Method.setAccessible(true);
250                 return (ClassLoader)Equinox_EquinoxBundle_getModuleClassLoader_Method.invoke(bundle, new Object[] {Boolean.FALSE});
251             }
252             catch (Exception e)
253             {
254                 LOG.warn(e);
255                 return null;
256             }
257         }
258         
259         LOG.warn("No classloader for equinox platform for bundle "+bundle.getSymbolicName());
260         return null;
261     }
262 
263    
264 
265 
266     /**
267      * @param bundle
268      * @return
269      */
270     private static ClassLoader internalGetFelixBundleClassLoader(Bundle bundle)
271     {
272         
273         if (osgiContainer == OSGiContainerType.Felix403)
274         {
275             try
276             {
277                 if (Felix_BundleWiring_Class == null)
278                     Felix_BundleWiring_Class = bundle.getClass().getClassLoader().loadClass("org.osgi.framework.wiring.BundleWiring");
279 
280 
281                 Felix_BundleImpl_Adapt_Method.setAccessible(true);
282 
283                 if (Felix_BundleWiring_getClassLoader_Method == null)
284                 {
285                     Felix_BundleWiring_getClassLoader_Method = Felix_BundleWiring_Class.getDeclaredMethod("getClassLoader");
286                     Felix_BundleWiring_getClassLoader_Method.setAccessible(true);
287                 }
288 
289 
290                 Object wiring = Felix_BundleImpl_Adapt_Method.invoke(bundle, new Object[] {Felix_BundleWiring_Class});
291                 return (ClassLoader)Felix_BundleWiring_getClassLoader_Method.invoke(wiring);
292             }
293             catch (Exception e)
294             {
295                 LOG.warn(e);
296                 return null;
297             }
298         }
299 
300 
301         if (osgiContainer == OSGiContainerType.FelixOld)
302         {     
303             try
304             {
305                 if (Felix_BundleImpl_m_Modules_Field == null)
306                 {
307                     Felix_BundleImpl_m_Modules_Field = Felix_BundleImpl_Class.getDeclaredField("m_modules");
308                     Felix_BundleImpl_m_Modules_Field.setAccessible(true);
309                 }
310 
311                 // Figure out which version of the modules is exported
312                 Object currentModuleImpl;
313 
314                 try
315                 {
316                     Object[] moduleArray = (Object[]) Felix_BundleImpl_m_Modules_Field.get(bundle);
317                     currentModuleImpl = moduleArray[moduleArray.length - 1];
318                 }
319                 catch (Throwable t2)
320                 {
321                     try
322                     {
323                         List<Object> moduleArray = (List<Object>) Felix_BundleImpl_m_Modules_Field.get(bundle);
324                         currentModuleImpl = moduleArray.get(moduleArray.size() - 1);
325                     }
326                     catch (Exception e)
327                     {
328                         LOG.warn(e);
329                         return null;
330                     }
331                 }
332 
333                 if (Felix_ModuleImpl_m_ClassLoader_Field == null && currentModuleImpl != null)
334                 {
335                     try
336                     {
337                         Felix_ModuleImpl_m_ClassLoader_Field = bundle.getClass().getClassLoader().loadClass("org.apache.felix.framework.ModuleImpl").getDeclaredField("m_classLoader");
338                         Felix_ModuleImpl_m_ClassLoader_Field.setAccessible(true);
339                     }
340                     catch (Exception e)
341                     {
342                         LOG.warn(e);
343                         return null;
344                     }
345                 }
346 
347                 // first make sure that the classloader is ready:
348                 // the m_classLoader field must be initialized by the
349                 // ModuleImpl.getClassLoader() private method.
350                 ClassLoader cl = null;
351                 try
352                 {
353                     cl = (ClassLoader) Felix_ModuleImpl_m_ClassLoader_Field.get(currentModuleImpl);
354                     if (cl != null)
355                         return cl;
356                 }
357                 catch (Exception e)
358                 {
359                     LOG.warn(e);
360                     return null;
361                 }
362 
363                 // looks like it was not ready:
364                 // the m_classLoader field must be initialized by the
365                 // ModuleImpl.getClassLoader() private method.
366                 // this call will do that.
367                 try
368                 {
369                     bundle.loadClass("java.lang.Object");
370                     cl = (ClassLoader) Felix_ModuleImpl_m_ClassLoader_Field.get(currentModuleImpl);
371                     return cl;
372                 }
373                 catch (Exception e)
374                 {
375                     LOG.warn(e);
376                     return null;
377                 }
378             }  
379             catch (Exception e)
380             {
381                 LOG.warn(e);
382                 return null;
383             }
384         }
385         
386         LOG.warn("No classloader for felix platform for bundle "+bundle.getSymbolicName());
387         return null;
388     }
389     
390     /**
391      * @param bundle
392      * @return
393      */
394     private static ClassLoader internalGetConciergeBundleClassLoader(Bundle bundle)
395     {
396         if (osgiContainer == OSGiContainerType.Concierge)
397         {
398             try
399             {
400                 /** 
401                  * In Concierge:
402                  * 
403                  * Option A:
404                  * <pre>
405                  * Concierge concierge = new Concierge(...);
406                  * BundleWiring bundleWiring = concierge.getWiring(); // method is public
407                  * </pre>
408                  * Problem: getWiring not yet implementd
409                  * 
410                  * Option B:
411                  * <pre>
412                  * Concierge concierge = new Concierge(...);
413                  * BundleWiring bundleWiring = concierge.adapt(org.osgi.framework.wiring.BundleWiring);
414                  * </pre>
415                  * Same approach as done in Felix.
416                  * 
417                  */
418                 if (Concierge_BundleWiring_Class == null) {
419                     Concierge_BundleWiring_Class = bundle.getClass().getClassLoader().loadClass("org.osgi.framework.wiring.BundleWiring");
420                     Concierge_BundleImpl_Adapt_Method = Concierge_BundleImpl_Class.getMethod("adapt", new Class[] {Class.class});
421                     Concierge_BundleImpl_Adapt_Method.setAccessible(true);
422                     Concierge_BundleWiring_getClassLoader_Method = Concierge_BundleWiring_Class.getMethod("getClassLoader");
423                     Concierge_BundleWiring_getClassLoader_Method.setAccessible(true);
424                 }
425 
426                 Object wiring = Concierge_BundleImpl_Adapt_Method.invoke(bundle, new Object[] {Concierge_BundleWiring_Class});
427                 ClassLoader cl = (ClassLoader)Concierge_BundleWiring_getClassLoader_Method.invoke(wiring);
428                 return cl;
429             }
430             catch (Exception e)
431             {
432                 LOG.warn(e);
433                 return null;
434             }
435         }
436 
437         LOG.warn("No classloader for Concierge platform for bundle "+bundle.getSymbolicName());
438         return null;
439     }
440 }