Skip to content

Commit

Permalink
fix: osgi loader resolve
Browse files Browse the repository at this point in the history
  • Loading branch information
ozhelezniak-talend committed Oct 15, 2024
1 parent cd2a265 commit 2ae9520
Showing 1 changed file with 58 additions and 38 deletions.
96 changes: 58 additions & 38 deletions src/main/java/com/cedarsoftware/util/ClassUtilities.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import java.util.Map;
import java.util.Queue;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

/**
* Useful utilities for Class work. For example, call computeInheritanceDistance(source, destination)
Expand Down Expand Up @@ -44,8 +45,8 @@ public class ClassUtilities
private static final Map<String, Class<?>> nameToClass = new HashMap<>();
private static final Map<Class<?>, Class<?>> wrapperMap = new HashMap<>();
// Cache for OSGi ClassLoader to avoid repeated reflection calls
private static volatile ClassLoader osgiClassLoader;
private static volatile boolean osgiChecked = false;
private static final Map<Class<?>, ClassLoader> osgiClassLoaders = new ConcurrentHashMap<>();
private static final Set<Class<?>> osgiChecked = new ConcurrentSet<>();

static {
prims.add(Byte.class);
Expand Down Expand Up @@ -357,8 +358,17 @@ public static boolean doesOneWrapTheOther(Class<?> x, Class<?> y) {
* @return the appropriate ClassLoader
*/
public static ClassLoader getClassLoader() {
return getClassLoader(ClassUtilities.class);
}

/**
* Obtains the appropriate ClassLoader depending on whether the environment is OSGi, JPMS, or neither.
*
* @return the appropriate ClassLoader
*/
public static ClassLoader getClassLoader(final Class<?> anchorClass) {
// Attempt to detect and handle OSGi environment
ClassLoader cl = getOSGiClassLoader();
ClassLoader cl = getOSGiClassLoader(anchorClass);
if (cl != null) {
return cl;
}
Expand All @@ -370,7 +380,7 @@ public static ClassLoader getClassLoader() {
}

// Fallback to the ClassLoader that loaded this utility class
cl = ClassUtilities.class.getClassLoader();
cl = anchorClass.getClassLoader();
if (cl != null) {
return cl;
}
Expand All @@ -384,58 +394,68 @@ public static ClassLoader getClassLoader() {
*
* @return the OSGi Bundle's ClassLoader if in an OSGi environment; otherwise, null
*/
private static ClassLoader getOSGiClassLoader() {
if (osgiChecked) {
return osgiClassLoader;
private static ClassLoader getOSGiClassLoader(final Class<?> classFromBundle) {
if (osgiChecked.contains(classFromBundle)) {
return osgiClassLoaders.get(classFromBundle);
}

synchronized (ClassUtilities.class) {
if (osgiChecked) {
return osgiClassLoader;
if (osgiChecked.contains(classFromBundle)) {
return osgiClassLoaders.get(classFromBundle);
}

try {
// Load the FrameworkUtil class from OSGi
Class<?> frameworkUtilClass = Class.forName("org.osgi.framework.FrameworkUtil");
osgiClassLoaders.computeIfAbsent(classFromBundle, k -> getOSGiClassLoader0(k));
osgiChecked.add(classFromBundle);
}

// Get the getBundle(Class<?>) method
Method getBundleMethod = frameworkUtilClass.getMethod("getBundle", Class.class);
return osgiClassLoaders.get(classFromBundle);
}

// Invoke FrameworkUtil.getBundle(thisClass) to get the Bundle instance
Object bundle = getBundleMethod.invoke(null, ClassUtilities.class);
/**
* Attempts to retrieve the OSGi Bundle's ClassLoader using FrameworkUtil.
*
* @return the OSGi Bundle's ClassLoader if in an OSGi environment; otherwise, null
*/
private static ClassLoader getOSGiClassLoader0(final Class<?> classFromBundle) {
try {
// Load the FrameworkUtil class from OSGi
Class<?> frameworkUtilClass = Class.forName("org.osgi.framework.FrameworkUtil");

// Get the getBundle(Class<?>) method
Method getBundleMethod = frameworkUtilClass.getMethod("getBundle", Class.class);

if (bundle != null) {
// Get BundleWiring class
Class<?> bundleWiringClass = Class.forName("org.osgi.framework.wiring.BundleWiring");
// Invoke FrameworkUtil.getBundle(thisClass) to get the Bundle instance
Object bundle = getBundleMethod.invoke(null, classFromBundle);

// Get the adapt(Class) method
Method adaptMethod = bundle.getClass().getMethod("adapt", Class.class);
if (bundle != null) {
// Get BundleWiring class
Class<?> bundleWiringClass = Class.forName("org.osgi.framework.wiring.BundleWiring");

// method is inside not a public class, so we need to make it accessible
adaptMethod.setAccessible(true);
// Get the adapt(Class) method
Method adaptMethod = bundle.getClass().getMethod("adapt", Class.class);

// Invoke bundle.adapt(BundleWiring.class) to get the BundleWiring instance
Object bundleWiring = adaptMethod.invoke(bundle, bundleWiringClass);
// method is inside not a public class, so we need to make it accessible
adaptMethod.setAccessible(true);

if (bundleWiring != null) {
// Get the getClassLoader() method from BundleWiring
Method getClassLoaderMethod = bundleWiringClass.getMethod("getClassLoader");
// Invoke bundle.adapt(BundleWiring.class) to get the BundleWiring instance
Object bundleWiring = adaptMethod.invoke(bundle, bundleWiringClass);

// Invoke getClassLoader() to obtain the ClassLoader
Object classLoader = getClassLoaderMethod.invoke(bundleWiring);
if (bundleWiring != null) {
// Get the getClassLoader() method from BundleWiring
Method getClassLoaderMethod = bundleWiringClass.getMethod("getClassLoader");

if (classLoader instanceof ClassLoader) {
osgiClassLoader = (ClassLoader) classLoader;
}
// Invoke getClassLoader() to obtain the ClassLoader
Object classLoader = getClassLoaderMethod.invoke(bundleWiring);

if (classLoader instanceof ClassLoader) {
return (ClassLoader) classLoader;
}
}
} catch (Exception e) {
// OSGi FrameworkUtil is not present; not in an OSGi environment
} finally {
osgiChecked = true;
}
} catch (Exception e) {
// OSGi FrameworkUtil is not present; not in an OSGi environment
}

return osgiClassLoader;
return null;
}
}

0 comments on commit 2ae9520

Please sign in to comment.