View Javadoc

1   // ========================================================================
2   // Copyright (c) 2009 Intalio, Inc.
3   // ------------------------------------------------------------------------
4   // All rights reserved. This program and the accompanying materials
5   // are made available under the terms of the Eclipse Public License v1.0
6   // and Apache License v2.0 which accompanies this distribution.
7   // The Eclipse Public License is available at 
8   // http://www.eclipse.org/legal/epl-v10.html
9   // The Apache License v2.0 is available at
10  // http://www.opensource.org/licenses/apache2.0.php
11  // You may elect to redistribute this code under either of these licenses. 
12  // ========================================================================
13  package org.eclipse.jetty.osgi.boot.utils.internal;
14  
15  import java.lang.reflect.Field;
16  import java.lang.reflect.Method;
17  import java.util.List;
18  
19  import org.eclipse.jetty.osgi.boot.utils.BundleClassLoaderHelper;
20  import org.osgi.framework.Bundle;
21  
22  /**
23   * Default implementation of the BundleClassLoaderHelper. Uses introspection to
24   * support equinox-3.5 and felix-2.0.0
25   */
26  public class DefaultBundleClassLoaderHelper implements BundleClassLoaderHelper
27  {
28  
29      private static boolean identifiedOsgiImpl = false;
30  
31      private static boolean isEquinox = false;
32  
33      private static boolean isFelix = false;
34  
35      private static void init(Bundle bundle)
36      {
37          identifiedOsgiImpl = true;
38          try
39          {
40              isEquinox = bundle.getClass().getClassLoader().loadClass("org.eclipse.osgi.framework.internal.core.BundleHost") != null;
41          }
42          catch (Throwable t)
43          {
44              isEquinox = false;
45          }
46          if (!isEquinox)
47          {
48              try
49              {
50                  isFelix = bundle.getClass().getClassLoader().loadClass("org.apache.felix.framework.BundleImpl") != null;
51              }
52              catch (Throwable t2)
53              {
54                  isFelix = false;
55              }
56          }
57      }
58  
59      /**
60       * Assuming the bundle is started.
61       * 
62       * @param bundle
63       * @return classloader object
64       */
65      public ClassLoader getBundleClassLoader(Bundle bundle)
66      {
67          String bundleActivator = (String) bundle.getHeaders().get("Bundle-Activator");
68          if (bundleActivator == null)
69          {
70              bundleActivator = (String) bundle.getHeaders().get("Jetty-ClassInBundle");
71          }
72          if (bundleActivator != null)
73          {
74              try
75              {
76                  return bundle.loadClass(bundleActivator).getClassLoader();
77              }
78              catch (ClassNotFoundException e)
79              {
80                  // should not happen as we are called if the bundle is started
81                  // anyways.
82                  e.printStackTrace();
83              }
84          }
85          // resort to introspection
86          if (!identifiedOsgiImpl)
87          {
88              init(bundle);
89          }
90          if (isEquinox)
91          {
92              return internalGetEquinoxBundleClassLoader(bundle);
93          }
94          else if (isFelix) { return internalGetFelixBundleClassLoader(bundle); }
95          return null;
96      }
97  
98      private static Method Equinox_BundleHost_getBundleLoader_method;
99  
100     private static Method Equinox_BundleLoader_createClassLoader_method;
101 
102     private static ClassLoader internalGetEquinoxBundleClassLoader(Bundle bundle)
103     {
104         // assume equinox:
105         try
106         {
107             if (Equinox_BundleHost_getBundleLoader_method == null)
108             {
109                 Equinox_BundleHost_getBundleLoader_method = 
110                     bundle.getClass().getClassLoader().loadClass("org.eclipse.osgi.framework.internal.core.BundleHost").getDeclaredMethod("getBundleLoader", new Class[] {});
111                 Equinox_BundleHost_getBundleLoader_method.setAccessible(true);
112             }
113             Object bundleLoader = Equinox_BundleHost_getBundleLoader_method.invoke(bundle, new Object[] {});
114             if (Equinox_BundleLoader_createClassLoader_method == null && bundleLoader != null)
115             {
116                 Equinox_BundleLoader_createClassLoader_method = 
117                     bundleLoader.getClass().getClassLoader().loadClass("org.eclipse.osgi.internal.loader.BundleLoader").getDeclaredMethod("createClassLoader", new Class[] {});
118                 Equinox_BundleLoader_createClassLoader_method.setAccessible(true);
119             }
120             return (ClassLoader) Equinox_BundleLoader_createClassLoader_method.invoke(bundleLoader, new Object[] {});
121         }
122         catch (Throwable t)
123         {
124             t.printStackTrace();
125         }
126         return null;
127     }
128 
129     private static Field Felix_BundleImpl_m_modules_field;
130 
131     private static Field Felix_ModuleImpl_m_classLoader_field;
132 
133     private static ClassLoader internalGetFelixBundleClassLoader(Bundle bundle)
134     {
135         // assume felix:
136         try
137         {
138             // now get the current module from the bundle.
139             // and return the private field m_classLoader of ModuleImpl
140             if (Felix_BundleImpl_m_modules_field == null)
141             {
142                 Felix_BundleImpl_m_modules_field = bundle.getClass().getClassLoader().loadClass("org.apache.felix.framework.BundleImpl").getDeclaredField("m_modules");
143                 Felix_BundleImpl_m_modules_field.setAccessible(true);
144             }
145 
146             // Figure out which version of the modules is exported
147             Object currentModuleImpl;
148             try
149             {
150                 Object[] moduleArray = (Object[]) Felix_BundleImpl_m_modules_field.get(bundle);
151                 currentModuleImpl = moduleArray[moduleArray.length - 1];
152             }
153             catch (Throwable t2)
154             {
155                 @SuppressWarnings("unchecked")
156                 List<Object> moduleArray = (List<Object>) Felix_BundleImpl_m_modules_field.get(bundle);
157                 currentModuleImpl = moduleArray.get(moduleArray.size() - 1);
158             }
159 
160             if (Felix_ModuleImpl_m_classLoader_field == null && currentModuleImpl != null)
161             {
162                 Felix_ModuleImpl_m_classLoader_field = bundle.getClass().getClassLoader().loadClass("org.apache.felix.framework.ModuleImpl").getDeclaredField("m_classLoader");
163                 Felix_ModuleImpl_m_classLoader_field.setAccessible(true);
164             }
165             // first make sure that the classloader is ready:
166             // the m_classLoader field must be initialized by the
167             // ModuleImpl.getClassLoader() private method.
168             ClassLoader cl = (ClassLoader) Felix_ModuleImpl_m_classLoader_field.get(currentModuleImpl);
169             if (cl == null)
170             {
171                 // looks like it was not ready:
172                 // the m_classLoader field must be initialized by the
173                 // ModuleImpl.getClassLoader() private method.
174                 // this call will do that.
175                 bundle.loadClass("java.lang.Object");
176                 cl = (ClassLoader) Felix_ModuleImpl_m_classLoader_field.get(currentModuleImpl);
177                 return cl;
178             }
179             else
180             {
181                 return cl;
182             }
183         }
184         catch (Throwable t)
185         {
186             t.printStackTrace();
187         }
188         return null;
189     }
190 
191 }