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