Skip to content

Commit

Permalink
Merge pull request #108 from ozhelezniak-talend/ozhelezniak/fix_osgi_…
Browse files Browse the repository at this point in the history
…loader_issue

fix: find osgi loader
  • Loading branch information
jdereg authored Oct 17, 2024
2 parents 899b5dc + 2ae9520 commit 8712818
Show file tree
Hide file tree
Showing 2 changed files with 62 additions and 38 deletions.
95 changes: 59 additions & 36 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,55 +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);
}

return osgiClassLoaders.get(classFromBundle);
}

/**
* 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);
// Get the getBundle(Class<?>) method
Method getBundleMethod = frameworkUtilClass.getMethod("getBundle", Class.class);

// Invoke FrameworkUtil.getBundle(thisClass) to get the Bundle instance
Object bundle = getBundleMethod.invoke(null, ClassUtilities.class);
// Invoke FrameworkUtil.getBundle(thisClass) to get the Bundle instance
Object bundle = getBundleMethod.invoke(null, classFromBundle);

if (bundle != null) {
// Get BundleWiring class
Class<?> bundleWiringClass = Class.forName("org.osgi.framework.wiring.BundleWiring");
if (bundle != null) {
// Get BundleWiring class
Class<?> bundleWiringClass = Class.forName("org.osgi.framework.wiring.BundleWiring");

// Get the adapt(Class) method
Method adaptMethod = bundle.getClass().getMethod("adapt", Class.class);
// 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;
}
}
5 changes: 3 additions & 2 deletions src/test/java/com/cedarsoftware/util/TestDateUtilities.java
Original file line number Diff line number Diff line change
Expand Up @@ -555,8 +555,9 @@ void testDateToStringFormat()
boolean okToTest = false;

for (String zoneName : timeZoneOldSchoolNames) {
if (dateToString.contains(zoneName)) {
if (dateToString.contains(" " + zoneName)) {
okToTest = true;
break;
}
}

Expand Down Expand Up @@ -874,7 +875,7 @@ void testTimeZoneParsing(String exampleZone, Long epochMilli)
@Test
void testTimeBetterThanMilliResolution()
{
ZonedDateTime zonedDateTime = (ZonedDateTime) DateUtilities.parseDate("Jan 22nd, 2024 21:52:05.123456789-05:00", ZoneId.systemDefault(), true);
ZonedDateTime zonedDateTime = DateUtilities.parseDate("Jan 22nd, 2024 21:52:05.123456789-05:00", ZoneId.systemDefault(), true);
assertEquals(123456789, zonedDateTime.getNano());
assertEquals(2024, zonedDateTime.getYear());
assertEquals(1, zonedDateTime.getMonthValue());
Expand Down

0 comments on commit 8712818

Please sign in to comment.