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.osgi.framework.Bundle;
27  
28  /**
29   * Default implementation of the BundleClassLoaderHelper. Uses introspection to
30   * support equinox-3.5 and felix-2.0.0
31   */
32  public class DefaultBundleClassLoaderHelper implements BundleClassLoaderHelper
33  {
34  
35      private static boolean identifiedOsgiImpl = false;
36  
37      private static boolean isEquinox = false;
38  
39      private static boolean isFelix = false;
40  
41      private static void init(Bundle bundle)
42      {
43          identifiedOsgiImpl = true;
44          try
45          {
46              isEquinox = bundle.getClass().getClassLoader().loadClass("org.eclipse.osgi.framework.internal.core.BundleHost") != null;
47          }
48          catch (Throwable t)
49          {
50              isEquinox = false;
51          }
52          if (!isEquinox)
53          {
54              try
55              {
56                  isFelix = bundle.getClass().getClassLoader().loadClass("org.apache.felix.framework.BundleImpl") != null;
57              }
58              catch (Throwable t2)
59              {
60                  isFelix = false;
61              }
62          }
63      }
64  
65      /**
66       * Assuming the bundle is started.
67       * 
68       * @param bundle
69       * @return classloader object
70       */
71      public ClassLoader getBundleClassLoader(Bundle bundle)
72      {
73          String bundleActivator = (String) bundle.getHeaders().get("Bundle-Activator");
74          if (bundleActivator == null)
75          {
76              bundleActivator = (String) bundle.getHeaders().get("Jetty-ClassInBundle");
77          }
78          if (bundleActivator != null)
79          {
80              try
81              {
82                  return bundle.loadClass(bundleActivator).getClassLoader();
83              }
84              catch (ClassNotFoundException e)
85              {
86                  // should not happen as we are called if the bundle is started
87                  // anyways.
88                  e.printStackTrace();
89              }
90          }
91          // resort to introspection
92          if (!identifiedOsgiImpl)
93          {
94              init(bundle);
95          }
96          if (isEquinox)
97          {
98              return internalGetEquinoxBundleClassLoader(bundle);
99          }
100         else if (isFelix) { return internalGetFelixBundleClassLoader(bundle); }
101         return null;
102     }
103 
104     private static Method Equinox_BundleHost_getBundleLoader_method;
105 
106     private static Method Equinox_BundleLoader_createClassLoader_method;
107 
108     private static ClassLoader internalGetEquinoxBundleClassLoader(Bundle bundle)
109     {
110         // assume equinox:
111         try
112         {
113             if (Equinox_BundleHost_getBundleLoader_method == null)
114             {
115                 Equinox_BundleHost_getBundleLoader_method = 
116                     bundle.getClass().getClassLoader().loadClass("org.eclipse.osgi.framework.internal.core.BundleHost").getDeclaredMethod("getBundleLoader", new Class[] {});
117                 Equinox_BundleHost_getBundleLoader_method.setAccessible(true);
118             }
119             Object bundleLoader = Equinox_BundleHost_getBundleLoader_method.invoke(bundle, new Object[] {});
120             if (Equinox_BundleLoader_createClassLoader_method == null && bundleLoader != null)
121             {
122                 Equinox_BundleLoader_createClassLoader_method = 
123                     bundleLoader.getClass().getClassLoader().loadClass("org.eclipse.osgi.internal.loader.BundleLoader").getDeclaredMethod("createClassLoader", new Class[] {});
124                 Equinox_BundleLoader_createClassLoader_method.setAccessible(true);
125             }
126             return (ClassLoader) Equinox_BundleLoader_createClassLoader_method.invoke(bundleLoader, new Object[] {});
127         }
128         catch (Throwable t)
129         {
130             t.printStackTrace();
131         }
132         return null;
133     }
134 
135     private static Field Felix_BundleImpl_m_modules_field;
136 
137     private static Field Felix_ModuleImpl_m_classLoader_field;
138 
139     private static ClassLoader internalGetFelixBundleClassLoader(Bundle bundle)
140     {
141         // assume felix:
142         try
143         {
144             // now get the current module from the bundle.
145             // and return the private field m_classLoader of ModuleImpl
146             if (Felix_BundleImpl_m_modules_field == null)
147             {
148                 Felix_BundleImpl_m_modules_field = bundle.getClass().getClassLoader().loadClass("org.apache.felix.framework.BundleImpl").getDeclaredField("m_modules");
149                 Felix_BundleImpl_m_modules_field.setAccessible(true);
150             }
151 
152             // Figure out which version of the modules is exported
153             Object currentModuleImpl;
154             try
155             {
156                 Object[] moduleArray = (Object[]) Felix_BundleImpl_m_modules_field.get(bundle);
157                 currentModuleImpl = moduleArray[moduleArray.length - 1];
158             }
159             catch (Throwable t2)
160             {
161                 @SuppressWarnings("unchecked")
162                 List<Object> moduleArray = (List<Object>) Felix_BundleImpl_m_modules_field.get(bundle);
163                 currentModuleImpl = moduleArray.get(moduleArray.size() - 1);
164             }
165 
166             if (Felix_ModuleImpl_m_classLoader_field == null && currentModuleImpl != null)
167             {
168                 Felix_ModuleImpl_m_classLoader_field = bundle.getClass().getClassLoader().loadClass("org.apache.felix.framework.ModuleImpl").getDeclaredField("m_classLoader");
169                 Felix_ModuleImpl_m_classLoader_field.setAccessible(true);
170             }
171             // first make sure that the classloader is ready:
172             // the m_classLoader field must be initialized by the
173             // ModuleImpl.getClassLoader() private method.
174             ClassLoader cl = (ClassLoader) Felix_ModuleImpl_m_classLoader_field.get(currentModuleImpl);
175             if (cl == null)
176             {
177                 // looks like it was not ready:
178                 // the m_classLoader field must be initialized by the
179                 // ModuleImpl.getClassLoader() private method.
180                 // this call will do that.
181                 bundle.loadClass("java.lang.Object");
182                 cl = (ClassLoader) Felix_ModuleImpl_m_classLoader_field.get(currentModuleImpl);
183                 return cl;
184             }
185             else
186             {
187                 return cl;
188             }
189         }
190         catch (Throwable t)
191         {
192             t.printStackTrace();
193         }
194         return null;
195     }
196 
197 }