/* * Copyright (c) 2014, 2018, 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.module; import java.io.PrintStream; import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Deque; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Objects; import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; import java.util.stream.Stream; import jdk.internal.misc.VM; import jdk.internal.module.ModuleReferenceImpl; import jdk.internal.module.ModuleTarget; import jdk.internal.vm.annotation.Stable; /** * A configuration that is the result of * resolution or resolution with * service binding. * *
A configuration encapsulates the readability graph that is the * output of resolution. A readability graph is a directed graph whose vertices * are of type {@link ResolvedModule} and the edges represent the readability * amongst the modules. {@code Configuration} defines the {@link #modules() * modules()} method to get the set of resolved modules in the graph. {@code * ResolvedModule} defines the {@link ResolvedModule#reads() reads()} method to * get the set of modules that a resolved module reads. The modules that are * read may be in the same configuration or may be in {@link #parents() parent} * configurations.
* *Configuration defines the {@link #resolve(ModuleFinder,List,ModuleFinder,Collection) * resolve} method to resolve a collection of root modules, and the {@link * #resolveAndBind(ModuleFinder,List,ModuleFinder,Collection) resolveAndBind} * method to do resolution with service binding. There are instance and * static variants of both methods. The instance methods create a configuration * with the receiver as the parent configuration. The static methods are for * more advanced cases where there can be more than one parent configuration.
* *Each {@link java.lang.ModuleLayer layer} of modules in the Java virtual * machine is created from a configuration. The configuration for the {@link * java.lang.ModuleLayer#boot() boot} layer is obtained by invoking {@code * ModuleLayer.boot().configuration()}. The configuration for the boot layer * will often be the parent when creating new configurations.
* *The following example uses the {@link * #resolve(ModuleFinder,ModuleFinder,Collection) resolve} method to resolve a * module named myapp with the configuration for the boot layer as the * parent configuration. It prints the name of each resolved module and the * names of the modules that each module reads.
* *{@code * ModuleFinder finder = ModuleFinder.of(dir1, dir2, dir3); * * Configuration parent = ModuleLayer.boot().configuration(); * * Configuration cf = parent.resolve(finder, ModuleFinder.of(), Set.of("myapp")); * cf.modules().forEach(m -> { * System.out.format("%s -> %s%n", * m.name(), * m.reads().stream() * .map(ResolvedModule::name) * .collect(Collectors.joining(", "))); * }); * }* * @since 9 * @spec JPMS * @see java.lang.ModuleLayer */ public final class Configuration { // @see Configuration#empty() // EMPTY_CONFIGURATION may be initialized from the CDS archive. private static @Stable Configuration EMPTY_CONFIGURATION; static { // Initialize EMPTY_CONFIGURATION from the archive. VM.initializeFromArchive(Configuration.class); // Create a new empty Configuration if there is no archived version. if (EMPTY_CONFIGURATION == null) { EMPTY_CONFIGURATION = new Configuration(); } } // parent configurations, in search order private final List
{@code * Configuration.resolve(before, List.of(cf), after, roots); * }* * @param before * The before module finder to find modules * @param after * The after module finder to locate modules when not * located by the {@code before} module finder or in parent * configurations * @param roots * The possibly-empty collection of module names of the modules * to resolve * * @return The configuration that is the result of resolving the given * root modules * * @throws FindException * If resolution fails for any of the observability-related reasons * specified by the static {@code resolve} method * @throws ResolutionException * If resolution fails any of the consistency checks specified by * the static {@code resolve} method * @throws SecurityException * If locating a module is denied by the security manager */ public Configuration resolve(ModuleFinder before, ModuleFinder after, Collection
{@code * Configuration.resolveAndBind(before, List.of(cf), after, roots); * }* * * @param before * The before module finder to find modules * @param after * The after module finder to locate modules when not * located by the {@code before} module finder or in parent * configurations * @param roots * The possibly-empty collection of module names of the modules * to resolve * * @return The configuration that is the result of resolving, with service * binding, the given root modules * * @throws FindException * If resolution fails for any of the observability-related reasons * specified by the static {@code resolve} method * @throws ResolutionException * If resolution fails any of the consistency checks specified by * the static {@code resolve} method * @throws SecurityException * If locating a module is denied by the security manager */ public Configuration resolveAndBind(ModuleFinder before, ModuleFinder after, Collection
Each root module is located using the given {@code before} module * finder. If a module is not found then it is located in the parent * configuration as if by invoking the {@link #findModule(String) * findModule} method on each parent in iteration order. If not found then * the module is located using the given {@code after} module finder. The * same search order is used to locate transitive dependences. Root modules * or dependences that are located in a parent configuration are resolved * no further and are not included in the resulting configuration.
* *When all modules have been enumerated then a readability graph * is computed, and in conjunction with the module exports and service use, * checked for consistency.
* *Resolution may fail with {@code FindException} for the following * observability-related reasons:
* *A root module, or a direct or transitive dependency, is not * found.
An error occurs when attempting to find a module. * Possible errors include I/O errors, errors detected parsing a module * descriptor ({@code module-info.class}) or two versions of the same * module are found in the same directory.
Resolution may fail with {@code ResolutionException} if any of the * following consistency checks fail:
* *A cycle is detected, say where module {@code m1} requires * module {@code m2} and {@code m2} requires {@code m1}.
A module reads two or more modules with the same name. This * includes the case where a module reads another with the same name as * itself.
Two or more modules in the configuration export the same * package to a module that reads both. This includes the case where a * module {@code M} containing package {@code p} reads another module * that exports {@code p} to {@code M}.
A module {@code M} declares that it "{@code uses p.S}" or * "{@code provides p.S with ...}" but package {@code p} is neither in * module {@code M} nor exported to {@code M} by any module that * {@code M} reads.
This method works exactly as specified by {@link * #resolve(ModuleFinder,List,ModuleFinder,Collection) * resolve} except that the graph of resolved modules is augmented * with modules induced by the service-use dependence relation.
* *More specifically, the root modules are * resolved as if by calling {@code resolve}. The resolved modules, and * all modules in the parent configurations, with {@link ModuleDescriptor#uses() * service dependences} are then examined. All modules found by the given * module finders that {@link ModuleDescriptor#provides() provide} an * implementation of one or more of the service types are added to the * module graph and then resolved as if by calling the {@code * resolve} method. Adding modules to the module graph may introduce new * service-use dependences and so the process works iteratively until no * more modules are added.
* *As service binding involves resolution then it may fail with {@code * FindException} or {@code ResolutionException} for exactly the same * reasons specified in {@code resolve}.
* * @param before * The before module finder to find modules * @param parents * The list parent configurations in search order * @param after * The after module finder to locate modules when not * located by the {@code before} module finder or in parent * configurations * @param roots * The possibly-empty collection of module names of the modules * to resolve * * @return The configuration that is the result of resolving, with service * binding, the given root modules * * @throws FindException * If resolution fails for any of the observability-related reasons * specified by the static {@code resolve} method * @throws ResolutionException * If resolution fails any of the consistency checks specified by * the static {@code resolve} method * @throws IllegalArgumentException * If the list of parents is empty, or the list has two or more * parents with modules for different target operating systems, * architectures, or versions * @throws SecurityException * If locating a module is denied by the security manager */ public static Configuration resolveAndBind(ModuleFinder before, List