blob: e9e5ff7f6d6880a86099508f4a7497862f271091 [file] [log] [blame]
//
// ========================================================================
// Copyright (c) 1995-2015 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
//
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
//
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
//
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
//
package org.eclipse.jetty.osgi.boot.utils.internal;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.List;
import org.eclipse.jetty.osgi.boot.utils.BundleClassLoaderHelper;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
import org.osgi.framework.Bundle;
/**
* DefaultBundleClassLoaderHelper
* <p>
* Default implementation of the BundleClassLoaderHelper. Uses introspection to
* support equinox-3.5 and felix-2.0.0
*/
public class DefaultBundleClassLoaderHelper implements BundleClassLoaderHelper
{
private static final Logger LOG = Log.getLogger(BundleClassLoaderHelper.class);
private static enum OSGiContainerType {EquinoxOld, EquinoxLuna, FelixOld, Felix403, Concierge};
private static OSGiContainerType osgiContainer;
private static Class Equinox_BundleHost_Class;
private static Class Equinox_EquinoxBundle_Class;
private static Class Felix_BundleImpl_Class;
private static Class Felix_BundleWiring_Class;
//old equinox
private static Method Equinox_BundleHost_getBundleLoader_method;
private static Method Equinox_BundleLoader_createClassLoader_method;
//new equinox
private static Method Equinox_EquinoxBundle_getModuleClassLoader_Method;
//new felix
private static Method Felix_BundleImpl_Adapt_Method;
//old felix
private static Field Felix_BundleImpl_m_Modules_Field;
private static Field Felix_ModuleImpl_m_ClassLoader_Field;
private static Method Felix_BundleWiring_getClassLoader_Method;
// Concierge
private static Class Concierge_BundleImpl_Class;
private static Class Concierge_BundleWiring_Class;
private static Method Concierge_BundleImpl_Adapt_Method;
private static Method Concierge_BundleWiring_getClassLoader_Method;
private static void checkContainerType (Bundle bundle)
{
if (osgiContainer != null)
return;
try
{
Equinox_BundleHost_Class = bundle.getClass().getClassLoader().loadClass("org.eclipse.osgi.framework.internal.core.BundleHost");
osgiContainer = OSGiContainerType.EquinoxOld;
return;
}
catch (ClassNotFoundException e)
{
LOG.ignore(e);
}
try
{
Equinox_EquinoxBundle_Class = bundle.getClass().getClassLoader().loadClass("org.eclipse.osgi.internal.framework.EquinoxBundle");
osgiContainer = OSGiContainerType.EquinoxLuna;
return;
}
catch (ClassNotFoundException e)
{
LOG.ignore(e);
}
try
{
//old felix or new felix?
Felix_BundleImpl_Class = bundle.getClass().getClassLoader().loadClass("org.apache.felix.framework.BundleImpl");
try
{
Felix_BundleImpl_Adapt_Method = Felix_BundleImpl_Class.getDeclaredMethod("adapt", new Class[] {Class.class});
osgiContainer = OSGiContainerType.Felix403;
return;
}
catch (NoSuchMethodException e)
{
osgiContainer = OSGiContainerType.FelixOld;
return;
}
}
catch (ClassNotFoundException e)
{
LOG.ignore(e);
}
try
{
Concierge_BundleImpl_Class = bundle.getClass().getClassLoader().loadClass("org.eclipse.concierge.BundleImpl");
osgiContainer = OSGiContainerType.Concierge;
return;
}
catch (ClassNotFoundException e)
{
LOG.ignore(e);
}
LOG.warn("Unknown OSGi container type");
return;
}
/**
* Assuming the bundle is started.
*
* @param bundle the bundle
* @return classloader object
*/
public ClassLoader getBundleClassLoader(Bundle bundle)
{
String bundleActivator = (String) bundle.getHeaders().get("Bundle-Activator");
if (bundleActivator == null)
{
bundleActivator = (String) bundle.getHeaders().get("Jetty-ClassInBundle");
}
if (bundleActivator != null)
{
try
{
return bundle.loadClass(bundleActivator).getClassLoader();
}
catch (ClassNotFoundException e)
{
LOG.warn(e);
}
}
// resort to introspection
return getBundleClassLoaderForContainer(bundle);
}
/**
* @param bundle
* @return
*/
private ClassLoader getBundleClassLoaderForContainer (Bundle bundle)
{
checkContainerType (bundle);
if (osgiContainer == null)
{
LOG.warn("No classloader for unknown OSGi container type");
return null;
}
switch (osgiContainer)
{
case EquinoxOld:
case EquinoxLuna:
{
return internalGetEquinoxBundleClassLoader(bundle);
}
case FelixOld:
case Felix403:
{
return internalGetFelixBundleClassLoader(bundle);
}
case Concierge:
{
return internalGetConciergeBundleClassLoader(bundle);
}
default:
{
LOG.warn("No classloader found for bundle "+bundle.getSymbolicName());
return null;
}
}
}
/**
* @param bundle
* @return
*/
private static ClassLoader internalGetEquinoxBundleClassLoader(Bundle bundle)
{
if (osgiContainer == OSGiContainerType.EquinoxOld)
{
try
{
if (Equinox_BundleHost_getBundleLoader_method == null)
{
Equinox_BundleHost_getBundleLoader_method =
Equinox_BundleHost_Class.getDeclaredMethod("getBundleLoader", new Class[] {});
Equinox_BundleHost_getBundleLoader_method.setAccessible(true);
}
Object bundleLoader = Equinox_BundleHost_getBundleLoader_method.invoke(bundle, new Object[] {});
if (Equinox_BundleLoader_createClassLoader_method == null && bundleLoader != null)
{
Equinox_BundleLoader_createClassLoader_method =
bundleLoader.getClass().getClassLoader().loadClass("org.eclipse.osgi.internal.loader.BundleLoader").getDeclaredMethod("createClassLoader", new Class[] {});
Equinox_BundleLoader_createClassLoader_method.setAccessible(true);
}
return (ClassLoader) Equinox_BundleLoader_createClassLoader_method.invoke(bundleLoader, new Object[] {});
}
catch (ClassNotFoundException t)
{
LOG.warn(t);
return null;
}
catch (Throwable t)
{
LOG.warn(t);
return null;
}
}
if (osgiContainer == OSGiContainerType.EquinoxLuna)
{
try
{
if (Equinox_EquinoxBundle_getModuleClassLoader_Method == null)
Equinox_EquinoxBundle_getModuleClassLoader_Method = Equinox_EquinoxBundle_Class.getDeclaredMethod("getModuleClassLoader", new Class[] {Boolean.TYPE});
Equinox_EquinoxBundle_getModuleClassLoader_Method.setAccessible(true);
return (ClassLoader)Equinox_EquinoxBundle_getModuleClassLoader_Method.invoke(bundle, new Object[] {Boolean.FALSE});
}
catch (Exception e)
{
LOG.warn(e);
return null;
}
}
LOG.warn("No classloader for equinox platform for bundle "+bundle.getSymbolicName());
return null;
}
/**
* @param bundle
* @return
*/
private static ClassLoader internalGetFelixBundleClassLoader(Bundle bundle)
{
if (osgiContainer == OSGiContainerType.Felix403)
{
try
{
if (Felix_BundleWiring_Class == null)
Felix_BundleWiring_Class = bundle.getClass().getClassLoader().loadClass("org.osgi.framework.wiring.BundleWiring");
Felix_BundleImpl_Adapt_Method.setAccessible(true);
if (Felix_BundleWiring_getClassLoader_Method == null)
{
Felix_BundleWiring_getClassLoader_Method = Felix_BundleWiring_Class.getDeclaredMethod("getClassLoader");
Felix_BundleWiring_getClassLoader_Method.setAccessible(true);
}
Object wiring = Felix_BundleImpl_Adapt_Method.invoke(bundle, new Object[] {Felix_BundleWiring_Class});
return (ClassLoader)Felix_BundleWiring_getClassLoader_Method.invoke(wiring);
}
catch (Exception e)
{
LOG.warn(e);
return null;
}
}
if (osgiContainer == OSGiContainerType.FelixOld)
{
try
{
if (Felix_BundleImpl_m_Modules_Field == null)
{
Felix_BundleImpl_m_Modules_Field = Felix_BundleImpl_Class.getDeclaredField("m_modules");
Felix_BundleImpl_m_Modules_Field.setAccessible(true);
}
// Figure out which version of the modules is exported
Object currentModuleImpl;
try
{
Object[] moduleArray = (Object[]) Felix_BundleImpl_m_Modules_Field.get(bundle);
currentModuleImpl = moduleArray[moduleArray.length - 1];
}
catch (Throwable t2)
{
try
{
List<Object> moduleArray = (List<Object>) Felix_BundleImpl_m_Modules_Field.get(bundle);
currentModuleImpl = moduleArray.get(moduleArray.size() - 1);
}
catch (Exception e)
{
LOG.warn(e);
return null;
}
}
if (Felix_ModuleImpl_m_ClassLoader_Field == null && currentModuleImpl != null)
{
try
{
Felix_ModuleImpl_m_ClassLoader_Field = bundle.getClass().getClassLoader().loadClass("org.apache.felix.framework.ModuleImpl").getDeclaredField("m_classLoader");
Felix_ModuleImpl_m_ClassLoader_Field.setAccessible(true);
}
catch (Exception e)
{
LOG.warn(e);
return null;
}
}
// first make sure that the classloader is ready:
// the m_classLoader field must be initialized by the
// ModuleImpl.getClassLoader() private method.
ClassLoader cl = null;
try
{
cl = (ClassLoader) Felix_ModuleImpl_m_ClassLoader_Field.get(currentModuleImpl);
if (cl != null)
return cl;
}
catch (Exception e)
{
LOG.warn(e);
return null;
}
// looks like it was not ready:
// the m_classLoader field must be initialized by the
// ModuleImpl.getClassLoader() private method.
// this call will do that.
try
{
bundle.loadClass("java.lang.Object");
cl = (ClassLoader) Felix_ModuleImpl_m_ClassLoader_Field.get(currentModuleImpl);
return cl;
}
catch (Exception e)
{
LOG.warn(e);
return null;
}
}
catch (Exception e)
{
LOG.warn(e);
return null;
}
}
LOG.warn("No classloader for felix platform for bundle "+bundle.getSymbolicName());
return null;
}
/**
* @param bundle
* @return
*/
private static ClassLoader internalGetConciergeBundleClassLoader(Bundle bundle)
{
if (osgiContainer == OSGiContainerType.Concierge)
{
try
{
/**
* In Concierge:
*
* Option A:
* <pre>
* Concierge concierge = new Concierge(...);
* BundleWiring bundleWiring = concierge.getWiring(); // method is public
* </pre>
* Problem: getWiring not yet implementd
*
* Option B:
* <pre>
* Concierge concierge = new Concierge(...);
* BundleWiring bundleWiring = concierge.adapt(org.osgi.framework.wiring.BundleWiring);
* </pre>
* Same approach as done in Felix.
*
*/
if (Concierge_BundleWiring_Class == null) {
Concierge_BundleWiring_Class = bundle.getClass().getClassLoader().loadClass("org.osgi.framework.wiring.BundleWiring");
Concierge_BundleImpl_Adapt_Method = Concierge_BundleImpl_Class.getMethod("adapt", new Class[] {Class.class});
Concierge_BundleImpl_Adapt_Method.setAccessible(true);
Concierge_BundleWiring_getClassLoader_Method = Concierge_BundleWiring_Class.getMethod("getClassLoader");
Concierge_BundleWiring_getClassLoader_Method.setAccessible(true);
}
Object wiring = Concierge_BundleImpl_Adapt_Method.invoke(bundle, new Object[] {Concierge_BundleWiring_Class});
ClassLoader cl = (ClassLoader)Concierge_BundleWiring_getClassLoader_Method.invoke(wiring);
return cl;
}
catch (Exception e)
{
LOG.warn(e);
return null;
}
}
LOG.warn("No classloader for Concierge platform for bundle "+bundle.getSymbolicName());
return null;
}
}