View Javadoc

1   //
2   //  ========================================================================
3   //  Copyright (c) 1995-2013 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      
41      private static boolean identifiedOsgiImpl = false;
42  
43      private static boolean isEquinox = false;
44  
45      private static boolean isFelix = false;
46  
47      private static void init(Bundle bundle)
48      {
49          identifiedOsgiImpl = true;
50          try
51          {
52              isEquinox = bundle.getClass().getClassLoader().loadClass("org.eclipse.osgi.framework.internal.core.BundleHost") != null;
53          }
54          catch (Throwable t)
55          {
56              isEquinox = false;
57          }
58          if (!isEquinox)
59          {
60              try
61              {
62                  isFelix = bundle.getClass().getClassLoader().loadClass("org.apache.felix.framework.BundleImpl") != null;  
63              }
64              catch (Throwable t2)
65              {
66                  isFelix = false;
67              }
68          }
69      }
70  
71      /**
72       * Assuming the bundle is started.
73       * 
74       * @param bundle
75       * @return classloader object
76       */
77      public ClassLoader getBundleClassLoader(Bundle bundle)
78      {
79          String bundleActivator = (String) bundle.getHeaders().get("Bundle-Activator");
80         
81          if (bundleActivator == null)
82          {
83              bundleActivator = (String) bundle.getHeaders().get("Jetty-ClassInBundle");
84          }
85          if (bundleActivator != null)
86          {
87              try
88              {
89                  return bundle.loadClass(bundleActivator).getClassLoader();
90              }
91              catch (ClassNotFoundException e)
92              {
93                  LOG.warn(e);
94              }
95          }
96          // resort to introspection
97          if (!identifiedOsgiImpl)
98          {
99              init(bundle);
100         }
101         if (isEquinox)
102         {
103             return internalGetEquinoxBundleClassLoader(bundle);
104         }
105         else if (isFelix) 
106         { 
107             return internalGetFelixBundleClassLoader(bundle); 
108         }
109         
110         LOG.warn("No classloader found for bundle "+bundle.getSymbolicName());
111         return null;
112     }
113 
114     private static Method Equinox_BundleHost_getBundleLoader_method;
115 
116     private static Method Equinox_BundleLoader_createClassLoader_method;
117 
118     private static ClassLoader internalGetEquinoxBundleClassLoader(Bundle bundle)
119     {
120         // assume equinox:
121         try
122         {
123             if (Equinox_BundleHost_getBundleLoader_method == null)
124             {
125                 Equinox_BundleHost_getBundleLoader_method = 
126                     bundle.getClass().getClassLoader().loadClass("org.eclipse.osgi.framework.internal.core.BundleHost").getDeclaredMethod("getBundleLoader", new Class[] {});
127                 Equinox_BundleHost_getBundleLoader_method.setAccessible(true);
128             }
129             Object bundleLoader = Equinox_BundleHost_getBundleLoader_method.invoke(bundle, new Object[] {});
130             if (Equinox_BundleLoader_createClassLoader_method == null && bundleLoader != null)
131             {
132                 Equinox_BundleLoader_createClassLoader_method = 
133                     bundleLoader.getClass().getClassLoader().loadClass("org.eclipse.osgi.internal.loader.BundleLoader").getDeclaredMethod("createClassLoader", new Class[] {});
134                 Equinox_BundleLoader_createClassLoader_method.setAccessible(true);
135             }
136             return (ClassLoader) Equinox_BundleLoader_createClassLoader_method.invoke(bundleLoader, new Object[] {});
137         }
138         catch (Throwable t)
139         {
140             LOG.warn(t);
141         }
142         LOG.warn("No classloader for equinox platform for bundle "+bundle.getSymbolicName());
143         return null;
144     }
145 
146     private static Field Felix_BundleImpl_m_modules_field;
147 
148     private static Field Felix_ModuleImpl_m_classLoader_field;
149     
150     private static Method Felix_adapt_method;
151     
152     private static Method Felix_bundle_wiring_getClassLoader_method;
153     
154     private static Class Felix_bundleWiringClazz;
155 
156     private static Boolean isFelix403 = null;
157 
158     private static ClassLoader internalGetFelixBundleClassLoader(Bundle bundle)
159     {
160         //firstly, try to find classes matching a newer version of felix
161         initFelix403(bundle);
162       
163         if (isFelix403.booleanValue())
164         {
165             try
166             {
167                 Object wiring = Felix_adapt_method.invoke(bundle, new Object[] {Felix_bundleWiringClazz});
168                 ClassLoader cl = (ClassLoader)Felix_bundle_wiring_getClassLoader_method.invoke(wiring);
169                 return cl;
170             }
171             catch (Exception e)
172             {
173                 LOG.warn(e);
174                 return null;
175             }
176         }
177 
178 
179         // Fallback to trying earlier versions of felix.     
180         if (Felix_BundleImpl_m_modules_field == null)
181         {
182             try
183             {
184                 Class bundleImplClazz = bundle.getClass().getClassLoader().loadClass("org.apache.felix.framework.BundleImpl");  
185                 Felix_BundleImpl_m_modules_field = bundleImplClazz.getDeclaredField("m_modules");
186                 Felix_BundleImpl_m_modules_field.setAccessible(true);
187             }
188             catch (ClassNotFoundException e)
189             {
190                 LOG.warn(e);
191             }
192             catch (NoSuchFieldException e)
193             {
194                 LOG.warn(e);
195             }
196         }
197 
198         // Figure out which version of the modules is exported
199         Object currentModuleImpl;
200         try
201         {
202             Object[] moduleArray = (Object[]) Felix_BundleImpl_m_modules_field.get(bundle);
203             currentModuleImpl = moduleArray[moduleArray.length - 1];
204         }
205         catch (Throwable t2)
206         {
207             try
208             {
209                 List<Object> moduleArray = (List<Object>) Felix_BundleImpl_m_modules_field.get(bundle);
210                 currentModuleImpl = moduleArray.get(moduleArray.size() - 1);
211             }
212             catch (Exception e)
213             {
214                 LOG.warn(e);
215                 return null;
216             }
217         }
218 
219         if (Felix_ModuleImpl_m_classLoader_field == null && currentModuleImpl != null)
220         {
221             try
222             {
223                 Felix_ModuleImpl_m_classLoader_field = bundle.getClass().getClassLoader().loadClass("org.apache.felix.framework.ModuleImpl").getDeclaredField("m_classLoader");
224                 Felix_ModuleImpl_m_classLoader_field.setAccessible(true);
225             }
226             catch (ClassNotFoundException e)
227             {
228                 LOG.warn(e);
229                 return null;
230             }   
231             catch (NoSuchFieldException e)
232             {
233                 LOG.warn(e);
234                 return null;
235             }
236         }
237         // first make sure that the classloader is ready:
238         // the m_classLoader field must be initialized by the
239         // ModuleImpl.getClassLoader() private method.
240         ClassLoader cl = null;
241         try
242         {
243             cl = (ClassLoader) Felix_ModuleImpl_m_classLoader_field.get(currentModuleImpl);
244             if (cl != null)
245                 return cl;
246         }
247         catch (Exception e)
248         {
249             LOG.warn(e);
250             return null;
251         }
252         
253         // looks like it was not ready:
254         // the m_classLoader field must be initialized by the
255         // ModuleImpl.getClassLoader() private method.
256         // this call will do that.
257         try
258         {
259             bundle.loadClass("java.lang.Object");
260             cl = (ClassLoader) Felix_ModuleImpl_m_classLoader_field.get(currentModuleImpl);
261             return cl;
262         }
263         catch (Exception e)
264         {
265             LOG.warn(e);
266             return null;
267         }
268     }
269 
270 
271     private static void initFelix403 (Bundle bundle)
272     {
273         //see if the version of Felix is a new one
274         if (isFelix403 == null)
275         {
276             try
277             {
278                 Class bundleImplClazz = bundle.getClass().getClassLoader().loadClass("org.apache.felix.framework.BundleImpl");
279                 Felix_bundleWiringClazz = bundle.getClass().getClassLoader().loadClass("org.osgi.framework.wiring.BundleWiring");
280                 Felix_adapt_method = bundleImplClazz.getDeclaredMethod("adapt", new Class[] {Class.class});
281                 Felix_adapt_method.setAccessible(true);
282                 Felix_bundle_wiring_getClassLoader_method = Felix_bundleWiringClazz.getDeclaredMethod("getClassLoader");
283                 Felix_bundle_wiring_getClassLoader_method.setAccessible(true);
284                 isFelix403 = Boolean.TRUE;
285             }
286             catch (ClassNotFoundException e)
287             {
288                 LOG.warn("Felix 4.x classes not found in environment");
289                 isFelix403 = Boolean.FALSE;
290             }
291             catch (NoSuchMethodException e)
292             { 
293                 LOG.warn("Felix 4.x classes not found in environment");
294                 isFelix403 = Boolean.FALSE;
295             }           
296         }
297     }
298 }