|
1 /* |
|
2 * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. |
|
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
|
4 * |
|
5 * This code is free software; you can redistribute it and/or modify it |
|
6 * under the terms of the GNU General Public License version 2 only, as |
|
7 * published by the Free Software Foundation. Oracle designates this |
|
8 * particular file as subject to the "Classpath" exception as provided |
|
9 * by Oracle in the LICENSE file that accompanied this code. |
|
10 * |
|
11 * This code is distributed in the hope that it will be useful, but WITHOUT |
|
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
|
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
|
14 * version 2 for more details (a copy is included in the LICENSE file that |
|
15 * accompanied this code). |
|
16 * |
|
17 * You should have received a copy of the GNU General Public License version |
|
18 * 2 along with this work; if not, write to the Free Software Foundation, |
|
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
|
20 * |
|
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
|
22 * or visit www.oracle.com if you need additional information or have any |
|
23 * questions. |
|
24 */ |
|
25 |
|
26 /* |
|
27 * This file is available under and governed by the GNU General Public |
|
28 * License version 2 only, as published by the Free Software Foundation. |
|
29 * However, the following notice accompanied the original version of this |
|
30 * file, and Oracle licenses the original version of this file under the BSD |
|
31 * license: |
|
32 */ |
|
33 /* |
|
34 Copyright 2009-2013 Attila Szegedi |
|
35 |
|
36 Licensed under both the Apache License, Version 2.0 (the "Apache License") |
|
37 and the BSD License (the "BSD License"), with licensee being free to |
|
38 choose either of the two at their discretion. |
|
39 |
|
40 You may not use this file except in compliance with either the Apache |
|
41 License or the BSD License. |
|
42 |
|
43 If you choose to use this file in compliance with the Apache License, the |
|
44 following notice applies to you: |
|
45 |
|
46 You may obtain a copy of the Apache License at |
|
47 |
|
48 http://www.apache.org/licenses/LICENSE-2.0 |
|
49 |
|
50 Unless required by applicable law or agreed to in writing, software |
|
51 distributed under the License is distributed on an "AS IS" BASIS, |
|
52 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or |
|
53 implied. See the License for the specific language governing |
|
54 permissions and limitations under the License. |
|
55 |
|
56 If you choose to use this file in compliance with the BSD License, the |
|
57 following notice applies to you: |
|
58 |
|
59 Redistribution and use in source and binary forms, with or without |
|
60 modification, are permitted provided that the following conditions are |
|
61 met: |
|
62 * Redistributions of source code must retain the above copyright |
|
63 notice, this list of conditions and the following disclaimer. |
|
64 * Redistributions in binary form must reproduce the above copyright |
|
65 notice, this list of conditions and the following disclaimer in the |
|
66 documentation and/or other materials provided with the distribution. |
|
67 * Neither the name of the copyright holder nor the names of |
|
68 contributors may be used to endorse or promote products derived from |
|
69 this software without specific prior written permission. |
|
70 |
|
71 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS |
|
72 IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
|
73 TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A |
|
74 PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDER |
|
75 BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
|
76 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
|
77 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR |
|
78 BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, |
|
79 WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR |
|
80 OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF |
|
81 ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
|
82 */ |
|
83 |
|
84 package jdk.dynalink; |
|
85 |
|
86 import java.lang.invoke.MethodHandle; |
|
87 import java.lang.invoke.MethodType; |
|
88 import java.lang.invoke.MutableCallSite; |
|
89 import java.security.AccessControlContext; |
|
90 import java.security.AccessController; |
|
91 import java.security.PrivilegedAction; |
|
92 import java.util.ArrayList; |
|
93 import java.util.Arrays; |
|
94 import java.util.Collections; |
|
95 import java.util.HashSet; |
|
96 import java.util.Iterator; |
|
97 import java.util.LinkedList; |
|
98 import java.util.List; |
|
99 import java.util.Objects; |
|
100 import java.util.ServiceConfigurationError; |
|
101 import java.util.ServiceLoader; |
|
102 import java.util.Set; |
|
103 import java.util.function.Supplier; |
|
104 import jdk.dynalink.beans.BeansLinker; |
|
105 import jdk.dynalink.internal.AccessControlContextFactory; |
|
106 import jdk.dynalink.linker.GuardedInvocation; |
|
107 import jdk.dynalink.linker.GuardedInvocationTransformer; |
|
108 import jdk.dynalink.linker.GuardingDynamicLinker; |
|
109 import jdk.dynalink.linker.GuardingDynamicLinkerExporter; |
|
110 import jdk.dynalink.linker.GuardingTypeConverterFactory; |
|
111 import jdk.dynalink.linker.LinkRequest; |
|
112 import jdk.dynalink.linker.LinkerServices; |
|
113 import jdk.dynalink.linker.MethodHandleTransformer; |
|
114 import jdk.dynalink.linker.MethodTypeConversionStrategy; |
|
115 import jdk.dynalink.linker.support.CompositeGuardingDynamicLinker; |
|
116 import jdk.dynalink.linker.support.CompositeTypeBasedGuardingDynamicLinker; |
|
117 import jdk.dynalink.linker.support.DefaultInternalObjectFilter; |
|
118 import jdk.dynalink.linker.support.TypeUtilities; |
|
119 |
|
120 /** |
|
121 * A factory class for creating {@link DynamicLinker} objects. Dynamic linkers |
|
122 * are the central objects in Dynalink; these are composed of several |
|
123 * {@link GuardingDynamicLinker} objects and coordinate linking of call sites |
|
124 * with them. The usual dynamic linker is a linker |
|
125 * composed of all {@link GuardingDynamicLinker} objects explicitly pre-created |
|
126 * by the user of the factory and configured with |
|
127 * {@link #setPrioritizedLinkers(List)}, as well as any |
|
128 * {@link #setClassLoader(ClassLoader) automatically discovered} ones, and |
|
129 * finally the ones configured with {@link #setFallbackLinkers(List)}; this last |
|
130 * category usually includes {@link BeansLinker}. |
|
131 */ |
|
132 public final class DynamicLinkerFactory { |
|
133 private static final AccessControlContext GET_CLASS_LOADER_CONTEXT = |
|
134 AccessControlContextFactory.createAccessControlContext("getClassLoader"); |
|
135 |
|
136 /** |
|
137 * Default value for {@link #setUnstableRelinkThreshold(int) unstable relink |
|
138 * threshold}. |
|
139 */ |
|
140 private static final int DEFAULT_UNSTABLE_RELINK_THRESHOLD = 8; |
|
141 |
|
142 private boolean classLoaderExplicitlySet = false; |
|
143 private ClassLoader classLoader; |
|
144 |
|
145 private List<? extends GuardingDynamicLinker> prioritizedLinkers; |
|
146 private List<? extends GuardingDynamicLinker> fallbackLinkers; |
|
147 private boolean syncOnRelink = false; |
|
148 private int unstableRelinkThreshold = DEFAULT_UNSTABLE_RELINK_THRESHOLD; |
|
149 private GuardedInvocationTransformer prelinkTransformer; |
|
150 private MethodTypeConversionStrategy autoConversionStrategy; |
|
151 private MethodHandleTransformer internalObjectsFilter; |
|
152 |
|
153 private List<ServiceConfigurationError> autoLoadingErrors = Collections.emptyList(); |
|
154 |
|
155 /** |
|
156 * Creates a new dynamic linker factory with default configuration. Upon |
|
157 * creation, the factory can be configured using various {@code setXxx()} |
|
158 * methods and used to create one or more dynamic linkers according to its |
|
159 * current configuration using {@link #createLinker()}. |
|
160 */ |
|
161 public DynamicLinkerFactory() { |
|
162 } |
|
163 |
|
164 /** |
|
165 * Sets the class loader for automatic discovery of available guarding |
|
166 * dynamic linkers. {@link GuardingDynamicLinkerExporter} implementations |
|
167 * available through this class loader will be automatically instantiated |
|
168 * using the {@link ServiceLoader} mechanism and the linkers they provide |
|
169 * will be incorporated into {@code DynamicLinker}s that this factory |
|
170 * creates. This allows for cross-language interoperability where call sites |
|
171 * belonging to this language runtime can be linked by linkers from these |
|
172 * automatically discovered runtimes if their native objects are passed to |
|
173 * this runtime. If class loader is not set explicitly by invoking this |
|
174 * method, then the thread context class loader of the thread invoking |
|
175 * {@link #createLinker()} will be used. If this method is invoked |
|
176 * explicitly with null then {@link ServiceLoader#loadInstalled(Class)} will |
|
177 * be used to load the linkers. |
|
178 * |
|
179 * @param classLoader the class loader used for the automatic discovery of |
|
180 * available linkers. |
|
181 */ |
|
182 public void setClassLoader(final ClassLoader classLoader) { |
|
183 this.classLoader = classLoader; |
|
184 classLoaderExplicitlySet = true; |
|
185 } |
|
186 |
|
187 /** |
|
188 * Sets the prioritized guarding dynamic linkers. Language runtimes using |
|
189 * Dynalink will usually have at least one linker for their own language. |
|
190 * These linkers will be consulted first by the resulting dynamic linker |
|
191 * when it is linking call sites, before any autodiscovered and fallback |
|
192 * linkers. If the factory also autodiscovers a linker class matching one |
|
193 * of the prioritized linkers, the autodiscovered class will be ignored and |
|
194 * the explicit prioritized instance will be used. |
|
195 * |
|
196 * @param prioritizedLinkers the list of prioritized linkers. Can be null. |
|
197 * @throws NullPointerException if any of the list elements are null. |
|
198 */ |
|
199 public void setPrioritizedLinkers(final List<? extends GuardingDynamicLinker> prioritizedLinkers) { |
|
200 this.prioritizedLinkers = copyListRequireNonNullElements(prioritizedLinkers); |
|
201 } |
|
202 |
|
203 /** |
|
204 * Sets the prioritized guarding dynamic linkers. Identical to calling |
|
205 * {@link #setPrioritizedLinkers(List)} with |
|
206 * {@code Arrays.asList(prioritizedLinkers)}. |
|
207 * |
|
208 * @param prioritizedLinkers an array of prioritized linkers. Can be null. |
|
209 * @throws NullPointerException if any of the array elements are null. |
|
210 */ |
|
211 public void setPrioritizedLinkers(final GuardingDynamicLinker... prioritizedLinkers) { |
|
212 setPrioritizedLinkers(prioritizedLinkers == null ? null : Arrays.asList(prioritizedLinkers)); |
|
213 } |
|
214 |
|
215 /** |
|
216 * Sets a single prioritized linker. Identical to calling |
|
217 * {@link #setPrioritizedLinkers(List)} with a single-element list. |
|
218 * |
|
219 * @param prioritizedLinker the single prioritized linker. Must not be null. |
|
220 * @throws NullPointerException if null is passed. |
|
221 */ |
|
222 public void setPrioritizedLinker(final GuardingDynamicLinker prioritizedLinker) { |
|
223 this.prioritizedLinkers = Collections.singletonList(Objects.requireNonNull(prioritizedLinker)); |
|
224 } |
|
225 |
|
226 /** |
|
227 * Sets the fallback guarding dynamic linkers. These linkers will be |
|
228 * consulted last by the resulting dynamic linker when it is linking call |
|
229 * sites, after any autodiscovered and prioritized linkers. If the factory |
|
230 * also autodiscovers a linker class matching one of the fallback linkers, |
|
231 * the autodiscovered class will be ignored and the explicit fallback |
|
232 * instance will be used. |
|
233 * |
|
234 * @param fallbackLinkers the list of fallback linkers. Can be empty to |
|
235 * indicate the caller wishes to set no fallback linkers. Note that if this |
|
236 * method is not invoked explicitly or is passed null, then the factory |
|
237 * will create an instance of {@link BeansLinker} to serve as the default |
|
238 * fallback linker. |
|
239 * @throws NullPointerException if any of the list elements are null. |
|
240 */ |
|
241 public void setFallbackLinkers(final List<? extends GuardingDynamicLinker> fallbackLinkers) { |
|
242 this.fallbackLinkers = copyListRequireNonNullElements(fallbackLinkers); |
|
243 } |
|
244 |
|
245 /** |
|
246 * Sets the fallback guarding dynamic linkers. Identical to calling |
|
247 * {@link #setFallbackLinkers(List)} with |
|
248 * {@code Arrays.asList(fallbackLinkers)}. |
|
249 * |
|
250 * @param fallbackLinkers an array of fallback linkers. Can be empty to |
|
251 * indicate the caller wishes to set no fallback linkers. Note that if this |
|
252 * method is not invoked explicitly or is passed null, then the factory |
|
253 * will create an instance of {@link BeansLinker} to serve as the default |
|
254 * fallback linker. |
|
255 * @throws NullPointerException if any of the array elements are null. |
|
256 */ |
|
257 public void setFallbackLinkers(final GuardingDynamicLinker... fallbackLinkers) { |
|
258 setFallbackLinkers(fallbackLinkers == null ? null : Arrays.asList(fallbackLinkers)); |
|
259 } |
|
260 |
|
261 /** |
|
262 * Sets whether the dynamic linker created by this factory will invoke |
|
263 * {@link MutableCallSite#syncAll(MutableCallSite[])} after a call site is |
|
264 * relinked. Defaults to false. You probably want to set it to true if your |
|
265 * runtime supports multithreaded execution of dynamically linked code. |
|
266 * @param syncOnRelink true for invoking sync on relink, false otherwise. |
|
267 */ |
|
268 public void setSyncOnRelink(final boolean syncOnRelink) { |
|
269 this.syncOnRelink = syncOnRelink; |
|
270 } |
|
271 |
|
272 /** |
|
273 * Sets the unstable relink threshold; the number of times a call site is |
|
274 * relinked after which it will be considered unstable, and subsequent link |
|
275 * requests for it will indicate this. Defaults to 8 when not set explicitly. |
|
276 * @param unstableRelinkThreshold the new threshold. Must not be less than |
|
277 * zero. The value of zero means that call sites will never be considered |
|
278 * unstable. |
|
279 * @see LinkRequest#isCallSiteUnstable() |
|
280 */ |
|
281 public void setUnstableRelinkThreshold(final int unstableRelinkThreshold) { |
|
282 if(unstableRelinkThreshold < 0) { |
|
283 throw new IllegalArgumentException("unstableRelinkThreshold < 0"); |
|
284 } |
|
285 this.unstableRelinkThreshold = unstableRelinkThreshold; |
|
286 } |
|
287 |
|
288 /** |
|
289 * Set the pre-link transformer. This is a |
|
290 * {@link GuardedInvocationTransformer} that will get the final chance to |
|
291 * modify the guarded invocation after it has been created by a component |
|
292 * linker and before the dynamic linker links it into the call site. It is |
|
293 * normally used to adapt the return value type of the invocation to the |
|
294 * type of the call site. When not set explicitly, a default pre-link |
|
295 * transformer will be used that simply calls |
|
296 * {@link GuardedInvocation#asType(LinkerServices, MethodType)}. Customized |
|
297 * pre-link transformers are rarely needed; they are mostly used as a |
|
298 * building block for implementing advanced techniques such as code |
|
299 * deoptimization strategies. |
|
300 * @param prelinkTransformer the pre-link transformer for the dynamic |
|
301 * linker. Can be null to have the factory use the default transformer. |
|
302 */ |
|
303 public void setPrelinkTransformer(final GuardedInvocationTransformer prelinkTransformer) { |
|
304 this.prelinkTransformer = prelinkTransformer; |
|
305 } |
|
306 |
|
307 /** |
|
308 * Sets an object representing the conversion strategy for automatic type |
|
309 * conversions. After |
|
310 * {@link LinkerServices#asType(MethodHandle, MethodType)} has applied all |
|
311 * custom conversions to a method handle, it still needs to effect |
|
312 * {@link TypeUtilities#isMethodInvocationConvertible(Class, Class) method |
|
313 * invocation conversions} that can usually be automatically applied as per |
|
314 * {@link MethodHandle#asType(MethodType)}. However, sometimes language |
|
315 * runtimes will want to customize even those conversions for their own call |
|
316 * sites. A typical example is allowing unboxing of null return values, |
|
317 * which is by default prohibited by ordinary |
|
318 * {@code MethodHandles.asType()}. In this case, a language runtime can |
|
319 * install its own custom automatic conversion strategy, that can deal with |
|
320 * null values. Note that when the strategy's |
|
321 * {@link MethodTypeConversionStrategy#asType(MethodHandle, MethodType)} |
|
322 * is invoked, the custom language conversions will already have been |
|
323 * applied to the method handle, so by design the difference between the |
|
324 * handle's current method type and the desired final type will always only |
|
325 * be ones that can be subjected to method invocation conversions. The |
|
326 * strategy also doesn't need to invoke a final |
|
327 * {@code MethodHandle.asType()} as that will be done internally as the |
|
328 * final step. |
|
329 * @param autoConversionStrategy the strategy for applying method invocation |
|
330 * conversions for the linker created by this factory. Can be null for no |
|
331 * custom strategy. |
|
332 */ |
|
333 public void setAutoConversionStrategy(final MethodTypeConversionStrategy autoConversionStrategy) { |
|
334 this.autoConversionStrategy = autoConversionStrategy; |
|
335 } |
|
336 |
|
337 /** |
|
338 * Sets a method handle transformer that is supposed to act as the |
|
339 * implementation of |
|
340 * {@link LinkerServices#filterInternalObjects(MethodHandle)} for linker |
|
341 * services of dynamic linkers created by this factory. Some language |
|
342 * runtimes can have internal objects that should not escape their scope. |
|
343 * They can add a transformer here that will modify the method handle so |
|
344 * that any parameters that can receive potentially internal language |
|
345 * runtime objects will have a filter added on them to prevent them from |
|
346 * escaping, potentially by wrapping them. The transformer can also |
|
347 * potentially add an unwrapping filter to the return value. |
|
348 * {@link DefaultInternalObjectFilter} is provided as a convenience class |
|
349 * for easily creating such filtering transformers. |
|
350 * @param internalObjectsFilter a method handle transformer filtering out |
|
351 * internal objects, or null. |
|
352 */ |
|
353 public void setInternalObjectsFilter(final MethodHandleTransformer internalObjectsFilter) { |
|
354 this.internalObjectsFilter = internalObjectsFilter; |
|
355 } |
|
356 |
|
357 /** |
|
358 * Creates a new dynamic linker based on the current configuration. This |
|
359 * method can be invoked more than once to create multiple dynamic linkers. |
|
360 * Automatically discovered linkers are newly instantiated on every |
|
361 * invocation of this method. It is allowed to change the factory's |
|
362 * configuration between invocations. The method is not thread safe. After |
|
363 * invocation, callers can invoke {@link #getAutoLoadingErrors()} to |
|
364 * retrieve a list of {@link ServiceConfigurationError}s that occurred while |
|
365 * trying to load automatically discovered linkers. These are never thrown |
|
366 * from the call to this method as it makes every effort to recover from |
|
367 * them and ignore the failing linkers. |
|
368 * @return the new dynamic Linker |
|
369 */ |
|
370 public DynamicLinker createLinker() { |
|
371 // Treat nulls appropriately |
|
372 if(prioritizedLinkers == null) { |
|
373 prioritizedLinkers = Collections.emptyList(); |
|
374 } |
|
375 if(fallbackLinkers == null) { |
|
376 fallbackLinkers = Collections.singletonList(new BeansLinker()); |
|
377 } |
|
378 |
|
379 // Gather classes of all precreated (prioritized and fallback) linkers. |
|
380 // We'll filter out any discovered linkers of the same class. |
|
381 final Set<Class<? extends GuardingDynamicLinker>> knownLinkerClasses = |
|
382 new HashSet<>(); |
|
383 addClasses(knownLinkerClasses, prioritizedLinkers); |
|
384 addClasses(knownLinkerClasses, fallbackLinkers); |
|
385 |
|
386 final List<GuardingDynamicLinker> discovered = discoverAutoLoadLinkers(); |
|
387 // Now, concatenate ... |
|
388 final List<GuardingDynamicLinker> linkers = |
|
389 new ArrayList<>(prioritizedLinkers.size() + discovered.size() |
|
390 + fallbackLinkers.size()); |
|
391 // ... prioritized linkers, ... |
|
392 linkers.addAll(prioritizedLinkers); |
|
393 // ... filtered discovered linkers, ... |
|
394 for(final GuardingDynamicLinker linker: discovered) { |
|
395 if(!knownLinkerClasses.contains(linker.getClass())) { |
|
396 linkers.add(linker); |
|
397 } |
|
398 } |
|
399 // ... and finally fallback linkers. |
|
400 linkers.addAll(fallbackLinkers); |
|
401 final List<GuardingDynamicLinker> optimized = CompositeTypeBasedGuardingDynamicLinker.optimize(linkers); |
|
402 final GuardingDynamicLinker composite; |
|
403 switch(linkers.size()) { |
|
404 case 0: { |
|
405 composite = (r, s) -> null; // linker that can't link anything |
|
406 break; |
|
407 } |
|
408 case 1: { |
|
409 composite = optimized.get(0); |
|
410 break; |
|
411 } |
|
412 default: { |
|
413 composite = new CompositeGuardingDynamicLinker(optimized); |
|
414 break; |
|
415 } |
|
416 } |
|
417 |
|
418 final List<GuardingTypeConverterFactory> typeConverters = new LinkedList<>(); |
|
419 for(final GuardingDynamicLinker linker: linkers) { |
|
420 if(linker instanceof GuardingTypeConverterFactory) { |
|
421 typeConverters.add((GuardingTypeConverterFactory)linker); |
|
422 } |
|
423 } |
|
424 |
|
425 if(prelinkTransformer == null) { |
|
426 prelinkTransformer = (inv, request, linkerServices) -> inv.asType(linkerServices, request.getCallSiteDescriptor().getMethodType()); |
|
427 } |
|
428 |
|
429 return new DynamicLinker(new LinkerServicesImpl(new TypeConverterFactory(typeConverters, |
|
430 autoConversionStrategy), composite, internalObjectsFilter), prelinkTransformer, |
|
431 syncOnRelink, unstableRelinkThreshold); |
|
432 } |
|
433 |
|
434 /** |
|
435 * Returns a list of {@link ServiceConfigurationError}s that were |
|
436 * encountered while loading automatically discovered linkers during the |
|
437 * last invocation of {@link #createLinker()}. They can be any non-Dynalink |
|
438 * specific service configuration issues, as well as some Dynalink-specific |
|
439 * errors when an exporter that the factory tried to automatically load: |
|
440 * <ul> |
|
441 * <li>did not have the runtime permission named |
|
442 * {@link GuardingDynamicLinkerExporter#AUTOLOAD_PERMISSION_NAME} in a |
|
443 * system with a security manager, or</li> |
|
444 * <li>returned null from {@link GuardingDynamicLinkerExporter#get()}, or</li> |
|
445 * <li>the list returned from {@link GuardingDynamicLinkerExporter#get()} |
|
446 * had a null element.</li> |
|
447 * </ul> |
|
448 * @return an immutable list of encountered |
|
449 * {@link ServiceConfigurationError}s. Can be empty. |
|
450 */ |
|
451 public List<ServiceConfigurationError> getAutoLoadingErrors() { |
|
452 return Collections.unmodifiableList(autoLoadingErrors); |
|
453 } |
|
454 |
|
455 private List<GuardingDynamicLinker> discoverAutoLoadLinkers() { |
|
456 autoLoadingErrors = new LinkedList<>(); |
|
457 final ClassLoader effectiveClassLoader = classLoaderExplicitlySet ? classLoader : getThreadContextClassLoader(); |
|
458 final List<GuardingDynamicLinker> discovered = new LinkedList<>(); |
|
459 try { |
|
460 final ServiceLoader<GuardingDynamicLinkerExporter> linkerLoader = |
|
461 AccessController.doPrivileged((PrivilegedAction<ServiceLoader<GuardingDynamicLinkerExporter>>)()-> { |
|
462 if (effectiveClassLoader == null) { |
|
463 return ServiceLoader.loadInstalled(GuardingDynamicLinkerExporter.class); |
|
464 } |
|
465 return ServiceLoader.load(GuardingDynamicLinkerExporter.class, effectiveClassLoader); |
|
466 }); |
|
467 |
|
468 for(final Iterator<GuardingDynamicLinkerExporter> it = linkerLoader.iterator(); it.hasNext();) { |
|
469 try { |
|
470 final GuardingDynamicLinkerExporter autoLoader = it.next(); |
|
471 try { |
|
472 discovered.addAll(requireNonNullElements( |
|
473 Objects.requireNonNull(autoLoader.get(), |
|
474 ()->(autoLoader.getClass().getName() + " returned null from get()")), |
|
475 ()->(autoLoader.getClass().getName() + " returned a list with at least one null element"))); |
|
476 } catch (final ServiceConfigurationError|VirtualMachineError e) { |
|
477 // Don't wrap a SCE in another SCE. Also, don't ignore |
|
478 // any VME (e.g. StackOverflowError or OutOfMemoryError). |
|
479 throw e; |
|
480 } catch (final Throwable t) { |
|
481 throw new ServiceConfigurationError(t.getMessage(), t); |
|
482 } |
|
483 } catch (final ServiceConfigurationError e) { |
|
484 // Catch SCE with an individual exporter, carry on with it.hasNext(). |
|
485 autoLoadingErrors.add(e); |
|
486 } |
|
487 } |
|
488 } catch (final ServiceConfigurationError e) { |
|
489 // Catch a top-level SCE; one either in ServiceLoader.load(), |
|
490 // ServiceLoader.iterator(), or Iterator.hasNext(). |
|
491 autoLoadingErrors.add(e); |
|
492 } |
|
493 return discovered; |
|
494 } |
|
495 |
|
496 private static ClassLoader getThreadContextClassLoader() { |
|
497 return AccessController.doPrivileged(new PrivilegedAction<ClassLoader>() { |
|
498 @Override |
|
499 public ClassLoader run() { |
|
500 return Thread.currentThread().getContextClassLoader(); |
|
501 } |
|
502 }, GET_CLASS_LOADER_CONTEXT); |
|
503 } |
|
504 |
|
505 private static void addClasses(final Set<Class<? extends GuardingDynamicLinker>> knownLinkerClasses, |
|
506 final List<? extends GuardingDynamicLinker> linkers) { |
|
507 for(final GuardingDynamicLinker linker: linkers) { |
|
508 knownLinkerClasses.add(linker.getClass()); |
|
509 } |
|
510 } |
|
511 |
|
512 private static <T> List<T> copyListRequireNonNullElements(final List<T> list) { |
|
513 if (list == null) { |
|
514 return null; |
|
515 } |
|
516 return new ArrayList<>(requireNonNullElements(list, ()->"List has at least one null element")); |
|
517 } |
|
518 |
|
519 private static <T> List<T> requireNonNullElements(final List<T> list, final Supplier<String> msgSupplier) { |
|
520 for(final T t: list) { |
|
521 Objects.requireNonNull(t, msgSupplier); |
|
522 } |
|
523 return list; |
|
524 } |
|
525 |
|
526 } |