431892 DefaultFileLocatorHelper.getBundleInstallLocation fails for equinox 3.10

This commit is contained in:
Jan Bartel 2014-04-07 20:57:41 +10:00
parent 64e11bc8e8
commit 90f387bc34
2 changed files with 266 additions and 177 deletions

View File

@ -37,37 +37,81 @@ import org.osgi.framework.Bundle;
public class DefaultBundleClassLoaderHelper implements BundleClassLoaderHelper public class DefaultBundleClassLoaderHelper implements BundleClassLoaderHelper
{ {
private static final Logger LOG = Log.getLogger(BundleClassLoaderHelper.class); private static final Logger LOG = Log.getLogger(BundleClassLoaderHelper.class);
private static enum OSGiContainerType {EquinoxOld, EquinoxLuna, FelixOld, Felix403};
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;
private static boolean identifiedOsgiImpl = false; //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;
private static boolean isEquinox = false;
private static boolean isFelix = false; private static void checkContainerType (Bundle bundle)
private static void init(Bundle bundle)
{ {
identifiedOsgiImpl = true; if (osgiContainer != null)
return;
try try
{ {
isEquinox = bundle.getClass().getClassLoader().loadClass("org.eclipse.osgi.framework.internal.core.BundleHost") != null; Equinox_BundleHost_Class = bundle.getClass().getClassLoader().loadClass("org.eclipse.osgi.framework.internal.core.BundleHost");
osgiContainer = OSGiContainerType.EquinoxOld;
return;
} }
catch (Throwable t) catch (ClassNotFoundException e)
{ {
isEquinox = false; LOG.ignore(e);
} }
if (!isEquinox)
{
try try
{ {
isFelix = bundle.getClass().getClassLoader().loadClass("org.apache.felix.framework.BundleImpl") != null; Equinox_EquinoxBundle_Class = bundle.getClass().getClassLoader().loadClass("org.eclipse.osgi.internal.framework.EquinoxBundle");
osgiContainer = OSGiContainerType.EquinoxLuna;
return;
} }
catch (Throwable t2) catch (ClassNotFoundException e)
{ {
isFelix = false; 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.warn("Unknown OSGi container type");
return;
} }
}
/** /**
* Assuming the bundle is started. * Assuming the bundle is started.
* *
@ -93,37 +137,62 @@ public class DefaultBundleClassLoaderHelper implements BundleClassLoaderHelper
LOG.warn(e); LOG.warn(e);
} }
} }
// resort to introspection // resort to introspection
if (!identifiedOsgiImpl) return getBundleClassLoaderForContainer(bundle);
{
init(bundle);
}
if (isEquinox)
{
return internalGetEquinoxBundleClassLoader(bundle);
}
else if (isFelix)
{
return internalGetFelixBundleClassLoader(bundle);
} }
LOG.warn("No classloader found for bundle "+bundle.getSymbolicName()); /**
* @param bundle
* @return
*/
private ClassLoader getBundleClassLoaderForContainer (Bundle bundle)
{
checkContainerType (bundle);
if (osgiContainer == null)
{
LOG.warn("No classloader for unknown OSGi container type");
return null; return null;
} }
private static Method Equinox_BundleHost_getBundleLoader_method; switch (osgiContainer)
{
case EquinoxOld:
case EquinoxLuna:
{
return internalGetEquinoxBundleClassLoader(bundle);
}
private static Method Equinox_BundleLoader_createClassLoader_method; case FelixOld:
case Felix403:
{
return internalGetFelixBundleClassLoader(bundle);
}
default:
{
LOG.warn("No classloader found for bundle "+bundle.getSymbolicName());
return null;
}
}
}
/**
* @param bundle
* @return
*/
private static ClassLoader internalGetEquinoxBundleClassLoader(Bundle bundle) private static ClassLoader internalGetEquinoxBundleClassLoader(Bundle bundle)
{ {
// assume equinox: if (osgiContainer == OSGiContainerType.EquinoxOld)
{
try try
{ {
if (Equinox_BundleHost_getBundleLoader_method == null) if (Equinox_BundleHost_getBundleLoader_method == null)
{ {
Equinox_BundleHost_getBundleLoader_method = Equinox_BundleHost_getBundleLoader_method =
bundle.getClass().getClassLoader().loadClass("org.eclipse.osgi.framework.internal.core.BundleHost").getDeclaredMethod("getBundleLoader", new Class[] {}); Equinox_BundleHost_Class.getDeclaredMethod("getBundleLoader", new Class[] {});
Equinox_BundleHost_getBundleLoader_method.setAccessible(true); Equinox_BundleHost_getBundleLoader_method.setAccessible(true);
} }
Object bundleLoader = Equinox_BundleHost_getBundleLoader_method.invoke(bundle, new Object[] {}); Object bundleLoader = Equinox_BundleHost_getBundleLoader_method.invoke(bundle, new Object[] {});
@ -135,38 +204,68 @@ public class DefaultBundleClassLoaderHelper implements BundleClassLoaderHelper
} }
return (ClassLoader) Equinox_BundleLoader_createClassLoader_method.invoke(bundleLoader, new Object[] {}); return (ClassLoader) Equinox_BundleLoader_createClassLoader_method.invoke(bundleLoader, new Object[] {});
} }
catch (ClassNotFoundException t)
{
LOG.warn(t);
return null;
}
catch (Throwable t) catch (Throwable t)
{ {
LOG.warn(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()); LOG.warn("No classloader for equinox platform for bundle "+bundle.getSymbolicName());
return null; return null;
} }
private static Field Felix_BundleImpl_m_modules_field;
private static Field Felix_ModuleImpl_m_classLoader_field;
private static Method Felix_adapt_method;
private static Method Felix_bundle_wiring_getClassLoader_method;
private static Class Felix_bundleWiringClazz;
private static Boolean isFelix403 = null;
/**
* @param bundle
* @return
*/
private static ClassLoader internalGetFelixBundleClassLoader(Bundle bundle) private static ClassLoader internalGetFelixBundleClassLoader(Bundle bundle)
{ {
//firstly, try to find classes matching a newer version of felix
initFelix403(bundle);
if (isFelix403.booleanValue()) if (osgiContainer == OSGiContainerType.Felix403)
{ {
try try
{ {
Object wiring = Felix_adapt_method.invoke(bundle, new Object[] {Felix_bundleWiringClazz}); if (Felix_BundleWiring_Class == null)
ClassLoader cl = (ClassLoader)Felix_bundle_wiring_getClassLoader_method.invoke(wiring); Felix_BundleWiring_Class = bundle.getClass().getClassLoader().loadClass("org.osgi.framework.wiring.BundleWiring");
return cl;
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) catch (Exception e)
{ {
@ -176,37 +275,29 @@ public class DefaultBundleClassLoaderHelper implements BundleClassLoaderHelper
} }
// Fallback to trying earlier versions of felix. if (osgiContainer == OSGiContainerType.FelixOld)
if (Felix_BundleImpl_m_modules_field == null)
{ {
try try
{ {
Class bundleImplClazz = bundle.getClass().getClassLoader().loadClass("org.apache.felix.framework.BundleImpl"); if (Felix_BundleImpl_m_Modules_Field == null)
Felix_BundleImpl_m_modules_field = bundleImplClazz.getDeclaredField("m_modules");
Felix_BundleImpl_m_modules_field.setAccessible(true);
}
catch (ClassNotFoundException e)
{ {
LOG.warn(e); Felix_BundleImpl_m_Modules_Field = Felix_BundleImpl_Class.getDeclaredField("m_modules");
} Felix_BundleImpl_m_Modules_Field.setAccessible(true);
catch (NoSuchFieldException e)
{
LOG.warn(e);
}
} }
// Figure out which version of the modules is exported // Figure out which version of the modules is exported
Object currentModuleImpl; Object currentModuleImpl;
try try
{ {
Object[] moduleArray = (Object[]) Felix_BundleImpl_m_modules_field.get(bundle); Object[] moduleArray = (Object[]) Felix_BundleImpl_m_Modules_Field.get(bundle);
currentModuleImpl = moduleArray[moduleArray.length - 1]; currentModuleImpl = moduleArray[moduleArray.length - 1];
} }
catch (Throwable t2) catch (Throwable t2)
{ {
try try
{ {
List<Object> moduleArray = (List<Object>) Felix_BundleImpl_m_modules_field.get(bundle); List<Object> moduleArray = (List<Object>) Felix_BundleImpl_m_Modules_Field.get(bundle);
currentModuleImpl = moduleArray.get(moduleArray.size() - 1); currentModuleImpl = moduleArray.get(moduleArray.size() - 1);
} }
catch (Exception e) catch (Exception e)
@ -216,31 +307,27 @@ public class DefaultBundleClassLoaderHelper implements BundleClassLoaderHelper
} }
} }
if (Felix_ModuleImpl_m_classLoader_field == null && currentModuleImpl != null) if (Felix_ModuleImpl_m_ClassLoader_Field == null && currentModuleImpl != null)
{ {
try try
{ {
Felix_ModuleImpl_m_classLoader_field = bundle.getClass().getClassLoader().loadClass("org.apache.felix.framework.ModuleImpl").getDeclaredField("m_classLoader"); Felix_ModuleImpl_m_ClassLoader_Field = bundle.getClass().getClassLoader().loadClass("org.apache.felix.framework.ModuleImpl").getDeclaredField("m_classLoader");
Felix_ModuleImpl_m_classLoader_field.setAccessible(true); Felix_ModuleImpl_m_ClassLoader_Field.setAccessible(true);
} }
catch (ClassNotFoundException e) catch (Exception e)
{
LOG.warn(e);
return null;
}
catch (NoSuchFieldException e)
{ {
LOG.warn(e); LOG.warn(e);
return null; return null;
} }
} }
// first make sure that the classloader is ready: // first make sure that the classloader is ready:
// the m_classLoader field must be initialized by the // the m_classLoader field must be initialized by the
// ModuleImpl.getClassLoader() private method. // ModuleImpl.getClassLoader() private method.
ClassLoader cl = null; ClassLoader cl = null;
try try
{ {
cl = (ClassLoader) Felix_ModuleImpl_m_classLoader_field.get(currentModuleImpl); cl = (ClassLoader) Felix_ModuleImpl_m_ClassLoader_Field.get(currentModuleImpl);
if (cl != null) if (cl != null)
return cl; return cl;
} }
@ -257,7 +344,7 @@ public class DefaultBundleClassLoaderHelper implements BundleClassLoaderHelper
try try
{ {
bundle.loadClass("java.lang.Object"); bundle.loadClass("java.lang.Object");
cl = (ClassLoader) Felix_ModuleImpl_m_classLoader_field.get(currentModuleImpl); cl = (ClassLoader) Felix_ModuleImpl_m_ClassLoader_Field.get(currentModuleImpl);
return cl; return cl;
} }
catch (Exception e) catch (Exception e)
@ -266,33 +353,14 @@ public class DefaultBundleClassLoaderHelper implements BundleClassLoaderHelper
return null; return null;
} }
} }
catch (Exception e)
{
LOG.warn(e);
return null;
}
}
LOG.warn("No classloader for felix platform for bundle "+bundle.getSymbolicName());
private static void initFelix403 (Bundle bundle) return null;
{
//see if the version of Felix is a new one
if (isFelix403 == null)
{
try
{
Class bundleImplClazz = bundle.getClass().getClassLoader().loadClass("org.apache.felix.framework.BundleImpl");
Felix_bundleWiringClazz = bundle.getClass().getClassLoader().loadClass("org.osgi.framework.wiring.BundleWiring");
Felix_adapt_method = bundleImplClazz.getDeclaredMethod("adapt", new Class[] {Class.class});
Felix_adapt_method.setAccessible(true);
Felix_bundle_wiring_getClassLoader_method = Felix_bundleWiringClazz.getDeclaredMethod("getClassLoader");
Felix_bundle_wiring_getClassLoader_method.setAccessible(true);
isFelix403 = Boolean.TRUE;
}
catch (ClassNotFoundException e)
{
LOG.warn("Felix 4.x classes not found in environment");
isFelix403 = Boolean.FALSE;
}
catch (NoSuchMethodException e)
{
LOG.warn("Felix 4.x classes not found in environment");
isFelix403 = Boolean.FALSE;
}
}
} }
} }

View File

@ -64,6 +64,24 @@ public class DefaultFileLocatorHelper implements BundleFileLocatorHelper
private static Field ZIP_FILE_FILED_FOR_ZIP_BUNDLE_FILE = null;// ZipFile private static Field ZIP_FILE_FILED_FOR_ZIP_BUNDLE_FILE = null;// ZipFile
private static final String[] FILE_BUNDLE_ENTRY_CLASSES = {"org.eclipse.osgi.baseadaptor.bundlefile.FileBundleEntry","org.eclipse.osgi.storage.bundlefile.FileBundleEntry"};
private static final String[] ZIP_BUNDLE_ENTRY_CLASSES = {"org.eclipse.osgi.baseadaptor.bundlefile.ZipBundleEntry","org.eclipse.osgi.storage.bundlefile.ZipBundleEntry"};
private static final String[] DIR_ZIP_BUNDLE_ENTRY_CLASSES = {"org.eclipse.osgi.baseadaptor.bundlefile.DirZipBundleEntry","org.eclipse.osgi.storage.bundlefile.DirZipBundleEntry"};
private static final String[] BUNDLE_URL_CONNECTION_CLASSES = {"org.eclipse.osgi.framework.internal.core.BundleURLConnection", "org.eclipse.osgi.storage.url.BundleURLConnection"};
public static boolean match (String name, String... names)
{
if (name == null || names == null)
return false;
boolean matched = false;
for (int i=0; i< names.length && !matched; i++)
if (name.equals(names[i]))
matched = true;
return matched;
}
/** /**
* Works with equinox, felix, nuxeo and probably more. Not exactly in the * Works with equinox, felix, nuxeo and probably more. Not exactly in the
* spirit of OSGi but quite necessary to support self-contained webapps and * spirit of OSGi but quite necessary to support self-contained webapps and
@ -107,7 +125,8 @@ public class DefaultFileLocatorHelper implements BundleFileLocatorHelper
BUNDLE_ENTRY_FIELD.setAccessible(true); BUNDLE_ENTRY_FIELD.setAccessible(true);
} }
Object bundleEntry = BUNDLE_ENTRY_FIELD.get(con); Object bundleEntry = BUNDLE_ENTRY_FIELD.get(con);
if (bundleEntry.getClass().getName().equals("org.eclipse.osgi.baseadaptor.bundlefile.FileBundleEntry"))
if (match(bundleEntry.getClass().getName(), FILE_BUNDLE_ENTRY_CLASSES))
{ {
if (FILE_FIELD == null) if (FILE_FIELD == null)
{ {
@ -117,7 +136,7 @@ public class DefaultFileLocatorHelper implements BundleFileLocatorHelper
File f = (File) FILE_FIELD.get(bundleEntry); File f = (File) FILE_FIELD.get(bundleEntry);
return f.getParentFile().getParentFile(); return f.getParentFile().getParentFile();
} }
else if (bundleEntry.getClass().getName().equals("org.eclipse.osgi.baseadaptor.bundlefile.ZipBundleEntry")) else if (match(bundleEntry.getClass().getName(), ZIP_BUNDLE_ENTRY_CLASSES))
{ {
url = bundle.getEntry("/"); url = bundle.getEntry("/");
@ -144,7 +163,7 @@ public class DefaultFileLocatorHelper implements BundleFileLocatorHelper
ZipFile zipFile = (ZipFile) ZIP_FILE_FILED_FOR_ZIP_BUNDLE_FILE.get(zipBundleFile); ZipFile zipFile = (ZipFile) ZIP_FILE_FILED_FOR_ZIP_BUNDLE_FILE.get(zipBundleFile);
return new File(zipFile.getName()); return new File(zipFile.getName());
} }
else if (bundleEntry.getClass().getName().equals("org.eclipse.osgi.baseadaptor.bundlefile.DirZipBundleEntry")) else if (match (bundleEntry.getClass().getName(), DIR_ZIP_BUNDLE_ENTRY_CLASSES))
{ {
// that will not happen as we did ask for the manifest not a // that will not happen as we did ask for the manifest not a
// directory. // directory.
@ -309,7 +328,7 @@ public class DefaultFileLocatorHelper implements BundleFileLocatorHelper
URLConnection conn = url.openConnection(); URLConnection conn = url.openConnection();
conn.setDefaultUseCaches(Resource.getDefaultUseCaches()); conn.setDefaultUseCaches(Resource.getDefaultUseCaches());
if (BUNDLE_URL_CONNECTION_getLocalURL == null && conn.getClass().getName().equals("org.eclipse.osgi.framework.internal.core.BundleURLConnection")) if (BUNDLE_URL_CONNECTION_getLocalURL == null && match(conn.getClass().getName(), BUNDLE_URL_CONNECTION_CLASSES))
{ {
BUNDLE_URL_CONNECTION_getLocalURL = conn.getClass().getMethod("getLocalURL", null); BUNDLE_URL_CONNECTION_getLocalURL = conn.getClass().getMethod("getLocalURL", null);
BUNDLE_URL_CONNECTION_getLocalURL.setAccessible(true); BUNDLE_URL_CONNECTION_getLocalURL.setAccessible(true);
@ -340,7 +359,9 @@ public class DefaultFileLocatorHelper implements BundleFileLocatorHelper
URLConnection conn = url.openConnection(); URLConnection conn = url.openConnection();
conn.setDefaultUseCaches(Resource.getDefaultUseCaches()); conn.setDefaultUseCaches(Resource.getDefaultUseCaches());
if (BUNDLE_URL_CONNECTION_getFileURL == null && conn.getClass().getName().equals("org.eclipse.osgi.framework.internal.core.BundleURLConnection")) if (BUNDLE_URL_CONNECTION_getFileURL == null
&&
match (conn.getClass().getName(), BUNDLE_URL_CONNECTION_CLASSES))
{ {
BUNDLE_URL_CONNECTION_getFileURL = conn.getClass().getMethod("getFileURL", null); BUNDLE_URL_CONNECTION_getFileURL = conn.getClass().getMethod("getFileURL", null);
BUNDLE_URL_CONNECTION_getFileURL.setAccessible(true); BUNDLE_URL_CONNECTION_getFileURL.setAccessible(true);