11/*
2- * Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved.
2+ * Copyright (c) 2021, 2024 Oracle and/or its affiliates. All rights reserved.
33 *
44 * This program and the accompanying materials are made available under the
55 * terms of the Eclipse Distribution License v. 1.0, which is available at
1313import java .lang .reflect .Method ;
1414import java .security .AccessController ;
1515import java .security .PrivilegedAction ;
16+ import java .util .Arrays ;
1617import java .util .Iterator ;
1718import java .util .logging .Level ;
1819import java .util .logging .Logger ;
@@ -26,48 +27,41 @@ class FactoryFinder {
2627 new ServiceLoaderUtil .ExceptionHandler <RuntimeException >() {
2728 @ Override
2829 public RuntimeException createException (Throwable throwable , String message ) {
29- return new RuntimeException (message , throwable );
30+ return new IllegalStateException (message , throwable );
3031 }
3132 };
3233
3334 /**
3435 * Finds the implementation {@code Class} object for the given
35- * factory type. If it fails and {@code tryFallback} is {@code true}
36- * finds the {@code Class} object for the given default class name.
37- * The arguments supplied must be used in order
38- * Note the default class name may be needed even if fallback
39- * is not to be attempted in order to check if requested type is fallback.
36+ * factory type.
4037 * <P>
4138 * This method is package private so that this code can be shared.
4239 *
40+ * @param factoryClass factory abstract class or interface to be found
4341 * @return the {@code Class} object of the specified message factory;
44- * may not be {@code null}
45- *
46- * @param factoryClass factory abstract class or interface to be found
47- * @param defaultClassName the implementation class name, which is
48- * to be used only if nothing else
49- * is found; {@code null} to indicate
50- * that there is no default class name
51- * @param tryFallback whether to try the default class as a
52- * fallback
53- * @exception RuntimeException if there is no factory found
42+ * may not be {@code null}
43+ * @throws IllegalStateException if there is no factory found
5444 */
55- static <T > T find (Class <T > factoryClass ,
56- String defaultClassName ,
57- boolean tryFallback ) throws RuntimeException {
45+ static <T > T find (Class <T > factoryClass ) throws RuntimeException {
46+ for (ClassLoader l : getClassLoaders (
47+ Thread .class ,
48+ FactoryFinder .class ,
49+ System .class )) {
50+ T f = find (factoryClass , l );
51+ if (f != null ) {
52+ return f ;
53+ }
54+ }
5855
59- ClassLoader tccl = ServiceLoaderUtil .contextClassLoader (EXCEPTION_HANDLER );
60- String factoryId = factoryClass .getName ();
56+ throw EXCEPTION_HANDLER .createException ((Throwable ) null ,
57+ "Provider for " + factoryClass .getName () + " cannot be found" );
58+ }
6159
60+ static <T > T find (Class <T > factoryClass , ClassLoader loader ) throws RuntimeException {
6261 // Use the system property first
63- String className = fromSystemProperty (factoryId );
62+ String className = fromSystemProperty (factoryClass . getName () );
6463 if (className != null ) {
65- T result = newInstance (className , defaultClassName , tccl );
66- if (result != null ) {
67- return result ;
68- }
69- // try api loader
70- result = newInstance (className , defaultClassName , FactoryFinder .class .getClassLoader ());
64+ T result = newInstance (className , factoryClass , loader );
7165 if (result != null ) {
7266 return result ;
7367 }
@@ -76,40 +70,29 @@ static <T> T find(Class<T> factoryClass,
7670 // standard services: java.util.ServiceLoader
7771 T factory = ServiceLoaderUtil .firstByServiceLoader (
7872 factoryClass ,
73+ loader ,
7974 logger ,
8075 EXCEPTION_HANDLER );
8176 if (factory != null ) {
8277 return factory ;
8378 }
8479
8580 // handling Glassfish/OSGi (platform specific default)
86- if (isOsgi ()) {
87- T result = lookupUsingOSGiServiceLoader (factoryId );
88- if (result != null ) {
89- return result ;
90- }
81+ T result = lookupUsingHk2ServiceLoader (factoryClass , loader );
82+ if (result != null ) {
83+ return result ;
9184 }
9285
93- // If not found and fallback should not be tried, throw RuntimeException.
94- if (!tryFallback ) {
95- throw new RuntimeException (
96- "Provider for " + factoryId + " cannot be found" , null );
97- }
98-
99- // We didn't find the class through the usual means so try the default
100- // (built in) factory if specified.
101- if (defaultClassName == null ) {
102- throw new RuntimeException (
103- "Provider for " + factoryId + " cannot be found" , null );
104- }
105- return newInstance (defaultClassName , defaultClassName , tccl );
86+ return null ;
10687 }
10788
108- private static <T > T newInstance (String className , String defaultClassName , ClassLoader tccl ) throws RuntimeException {
89+ private static <T > T newInstance (String className ,
90+ Class <? extends T > service , ClassLoader loader )
91+ throws RuntimeException {
10992 return ServiceLoaderUtil .newInstance (
11093 className ,
111- defaultClassName ,
112- tccl ,
94+ service ,
95+ loader ,
11396 EXCEPTION_HANDLER );
11497 }
11598
@@ -138,31 +121,85 @@ private static void logFound(String value) {
138121 }
139122 }
140123
141- private static final String OSGI_SERVICE_LOADER_CLASS_NAME = "org.glassfish.hk2.osgiresourcelocator.ServiceLoader" ;
124+ private static Class <?>[] getHk2ServiceLoaderTargets (Class <?> factoryClass ) {
125+ ClassLoader [] loaders = getClassLoaders (Thread .class , factoryClass , System .class );
126+
127+ Class <?>[] classes = new Class <?>[loaders .length ];
128+ int w = 0 ;
129+ for (ClassLoader loader : loaders ) {
130+ if (loader != null ) {
131+ try {
132+ classes [w ++] = Class .forName ("org.glassfish.hk2.osgiresourcelocator.ServiceLoader" , false , loader );
133+ } catch (Exception | LinkageError ignored ) {
134+ } //GlassFish class loaders can throw undocumented exceptions
135+ }
136+ }
142137
143- private static boolean isOsgi () {
144- try {
145- Class .forName (OSGI_SERVICE_LOADER_CLASS_NAME );
146- return true ;
147- } catch (ClassNotFoundException ignored ) {
138+ if (classes .length != w ) {
139+ classes = Arrays .copyOf (classes , w );
148140 }
149- return false ;
141+ return classes ;
150142 }
151143
152144 @ SuppressWarnings ({"unchecked" })
153- private static <T > T lookupUsingOSGiServiceLoader (String factoryId ) {
154- try {
155- // Use reflection to avoid having any dependency on HK2 ServiceLoader class
156- Class <?> serviceClass = Class .forName (factoryId );
157- Class <?>[] args = new Class <?>[]{serviceClass };
158- Class <?> target = Class .forName (OSGI_SERVICE_LOADER_CLASS_NAME );
159- Method m = target .getMethod ("lookupProviderInstances" , Class .class );
160- Iterator <?> iter = ((Iterable <?>) m .invoke (null , (Object []) args )).iterator ();
161- return iter .hasNext () ? (T ) iter .next () : null ;
162- } catch (Exception ignored ) {
163- // log and continue
164- return null ;
145+ private static <T > T lookupUsingHk2ServiceLoader (Class <T > factoryClass , ClassLoader loader ) {
146+ for (Class <?> target : getHk2ServiceLoaderTargets (factoryClass )) {
147+ try {
148+ // Use reflection to avoid having any dependency on HK2 ServiceLoader class
149+ Class <?> serviceClass = Class .forName (factoryClass .getName (), false , loader );
150+ Class <?>[] args = new Class <?>[]{serviceClass };
151+ Method m = target .getMethod ("lookupProviderInstances" , Class .class );
152+ Iterable <?> iterable = ((Iterable <?>) m .invoke (null , (Object []) args ));
153+ if (iterable != null ) {
154+ Iterator <?> iter = iterable .iterator ();
155+ if (iter .hasNext ()) {
156+ return factoryClass .cast (iter .next ()); //Verify classloader.
157+ }
158+ }
159+ } catch (Exception ignored ) {
160+ // log and continue
161+ }
165162 }
163+ return null ;
166164 }
167165
166+ private static ClassLoader [] getClassLoaders (final Class <?>... classes ) {
167+ return AccessController .doPrivileged (
168+ new PrivilegedAction <ClassLoader []>() {
169+ @ Override
170+ public ClassLoader [] run () {
171+ ClassLoader [] loaders = new ClassLoader [classes .length ];
172+ int w = 0 ;
173+ for (Class <?> k : classes ) {
174+ ClassLoader cl = null ;
175+ if (k == Thread .class ) {
176+ try {
177+ cl = Thread .currentThread ().getContextClassLoader ();
178+ } catch (SecurityException ex ) {
179+ }
180+ } else if (k == System .class ) {
181+ try {
182+ cl = ClassLoader .getSystemClassLoader ();
183+ } catch (SecurityException ex ) {
184+ }
185+ } else {
186+ try {
187+ cl = k .getClassLoader ();
188+ } catch (SecurityException ex ) {
189+ }
190+ }
191+
192+ if (cl != null ) {
193+ loaders [w ++] = cl ;
194+ }
195+ }
196+
197+ if (loaders .length != w ) {
198+ loaders = Arrays .copyOf (loaders , w );
199+ }
200+ return loaders ;
201+ }
202+ }
203+ );
204+ }
168205}
0 commit comments