< prev index next >

src/java.base/share/classes/java/lang/module/Configuration.java

Print this page

        

*** 1,7 **** /* ! * 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 --- 1,7 ---- /* ! * 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
*** 40,179 **** import java.util.Set; import java.util.stream.Collectors; import java.util.stream.Stream; /** ! * The configuration that is the result of resolution or resolution with ! * service binding. ! * ! * <h2><a name="resolution">Resolution</a></h2> ! * ! * <p> Resolution is the process of computing the transitive closure of a set ! * of root modules over a set of observable modules by resolving the ! * dependences expressed by {@code requires} clauses. ! * ! * The <em>dependence graph</em> is augmented with edges that take account of ! * implicitly declared dependences ({@code requires transitive}) to create a ! * <em>readability graph</em>. A {@code Configuration} encapsulates the ! * resulting graph of {@link ResolvedModule resolved modules}. ! * ! * <p> Suppose we have the following observable modules: </p> ! * <pre> {@code ! * module m1 { requires m2; } ! * module m2 { requires transitive m3; } ! * module m3 { } ! * module m4 { } ! * } </pre> ! * ! * <p> If the module {@code m1} is resolved then the resulting configuration ! * contains three modules ({@code m1}, {@code m2}, {@code m3}). The edges in ! * its readability graph are: </p> ! * <pre> {@code ! * m1 --> m2 (meaning m1 reads m2) ! * m1 --> m3 ! * m2 --> m3 ! * } </pre> ! * ! * <p> Resolution is an additive process. When computing the transitive closure ! * then the dependence relation may include dependences on modules in parent ! * configurations. The result is a <em>relative configuration</em> that is ! * relative to one or more parent configurations and where the readability graph ! * may have edges from modules in the configuration to modules in parent ! * configurations. ! * ! * </p> ! * ! * <p> Suppose we have the following observable modules: </p> ! * <pre> {@code ! * module m1 { requires m2; requires java.xml; } ! * module m2 { } ! * } </pre> ! * ! * <p> If module {@code m1} is resolved with the configuration for the {@link ! * java.lang.reflect.Layer#boot() boot} layer as the parent then the resulting ! * configuration contains two modules ({@code m1}, {@code m2}). The edges in ! * its readability graph are: ! * <pre> {@code ! * m1 --> m2 ! * m1 --> java.xml ! * } </pre> ! * where module {@code java.xml} is in the parent configuration. For ! * simplicity, this example omits the implicitly declared dependence on the ! * {@code java.base} module. ! * ! * <a name="automaticmoduleresolution"></a> ! * <p> {@link ModuleDescriptor#isAutomatic() Automatic} modules receive special ! * treatment during resolution. Each automatic module is resolved so that it ! * reads all other modules in the configuration and all parent configurations. ! * Each automatic module is also resolved as if it {@code requires transitive} ! * all other automatic modules in the configuration (and all automatic modules ! * in parent configurations). </p> ! ! * <h2><a name="servicebinding">Service binding</a></h2> ! * ! * <p> Service binding is the process of augmenting a graph of resolved modules ! * from the set of observable modules induced by the service-use dependence ! * ({@code uses} and {@code provides} clauses). Any module that was not ! * previously in the graph requires resolution to compute its transitive ! * closure. Service binding is an iterative process in that adding a module ! * that satisfies some service-use dependence may introduce new service-use ! * dependences. </p> ! * ! * <p> Suppose we have the following observable modules: </p> ! * <pre> {@code ! * module m1 { exports p; uses p.S; } ! * module m2 { requires m1; provides p.S with p2.S2; } ! * module m3 { requires m1; requires m4; provides p.S with p3.S3; } ! * module m4 { } ! * } </pre> ! * ! * <p> If the module {@code m1} is resolved then the resulting graph of modules ! * has one module ({@code m1}). If the graph is augmented with modules induced ! * by the service-use dependence relation then the configuration will contain ! * four modules ({@code m1}, {@code m2}, {@code m3}, {@code m4}). The edges in ! * its readability graph are: </p> ! * <pre> {@code ! * m2 --> m1 ! * m3 --> m1 ! * m3 --> m4 ! * } </pre> ! * <p> The edges in the conceptual service-use graph are: </p> ! * <pre> {@code ! * m1 --> m2 (meaning m1 uses a service that is provided by m2) ! * m1 --> m3 ! * } </pre> ! * ! * <p> If this configuration is instantiated as a {@code Layer}, and if code in ! * module {@code m1} uses {@link java.util.ServiceLoader ServiceLoader} to ! * iterate over implementations of {@code p.S.class}, then it will iterate over ! * an instance of {@code p2.S2} and {@code p3.S3}. </p> * * <h3> Example </h3> * ! * <p> The following example uses the {@code resolveRequires} method to resolve ! * a module named <em>myapp</em> 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. </p> * * <pre>{@code * ModuleFinder finder = ModuleFinder.of(dir1, dir2, dir3); * * Configuration parent = Layer.boot().configuration(); * ! * Configuration cf = parent.resolveRequires(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(", "))); * }); * }</pre> * * @since 9 * @see java.lang.reflect.Layer */ public final class Configuration { // @see Configuration#empty() --- 40,102 ---- import java.util.Set; import java.util.stream.Collectors; import java.util.stream.Stream; /** ! * A configuration that is the result of <a href="package-summary.html#resolution"> ! * resolution</a> or resolution with <a href="package-summary.html#servicebinding"> ! * service binding</a>. ! * ! * <p> A configuration encapsulates the <em>readability graph</em> that is the ! * output of resolution. A readability graph is a directed graph where the nodes ! * 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. </p> ! * ! * <p> 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. </p> ! * ! * <p> Each {@link java.lang.reflect.Layer layer} of modules in the Java virtual ! * machine is created from a configuration. The configuration for the {@link ! * java.lang.reflect.Layer#boot() boot} layer is obtained by invoking {@code ! * Layer.boot().configuration()}. The configuration for the boot layer will ! * often be the parent when creating new configurations. </p> * * <h3> Example </h3> * ! * <p> The following example uses the {@link ! * #resolve(ModuleFinder,ModuleFinder,Collection) resolve} method to resolve a ! * module named <em>myapp</em> 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. </p> * * <pre>{@code * ModuleFinder finder = ModuleFinder.of(dir1, dir2, dir3); * * Configuration parent = Layer.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(", "))); * }); * }</pre> * * @since 9 + * @spec JPMS * @see java.lang.reflect.Layer */ public final class Configuration { // @see Configuration#empty()
*** 184,198 **** --- 107,133 ---- private final Map<ResolvedModule, Set<ResolvedModule>> graph; private final Set<ResolvedModule> modules; private final Map<String, ResolvedModule> nameToModule; + // module constraints on target + private final String osName; + private final String osArch; + private final String osVersion; + + String osName() { return osName; } + String osArch() { return osArch; } + String osVersion() { return osVersion; } + private Configuration() { this.parents = Collections.emptyList(); this.graph = Collections.emptyMap(); this.modules = Collections.emptySet(); this.nameToModule = Collections.emptyMap(); + this.osName = null; + this.osArch = null; + this.osVersion = null; } private Configuration(List<Configuration> parents, Resolver resolver, boolean check)
*** 212,316 **** this.parents = Collections.unmodifiableList(parents); this.graph = g; this.modules = Set.of(moduleArray); this.nameToModule = Map.ofEntries(nameEntries); - } /** * Resolves a collection of root modules, with this configuration as its * parent, to create a new configuration. This method works exactly as * specified by the static {@link ! * #resolveRequires(ModuleFinder,List,ModuleFinder,Collection) resolveRequires} * method when invoked with this configuration as the parent. In other words, * if this configuration is {@code cf} then this method is equivalent to * invoking: * <pre> {@code ! * Configuration.resolveRequires(before, List.of(cf), after, roots); * }</pre> * * @param before * The <em>before</em> module finder to find modules * @param after ! * The <em>after</em> module finder to locate modules when a ! * module cannot be located by the {@code before} module finder ! * and the module is not in this configuration * @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 ResolutionException ! * If resolution or the post-resolution checks fail * @throws SecurityException * If locating a module is denied by the security manager */ ! public Configuration resolveRequires(ModuleFinder before, ModuleFinder after, Collection<String> roots) { ! return resolveRequires(before, List.of(this), after, roots); } /** * Resolves a collection of root modules, with service binding, and with * this configuration as its parent, to create a new configuration. * This method works exactly as specified by the static {@link ! * #resolveRequiresAndUses(ModuleFinder,List,ModuleFinder,Collection) ! * resolveRequiresAndUses} method when invoked with this configuration * as the parent. In other words, if this configuration is {@code cf} then * this method is equivalent to invoking: * <pre> {@code ! * Configuration.resolveRequiresAndUses(before, List.of(cf), after, roots); * }</pre> * * * @param before * The <em>before</em> module finder to find modules * @param after * The <em>after</em> module finder to locate modules when not ! * located by the {@code before} module finder and this ! * configuration * @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 ResolutionException ! * If resolution or the post-resolution checks fail * @throws SecurityException * If locating a module is denied by the security manager */ ! public Configuration resolveRequiresAndUses(ModuleFinder before, ModuleFinder after, Collection<String> roots) { ! return resolveRequiresAndUses(before, List.of(this), after, roots); } /** * Resolves a collection of root modules, with service binding, and with * the empty configuration as its parent. The post resolution checks * are optionally run. * * This method is used to create the configuration for the boot layer. */ ! static Configuration resolveRequiresAndUses(ModuleFinder finder, Collection<String> roots, boolean check, PrintStream traceOutput) { List<Configuration> parents = List.of(empty()); Resolver resolver = new Resolver(finder, parents, ModuleFinder.of(), traceOutput); ! resolver.resolveRequires(roots).resolveUses(); return new Configuration(parents, resolver, check); } --- 147,262 ---- this.parents = Collections.unmodifiableList(parents); this.graph = g; this.modules = Set.of(moduleArray); this.nameToModule = Map.ofEntries(nameEntries); + this.osName = resolver.osName(); + this.osArch = resolver.osArch(); + this.osVersion = resolver.osVersion(); + } /** * Resolves a collection of root modules, with this configuration as its * parent, to create a new configuration. This method works exactly as * specified by the static {@link ! * #resolve(ModuleFinder,List,ModuleFinder,Collection) resolve} * method when invoked with this configuration as the parent. In other words, * if this configuration is {@code cf} then this method is equivalent to * invoking: * <pre> {@code ! * Configuration.resolve(before, List.of(cf), after, roots); * }</pre> * * @param before * The <em>before</em> module finder to find modules * @param after ! * The <em>after</em> 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 any of the post-resolution consistency checks specified by ! * the static {@code resolve} method fail * @throws SecurityException * If locating a module is denied by the security manager */ ! public Configuration resolve(ModuleFinder before, ModuleFinder after, Collection<String> roots) { ! return resolve(before, List.of(this), after, roots); } /** * Resolves a collection of root modules, with service binding, and with * this configuration as its parent, to create a new configuration. * This method works exactly as specified by the static {@link ! * #resolveAndBind(ModuleFinder,List,ModuleFinder,Collection) ! * resolveAndBind} method when invoked with this configuration * as the parent. In other words, if this configuration is {@code cf} then * this method is equivalent to invoking: * <pre> {@code ! * Configuration.resolveAndBind(before, List.of(cf), after, roots); * }</pre> * * * @param before * The <em>before</em> module finder to find modules * @param after * The <em>after</em> 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 any of the post-resolution consistency checks specified by ! * the static {@code resolve} method fail * @throws SecurityException * If locating a module is denied by the security manager */ ! public Configuration resolveAndBind(ModuleFinder before, ModuleFinder after, Collection<String> roots) { ! return resolveAndBind(before, List.of(this), after, roots); } /** * Resolves a collection of root modules, with service binding, and with * the empty configuration as its parent. The post resolution checks * are optionally run. * * This method is used to create the configuration for the boot layer. */ ! static Configuration resolveAndBind(ModuleFinder finder, Collection<String> roots, boolean check, PrintStream traceOutput) { List<Configuration> parents = List.of(empty()); Resolver resolver = new Resolver(finder, parents, ModuleFinder.of(), traceOutput); ! resolver.resolve(roots).bind(); return new Configuration(parents, resolver, check); }
*** 326,350 **** * or dependences that are located in a parent configuration are resolved * no further and are not included in the resulting configuration. </p> * * <p> When all modules have been resolved then the resulting dependency * graph is checked to ensure that it does not contain cycles. A ! * readability graph is constructed and in conjunction with the module * exports and service use, checked for consistency. </p> * ! * <p> Resolution and the (post-resolution) consistency checks may fail for ! * following reasons: </p> * * <ul> * <li><p> A root module, or a direct or transitive dependency, is not * found. </p></li> * * <li><p> 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. </p></li> * * <li><p> A cycle is detected, say where module {@code m1} requires * module {@code m2} and {@code m2} requires {@code m1}. </p></li> * * <li><p> Two or more modules in the configuration export the same * package to a module that reads both. This includes the case where a --- 272,310 ---- * or dependences that are located in a parent configuration are resolved * no further and are not included in the resulting configuration. </p> * * <p> When all modules have been resolved then the resulting dependency * graph is checked to ensure that it does not contain cycles. A ! * readability graph is constructed, and in conjunction with the module * exports and service use, checked for consistency. </p> * ! * <p> Resolution may fail with {@code FindException} for the following ! * <em>observability-related</em> reasons: </p> * * <ul> * <li><p> A root module, or a direct or transitive dependency, is not * found. </p></li> * * <li><p> 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. </p></li> * + * <li><p> A module with the required name is found but the module + * requires a different {@link ModuleDescriptor#osName() operating + * system}, {@link ModuleDescriptor#osArch() architecture}, or {@link + * ModuleDescriptor#osVersion() version} to other modules that have + * been resolved for the new configuration or modules in the parent + * configurations. </p></li> + * + * </ul> + * + * <p> Post-resolution consistency checks may fail with {@code + * ResolutionException} for the following reasons: </p> + * + * <ul> + * * <li><p> A cycle is detected, say where module {@code m1} requires * module {@code m2} and {@code m2} requires {@code m1}. </p></li> * * <li><p> Two or more modules in the configuration export the same * package to a module that reads both. This includes the case where a
*** 354,378 **** * <li><p> 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. </p></li> * - * <li><p> A module {@code M} declares that it - * "{@code provides ... with q.T}" but package {@code q} is not in - * module {@code M}. </p></li> - * - * <li><p> Two or more modules in the configuration are specific to - * different {@link ModuleDescriptor#osName() operating systems}, - * {@link ModuleDescriptor#osArch() architectures}, or {@link - * ModuleDescriptor#osVersion() versions}. </p></li> - * - * <li><p> Other implementation specific checks, for example referential - * integrity checks to ensure that different versions of tighly coupled - * modules cannot be combined in the same configuration. </p></li> - * * </ul> * * @param before * The <em>before</em> module finder to find modules * @param parents * The list parent configurations in search order * @param after --- 314,329 ---- * <li><p> 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. </p></li> * * </ul> * + * @implNote In the implementation then observability of modules may depend + * on referential integrity checks that ensure that different builds of + * tightly coupled modules cannot be combined in the same configuration. + * * @param before * The <em>before</em> module finder to find modules * @param parents * The list parent configurations in search order * @param after
*** 384,401 **** * to resolve * * @return The configuration that is the result of resolving the given * root modules * * @throws ResolutionException ! * If resolution or the post-resolution checks fail * @throws IllegalArgumentException ! * If the list of parents is empty * @throws SecurityException * If locating a module is denied by the security manager */ ! public static Configuration resolveRequires(ModuleFinder before, List<Configuration> parents, ModuleFinder after, Collection<String> roots) { Objects.requireNonNull(before); --- 335,357 ---- * to resolve * * @return The configuration that is the result of resolving the given * root modules * + * @throws FindException + * If resolution fails for an observability-related reason * @throws ResolutionException ! * If a post-resolution consistency checks fails * @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 resolve(ModuleFinder before, List<Configuration> parents, ModuleFinder after, Collection<String> roots) { Objects.requireNonNull(before);
*** 405,442 **** List<Configuration> parentList = new ArrayList<>(parents); if (parentList.isEmpty()) throw new IllegalArgumentException("'parents' is empty"); Resolver resolver = new Resolver(before, parentList, after, null); ! resolver.resolveRequires(roots); return new Configuration(parentList, resolver, true); } /** * Resolves a collection of root modules, with service binding, to create * configuration. * * <p> This method works exactly as specified by {@link ! * #resolveRequires(ModuleFinder,List,ModuleFinder,Collection) ! * resolveRequires} except that the graph of resolved modules is augmented * with modules induced by the service-use dependence relation. </p> * * <p> More specifically, the root modules are resolved as if by calling ! * {@code resolveRequires}. 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 ! * resolveRequires} 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. </p> ! * ! * <p> As service binding involves resolution then it may fail with {@link ! * ResolutionException} for exactly the same reasons specified in ! * {@code resolveRequires}. </p> * * @param before * The <em>before</em> module finder to find modules * @param parents * The list parent configurations in search order --- 361,398 ---- List<Configuration> parentList = new ArrayList<>(parents); if (parentList.isEmpty()) throw new IllegalArgumentException("'parents' is empty"); Resolver resolver = new Resolver(before, parentList, after, null); ! resolver.resolve(roots); return new Configuration(parentList, resolver, true); } /** * Resolves a collection of root modules, with service binding, to create * configuration. * * <p> 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. </p> * * <p> 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. </p> ! * ! * <p> As service binding involves resolution then it may fail with {@code ! * FindException} or {@code ResolutionException} for exactly the same ! * reasons specified in {@code resolve}. </p> * * @param before * The <em>before</em> module finder to find modules * @param parents * The list parent configurations in search order
*** 446,466 **** * 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 ResolutionException ! * If resolution or the post-resolution checks fail * @throws IllegalArgumentException ! * If the list of parents is empty * @throws SecurityException * If locating a module is denied by the security manager */ ! public static Configuration resolveRequiresAndUses(ModuleFinder before, List<Configuration> parents, ModuleFinder after, Collection<String> roots) { Objects.requireNonNull(before); --- 402,428 ---- * 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 any of the post-resolution consistency checks specified by ! * the static {@code resolve} method fail * @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<Configuration> parents, ModuleFinder after, Collection<String> roots) { Objects.requireNonNull(before);
*** 470,480 **** List<Configuration> parentList = new ArrayList<>(parents); if (parentList.isEmpty()) throw new IllegalArgumentException("'parents' is empty"); Resolver resolver = new Resolver(before, parentList, after, null); ! resolver.resolveRequires(roots).resolveUses(); return new Configuration(parentList, resolver, true); } --- 432,442 ---- List<Configuration> parentList = new ArrayList<>(parents); if (parentList.isEmpty()) throw new IllegalArgumentException("'parents' is empty"); Resolver resolver = new Resolver(before, parentList, after, null); ! resolver.resolve(roots).bind(); return new Configuration(parentList, resolver, true); }
< prev index next >