diff -r 2c33418a6d57 -r 83b611b88ac8 jdk/src/java.base/share/classes/java/lang/reflect/Layer.java --- a/jdk/src/java.base/share/classes/java/lang/reflect/Layer.java Thu Apr 06 17:01:03 2017 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,949 +0,0 @@ -/* - * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package java.lang.reflect; - -import java.lang.module.Configuration; -import java.lang.module.ModuleDescriptor; -import java.lang.module.ResolvedModule; -import java.util.ArrayDeque; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Deque; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; -import java.util.Set; -import java.util.concurrent.CopyOnWriteArrayList; -import java.util.function.Function; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -import jdk.internal.loader.ClassLoaderValue; -import jdk.internal.loader.Loader; -import jdk.internal.loader.LoaderPool; -import jdk.internal.misc.SharedSecrets; -import jdk.internal.module.Modules; -import jdk.internal.module.ServicesCatalog; -import sun.security.util.SecurityConstants; - - -/** - * A layer of modules in the Java virtual machine. - * - *

A layer is created from a graph of modules in a {@link Configuration} - * and a function that maps each module to a {@link ClassLoader}. - * Creating a layer informs the Java virtual machine about the classes that - * may be loaded from the modules so that the Java virtual machine knows which - * module that each class is a member of.

- * - *

Creating a layer creates a {@link Module} object for each {@link - * ResolvedModule} in the configuration. For each resolved module that is - * {@link ResolvedModule#reads() read}, the {@code Module} {@link - * Module#canRead reads} the corresponding run-time {@code Module}, which may - * be in the same layer or a {@link #parents() parent} layer.

- * - *

The {@link #defineModulesWithOneLoader defineModulesWithOneLoader} and - * {@link #defineModulesWithManyLoaders defineModulesWithManyLoaders} methods - * provide convenient ways to create a {@code Layer} where all modules are - * mapped to a single class loader or where each module is mapped to its own - * class loader. The {@link #defineModules defineModules} method is for more - * advanced cases where modules are mapped to custom class loaders by means of - * a function specified to the method. Each of these methods has an instance - * and static variant. The instance methods create a layer with the receiver - * as the parent layer. The static methods are for more advanced cases where - * there can be more than one parent layer or where a {@link Layer.Controller - * Controller} is needed to control modules in the layer.

- * - *

A Java virtual machine has at least one non-empty layer, the {@link - * #boot() boot} layer, that is created when the Java virtual machine is - * started. The boot layer contains module {@code java.base} and is the only - * layer in the Java virtual machine with a module named "{@code java.base}". - * The modules in the boot layer are mapped to the bootstrap class loader and - * other class loaders that are - * built-in into the Java virtual machine. The boot layer will often be - * the {@link #parents() parent} when creating additional layers.

- * - *

Each {@code Module} in a layer is created so that it {@link - * Module#isExported(String) exports} and {@link Module#isOpen(String) opens} - * the packages described by its {@link ModuleDescriptor}. Qualified exports - * (where a package is exported to a set of target modules rather than all - * modules) are reified when creating the layer as follows:

- * - * - *

Qualified opens are handled in same way as qualified exports.

- * - *

As when creating a {@code Configuration}, - * {@link ModuleDescriptor#isAutomatic() automatic} modules receive special - * treatment when creating a layer. An automatic module is created in the - * Java virtual machine as a {@code Module} that reads every unnamed {@code - * Module} in the Java virtual machine.

- * - *

Unless otherwise specified, passing a {@code null} argument to a method - * in this class causes a {@link NullPointerException NullPointerException} to - * be thrown.

- * - *

Example usage:

- * - *

This example creates a configuration by resolving a module named - * "{@code myapp}" with the configuration for the boot layer as the parent. It - * then creates a new layer with the modules in this configuration. All modules - * are defined to the same class loader.

- * - *
{@code
- *     ModuleFinder finder = ModuleFinder.of(dir1, dir2, dir3);
- *
- *     Layer parent = Layer.boot();
- *
- *     Configuration cf = parent.configuration().resolve(finder, ModuleFinder.of(), Set.of("myapp"));
- *
- *     ClassLoader scl = ClassLoader.getSystemClassLoader();
- *
- *     Layer layer = parent.defineModulesWithOneLoader(cf, scl);
- *
- *     Class c = layer.findLoader("myapp").loadClass("app.Main");
- * }
- * - * @since 9 - * @spec JPMS - * @see Module#getLayer() - */ - -public final class Layer { - - // the empty Layer - private static final Layer EMPTY_LAYER - = new Layer(Configuration.empty(), List.of(), null); - - // the configuration from which this Layer was created - private final Configuration cf; - - // parent layers, empty in the case of the empty layer - private final List parents; - - // maps module name to jlr.Module - private final Map nameToModule; - - /** - * Creates a new Layer from the modules in the given configuration. - */ - private Layer(Configuration cf, - List parents, - Function clf) - { - this.cf = cf; - this.parents = parents; // no need to do defensive copy - - Map map; - if (parents.isEmpty()) { - map = Collections.emptyMap(); - } else { - map = Module.defineModules(cf, clf, this); - } - this.nameToModule = map; // no need to do defensive copy - } - - /** - * Controls a layer. The static methods defined by {@link Layer} to create - * module layers return a {@code Controller} that can be used to control - * modules in the layer. - * - *

Unless otherwise specified, passing a {@code null} argument to a - * method in this class causes a {@link NullPointerException - * NullPointerException} to be thrown.

- * - * @apiNote Care should be taken with {@code Controller} objects, they - * should never be shared with untrusted code. - * - * @since 9 - * @spec JPMS - */ - public static final class Controller { - private final Layer layer; - - Controller(Layer layer) { - this.layer = layer; - } - - /** - * Returns the layer that this object controls. - * - * @return the layer - */ - public Layer layer() { - return layer; - } - - private void ensureInLayer(Module source) { - if (source.getLayer() != layer) - throw new IllegalArgumentException(source + " not in layer"); - } - - - /** - * Updates module {@code source} in the layer to read module - * {@code target}. This method is a no-op if {@code source} already - * reads {@code target}. - * - * @implNote Read edges added by this method are weak - * and do not prevent {@code target} from being GC'ed when {@code source} - * is strongly reachable. - * - * @param source - * The source module - * @param target - * The target module to read - * - * @return This controller - * - * @throws IllegalArgumentException - * If {@code source} is not in the layer - * - * @see Module#addReads - */ - public Controller addReads(Module source, Module target) { - ensureInLayer(source); - Objects.requireNonNull(target); - Modules.addReads(source, target); - return this; - } - - /** - * Updates module {@code source} in the layer to open a package to - * module {@code target}. This method is a no-op if {@code source} - * already opens the package to at least {@code target}. - * - * @param source - * The source module - * @param pn - * The package name - * @param target - * The target module to read - * - * @return This controller - * - * @throws IllegalArgumentException - * If {@code source} is not in the layer or the package is not - * in the source module - * - * @see Module#addOpens - */ - public Controller addOpens(Module source, String pn, Module target) { - ensureInLayer(source); - Objects.requireNonNull(pn); - Objects.requireNonNull(target); - Modules.addOpens(source, pn, target); - return this; - } - } - - - /** - * Creates a new layer, with this layer as its parent, by defining the - * modules in the given {@code Configuration} to the Java virtual machine. - * This method creates one class loader and defines all modules to that - * class loader. The {@link ClassLoader#getParent() parent} of each class - * loader is the given parent class loader. This method works exactly as - * specified by the static {@link - * #defineModulesWithOneLoader(Configuration,List,ClassLoader) - * defineModulesWithOneLoader} method when invoked with this layer as the - * parent. In other words, if this layer is {@code thisLayer} then this - * method is equivalent to invoking: - *
 {@code
-     *     Layer.defineModulesWithOneLoader(cf, List.of(thisLayer), parentLoader).layer();
-     * }
- * - * @param cf - * The configuration for the layer - * @param parentLoader - * The parent class loader for the class loader created by this - * method; may be {@code null} for the bootstrap class loader - * - * @return The newly created layer - * - * @throws IllegalArgumentException - * If the parent of the given configuration is not the configuration - * for this layer - * @throws LayerInstantiationException - * If the layer cannot be created for any of the reasons specified - * by the static {@code defineModulesWithOneLoader} method - * @throws SecurityException - * If {@code RuntimePermission("createClassLoader")} or - * {@code RuntimePermission("getClassLoader")} is denied by - * the security manager - * - * @see #findLoader - */ - public Layer defineModulesWithOneLoader(Configuration cf, - ClassLoader parentLoader) { - return defineModulesWithOneLoader(cf, List.of(this), parentLoader).layer(); - } - - - /** - * Creates a new layer, with this layer as its parent, by defining the - * modules in the given {@code Configuration} to the Java virtual machine. - * Each module is defined to its own {@link ClassLoader} created by this - * method. The {@link ClassLoader#getParent() parent} of each class loader - * is the given parent class loader. This method works exactly as specified - * by the static {@link - * #defineModulesWithManyLoaders(Configuration,List,ClassLoader) - * defineModulesWithManyLoaders} method when invoked with this layer as the - * parent. In other words, if this layer is {@code thisLayer} then this - * method is equivalent to invoking: - *
 {@code
-     *     Layer.defineModulesWithManyLoaders(cf, List.of(thisLayer), parentLoader).layer();
-     * }
- * - * @param cf - * The configuration for the layer - * @param parentLoader - * The parent class loader for each of the class loaders created by - * this method; may be {@code null} for the bootstrap class loader - * - * @return The newly created layer - * - * @throws IllegalArgumentException - * If the parent of the given configuration is not the configuration - * for this layer - * @throws LayerInstantiationException - * If the layer cannot be created for any of the reasons specified - * by the static {@code defineModulesWithManyLoaders} method - * @throws SecurityException - * If {@code RuntimePermission("createClassLoader")} or - * {@code RuntimePermission("getClassLoader")} is denied by - * the security manager - * - * @see #findLoader - */ - public Layer defineModulesWithManyLoaders(Configuration cf, - ClassLoader parentLoader) { - return defineModulesWithManyLoaders(cf, List.of(this), parentLoader).layer(); - } - - - /** - * Creates a new layer, with this layer as its parent, by defining the - * modules in the given {@code Configuration} to the Java virtual machine. - * Each module is mapped, by name, to its class loader by means of the - * given function. This method works exactly as specified by the static - * {@link #defineModules(Configuration,List,Function) defineModules} - * method when invoked with this layer as the parent. In other words, if - * this layer is {@code thisLayer} then this method is equivalent to - * invoking: - *
 {@code
-     *     Layer.defineModules(cf, List.of(thisLayer), clf).layer();
-     * }
- * - * @param cf - * The configuration for the layer - * @param clf - * The function to map a module name to a class loader - * - * @return The newly created layer - * - * @throws IllegalArgumentException - * If the parent of the given configuration is not the configuration - * for this layer - * @throws LayerInstantiationException - * If the layer cannot be created for any of the reasons specified - * by the static {@code defineModules} method - * @throws SecurityException - * If {@code RuntimePermission("getClassLoader")} is denied by - * the security manager - */ - public Layer defineModules(Configuration cf, - Function clf) { - return defineModules(cf, List.of(this), clf).layer(); - } - - /** - * Creates a new layer by defining the modules in the given {@code - * Configuration} to the Java virtual machine. This method creates one - * class loader and defines all modules to that class loader. - * - *

The class loader created by this method implements direct - * delegation when loading types from modules. When its {@link - * ClassLoader#loadClass(String, boolean) loadClass} method is invoked to - * load a class then it uses the package name of the class to map it to a - * module. This may be a module in this layer and hence defined to the same - * class loader. It may be a package in a module in a parent layer that is - * exported to one or more of the modules in this layer. The class - * loader delegates to the class loader of the module, throwing {@code - * ClassNotFoundException} if not found by that class loader. - * When {@code loadClass} is invoked to load classes that do not map to a - * module then it delegates to the parent class loader.

- * - *

Attempting to create a layer with all modules defined to the same - * class loader can fail for the following reasons: - * - *

    - * - *
  • Overlapping packages: Two or more modules in the - * configuration have the same package.

  • - * - *
  • Split delegation: The resulting class loader would - * need to delegate to more than one class loader in order to load types - * in a specific package.

  • - * - *
- * - *

In addition, a layer cannot be created if the configuration contains - * a module named "{@code java.base}", or a module contains a package named - * "{@code java}" or a package with a name starting with "{@code java.}".

- * - *

If there is a security manager then the class loader created by - * this method will load classes and resources with privileges that are - * restricted by the calling context of this method.

- * - * @param cf - * The configuration for the layer - * @param parentLayers - * The list of parent layers in search order - * @param parentLoader - * The parent class loader for the class loader created by this - * method; may be {@code null} for the bootstrap class loader - * - * @return A controller that controls the newly created layer - * - * @throws IllegalArgumentException - * If the parent configurations do not match the configuration of - * the parent layers, including order - * @throws LayerInstantiationException - * If all modules cannot be defined to the same class loader for any - * of the reasons listed above - * @throws SecurityException - * If {@code RuntimePermission("createClassLoader")} or - * {@code RuntimePermission("getClassLoader")} is denied by - * the security manager - * - * @see #findLoader - */ - public static Controller defineModulesWithOneLoader(Configuration cf, - List parentLayers, - ClassLoader parentLoader) - { - List parents = new ArrayList<>(parentLayers); - checkConfiguration(cf, parents); - - checkCreateClassLoaderPermission(); - checkGetClassLoaderPermission(); - - try { - Loader loader = new Loader(cf.modules(), parentLoader); - loader.initRemotePackageMap(cf, parents); - Layer layer = new Layer(cf, parents, mn -> loader); - return new Controller(layer); - } catch (IllegalArgumentException | IllegalStateException e) { - throw new LayerInstantiationException(e.getMessage()); - } - } - - /** - * Creates a new layer by defining the modules in the given {@code - * Configuration} to the Java virtual machine. Each module is defined to - * its own {@link ClassLoader} created by this method. The {@link - * ClassLoader#getParent() parent} of each class loader is the given parent - * class loader. - * - *

The class loaders created by this method implement direct - * delegation when loading types from modules. When {@link - * ClassLoader#loadClass(String, boolean) loadClass} method is invoked to - * load a class then it uses the package name of the class to map it to a - * module. The package may be in the module defined to the class loader. - * The package may be exported by another module in this layer to the - * module defined to the class loader. It may be in a package exported by a - * module in a parent layer. The class loader delegates to the class loader - * of the module, throwing {@code ClassNotFoundException} if not found by - * that class loader. - * When {@code loadClass} is invoked to load classes that do not map to a - * module then it delegates to the parent class loader.

- * - *

If there is a security manager then the class loaders created by - * this method will load classes and resources with privileges that are - * restricted by the calling context of this method.

- * - * @param cf - * The configuration for the layer - * @param parentLayers - * The list of parent layers in search order - * @param parentLoader - * The parent class loader for each of the class loaders created by - * this method; may be {@code null} for the bootstrap class loader - * - * @return A controller that controls the newly created layer - * - * @throws IllegalArgumentException - * If the parent configurations do not match the configuration of - * the parent layers, including order - * @throws LayerInstantiationException - * If the layer cannot be created because the configuration contains - * a module named "{@code java.base}" or a module contains a package - * named "{@code java}" or a package with a name starting with - * "{@code java.}" - * - * @throws SecurityException - * If {@code RuntimePermission("createClassLoader")} or - * {@code RuntimePermission("getClassLoader")} is denied by - * the security manager - * - * @see #findLoader - */ - public static Controller defineModulesWithManyLoaders(Configuration cf, - List parentLayers, - ClassLoader parentLoader) - { - List parents = new ArrayList<>(parentLayers); - checkConfiguration(cf, parents); - - checkCreateClassLoaderPermission(); - checkGetClassLoaderPermission(); - - LoaderPool pool = new LoaderPool(cf, parents, parentLoader); - try { - Layer layer = new Layer(cf, parents, pool::loaderFor); - return new Controller(layer); - } catch (IllegalArgumentException | IllegalStateException e) { - throw new LayerInstantiationException(e.getMessage()); - } - } - - /** - * Creates a new layer by defining the modules in the given {@code - * Configuration} to the Java virtual machine. The given function maps each - * module in the configuration, by name, to a class loader. Creating the - * layer informs the Java virtual machine about the classes that may be - * loaded so that the Java virtual machine knows which module that each - * class is a member of. - * - *

The class loader delegation implemented by the class loaders must - * respect module readability. The class loaders should be - * {@link ClassLoader#registerAsParallelCapable parallel-capable} so as to - * avoid deadlocks during class loading. In addition, the entity creating - * a new layer with this method should arrange that the class loaders be - * ready to load from these modules before there are any attempts to load - * classes or resources.

- * - *

Creating a {@code Layer} can fail for the following reasons:

- * - *
    - * - *
  • Two or more modules with the same package are mapped to the - * same class loader.

  • - * - *
  • A module is mapped to a class loader that already has a - * module of the same name defined to it.

  • - * - *
  • A module is mapped to a class loader that has already - * defined types in any of the packages in the module.

  • - * - *
- * - *

In addition, a layer cannot be created if the configuration contains - * a module named "{@code java.base}", a configuration contains a module - * with a package named "{@code java}" or a package name starting with - * "{@code java.}" and the module is mapped to a class loader other than - * the {@link ClassLoader#getPlatformClassLoader() platform class loader}, - * or the function to map a module name to a class loader returns - * {@code null}.

- * - *

If the function to map a module name to class loader throws an error - * or runtime exception then it is propagated to the caller of this method. - *

- * - * @apiNote It is implementation specific as to whether creating a Layer - * with this method is an atomic operation or not. Consequentially it is - * possible for this method to fail with some modules, but not all, defined - * to the Java virtual machine. - * - * @param cf - * The configuration for the layer - * @param parentLayers - * The list of parent layers in search order - * @param clf - * The function to map a module name to a class loader - * - * @return A controller that controls the newly created layer - * - * @throws IllegalArgumentException - * If the parent configurations do not match the configuration of - * the parent layers, including order - * @throws LayerInstantiationException - * If creating the layer fails for any of the reasons listed above - * @throws SecurityException - * If {@code RuntimePermission("getClassLoader")} is denied by - * the security manager - */ - public static Controller defineModules(Configuration cf, - List parentLayers, - Function clf) - { - List parents = new ArrayList<>(parentLayers); - checkConfiguration(cf, parents); - Objects.requireNonNull(clf); - - checkGetClassLoaderPermission(); - - // The boot layer is checked during module system initialization - if (boot() != null) { - checkForDuplicatePkgs(cf, clf); - } - - try { - Layer layer = new Layer(cf, parents, clf); - return new Controller(layer); - } catch (IllegalArgumentException | IllegalStateException e) { - throw new LayerInstantiationException(e.getMessage()); - } - } - - - /** - * Checks that the parent configurations match the configuration of - * the parent layers. - */ - private static void checkConfiguration(Configuration cf, - List parentLayers) - { - Objects.requireNonNull(cf); - - List parentConfigurations = cf.parents(); - if (parentLayers.size() != parentConfigurations.size()) - throw new IllegalArgumentException("wrong number of parents"); - - int index = 0; - for (Layer parent : parentLayers) { - if (parent.configuration() != parentConfigurations.get(index)) { - throw new IllegalArgumentException( - "Parent of configuration != configuration of this Layer"); - } - index++; - } - } - - private static void checkCreateClassLoaderPermission() { - SecurityManager sm = System.getSecurityManager(); - if (sm != null) - sm.checkPermission(SecurityConstants.CREATE_CLASSLOADER_PERMISSION); - } - - private static void checkGetClassLoaderPermission() { - SecurityManager sm = System.getSecurityManager(); - if (sm != null) - sm.checkPermission(SecurityConstants.GET_CLASSLOADER_PERMISSION); - } - - /** - * Checks a configuration and the module-to-loader mapping to ensure that - * no two modules mapped to the same class loader have the same package. - * It also checks that no two automatic modules have the same package. - * - * @throws LayerInstantiationException - */ - private static void checkForDuplicatePkgs(Configuration cf, - Function clf) - { - // HashMap allows null keys - Map> loaderToPackages = new HashMap<>(); - for (ResolvedModule resolvedModule : cf.modules()) { - ModuleDescriptor descriptor = resolvedModule.reference().descriptor(); - ClassLoader loader = clf.apply(descriptor.name()); - - Set loaderPackages - = loaderToPackages.computeIfAbsent(loader, k -> new HashSet<>()); - - for (String pkg : descriptor.packages()) { - boolean added = loaderPackages.add(pkg); - if (!added) { - throw fail("More than one module with package %s mapped" + - " to the same class loader", pkg); - } - } - } - } - - /** - * Creates a LayerInstantiationException with the a message formatted from - * the given format string and arguments. - */ - private static LayerInstantiationException fail(String fmt, Object ... args) { - String msg = String.format(fmt, args); - return new LayerInstantiationException(msg); - } - - - /** - * Returns the configuration for this layer. - * - * @return The configuration for this layer - */ - public Configuration configuration() { - return cf; - } - - - /** - * Returns the list of this layer's parents unless this is the - * {@linkplain #empty empty layer}, which has no parents and so an - * empty list is returned. - * - * @return The list of this layer's parents - */ - public List parents() { - return parents; - } - - - /** - * Returns an ordered stream of layers. The first element is is this layer, - * the remaining elements are the parent layers in DFS order. - * - * @implNote For now, the assumption is that the number of elements will - * be very low and so this method does not use a specialized spliterator. - */ - Stream layers() { - List allLayers = this.allLayers; - if (allLayers != null) - return allLayers.stream(); - - allLayers = new ArrayList<>(); - Set visited = new HashSet<>(); - Deque stack = new ArrayDeque<>(); - visited.add(this); - stack.push(this); - - while (!stack.isEmpty()) { - Layer layer = stack.pop(); - allLayers.add(layer); - - // push in reverse order - for (int i = layer.parents.size() - 1; i >= 0; i--) { - Layer parent = layer.parents.get(i); - if (!visited.contains(parent)) { - visited.add(parent); - stack.push(parent); - } - } - } - - this.allLayers = allLayers = Collections.unmodifiableList(allLayers); - return allLayers.stream(); - } - - private volatile List allLayers; - - /** - * Returns the set of the modules in this layer. - * - * @return A possibly-empty unmodifiable set of the modules in this layer - */ - public Set modules() { - Set modules = this.modules; - if (modules == null) { - this.modules = modules = - Collections.unmodifiableSet(new HashSet<>(nameToModule.values())); - } - return modules; - } - - private volatile Set modules; - - - /** - * Returns the module with the given name in this layer, or if not in this - * layer, the {@linkplain #parents parent} layers. Finding a module in - * parent layers is equivalent to invoking {@code findModule} on each - * parent, in search order, until the module is found or all parents have - * been searched. In a tree of layers then this is equivalent to - * a depth-first search. - * - * @param name - * The name of the module to find - * - * @return The module with the given name or an empty {@code Optional} - * if there isn't a module with this name in this layer or any - * parent layer - */ - public Optional findModule(String name) { - Objects.requireNonNull(name); - if (this == EMPTY_LAYER) - return Optional.empty(); - Module m = nameToModule.get(name); - if (m != null) - return Optional.of(m); - - return layers() - .skip(1) // skip this layer - .map(l -> l.nameToModule) - .filter(map -> map.containsKey(name)) - .map(map -> map.get(name)) - .findAny(); - } - - - /** - * Returns the {@code ClassLoader} for the module with the given name. If - * a module of the given name is not in this layer then the {@link #parents - * parent} layers are searched in the manner specified by {@link - * #findModule(String) findModule}. - * - *

If there is a security manager then its {@code checkPermission} - * method is called with a {@code RuntimePermission("getClassLoader")} - * permission to check that the caller is allowed to get access to the - * class loader.

- * - * @apiNote This method does not return an {@code Optional} - * because `null` must be used to represent the bootstrap class loader. - * - * @param name - * The name of the module to find - * - * @return The ClassLoader that the module is defined to - * - * @throws IllegalArgumentException if a module of the given name is not - * defined in this layer or any parent of this layer - * - * @throws SecurityException if denied by the security manager - */ - public ClassLoader findLoader(String name) { - Optional om = findModule(name); - - // can't use map(Module::getClassLoader) as class loader can be null - if (om.isPresent()) { - return om.get().getClassLoader(); - } else { - throw new IllegalArgumentException("Module " + name - + " not known to this layer"); - } - } - - /** - * Returns a string describing this layer. - * - * @return A possibly empty string describing this layer - */ - @Override - public String toString() { - return modules().stream() - .map(Module::getName) - .collect(Collectors.joining(", ")); - } - - /** - * Returns the empty layer. There are no modules in the empty - * layer. It has no parents. - * - * @return The empty layer - */ - public static Layer empty() { - return EMPTY_LAYER; - } - - - /** - * Returns the boot layer. The boot layer contains at least one module, - * {@code java.base}. Its parent is the {@link #empty() empty} layer. - * - * @apiNote This method returns {@code null} during startup and before - * the boot layer is fully initialized. - * - * @return The boot layer - */ - public static Layer boot() { - return SharedSecrets.getJavaLangAccess().getBootLayer(); - } - - - /** - * Returns the ServicesCatalog for this Layer, creating it if not - * already created. - */ - ServicesCatalog getServicesCatalog() { - ServicesCatalog servicesCatalog = this.servicesCatalog; - if (servicesCatalog != null) - return servicesCatalog; - - synchronized (this) { - servicesCatalog = this.servicesCatalog; - if (servicesCatalog == null) { - servicesCatalog = ServicesCatalog.create(); - nameToModule.values().forEach(servicesCatalog::register); - this.servicesCatalog = servicesCatalog; - } - } - - return servicesCatalog; - } - - private volatile ServicesCatalog servicesCatalog; - - - /** - * Record that this layer has at least one module defined to the given - * class loader. - */ - void bindToLoader(ClassLoader loader) { - // CLV.computeIfAbsent(loader, (cl, clv) -> new CopyOnWriteArrayList<>()) - List list = CLV.get(loader); - if (list == null) { - list = new CopyOnWriteArrayList<>(); - List previous = CLV.putIfAbsent(loader, list); - if (previous != null) list = previous; - } - list.add(this); - } - - /** - * Returns a stream of the layers that have at least one module defined to - * the given class loader. - */ - static Stream layers(ClassLoader loader) { - List list = CLV.get(loader); - if (list != null) { - return list.stream(); - } else { - return Stream.empty(); - } - } - - // the list of layers with modules defined to a class loader - private static final ClassLoaderValue> CLV = new ClassLoaderValue<>(); -}