/* * Copyright (c) 2014, 2016, 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 that is the {@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 modules so that the Java virtual machine knows which * module that each class is a member of. Each layer, except the {@link * #empty() empty} layer, has at least one {@link #parents() parent}.
* *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 parent layer. The {@code Module} {@link * Module#isExported(String) exports} the packages described by its {@link * ModuleDescriptor}.
* *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 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.
* *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.
* *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() * .resolveRequires(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 * @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
{@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 all modules cannot be defined to the same class loader for any * of the reasons listed above or the layer cannot be created because * the configuration contains a module named "{@code java.base}" or * a module with a package name starting with "{@code java.}" * @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 because the configuration contains * a module named "{@code java.base}" or a module with a package * name starting with "{@code java.}" * @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 creating the {@code Layer} fails for any of the reasons * listed above, the layer cannot be created because the * configuration contains a module named "{@code java.base}", * a module with a package name starting with "{@code java.}" 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} * @throws SecurityException * If {@code RuntimePermission("getClassLoader")} is denied by * the security manager */ public Layer defineModules(Configuration cf, Function
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.
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 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 or the layer cannot be created because * the configuration contains a module named "{@code java.base}" or * a module with a package 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 defineModulesWithOneLoader(Configuration cf, ListThe 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 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 with a package * 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, ListCreating 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.
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 Java virtual machine. * * @param cf * The configuration for the layer * @param parentLayers * The list 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 {@code Layer} fails for any of the reasons * listed above, the layer cannot be created because the * configuration contains a module named "{@code java.base}", * a module with a package name starting with "{@code java.}" 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} * @throws SecurityException * If {@code RuntimePermission("getClassLoader")} is denied by * the security manager */ public static Controller defineModules(Configuration cf, ListIf 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