src/jdk.dynalink/share/classes/jdk/dynalink/DynamicLinkerFactory.java
changeset 47216 71c04702a3d5
parent 36517 41a1c20eb619
child 50695 36ca515343e0
equal deleted inserted replaced
47215:4ebc2e2fb97c 47216:71c04702a3d5
       
     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 }