1 /*
2 * Copyright (c) 2014, 2016, 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
25
26 package java.lang.module;
27
28 import java.io.PrintStream;
29 import java.util.ArrayDeque;
30 import java.util.ArrayList;
31 import java.util.Collection;
32 import java.util.Collections;
33 import java.util.Deque;
34 import java.util.HashSet;
35 import java.util.List;
36 import java.util.Map;
37 import java.util.Map.Entry;
38 import java.util.Objects;
39 import java.util.Optional;
40 import java.util.Set;
41 import java.util.stream.Collectors;
42 import java.util.stream.Stream;
43
44 /**
45 * The configuration that is the result of resolution or resolution with
46 * service binding.
47 *
48 * <h2><a name="resolution">Resolution</a></h2>
49 *
50 * <p> Resolution is the process of computing the transitive closure of a set
51 * of root modules over a set of observable modules by resolving the
52 * dependences expressed by {@code requires} clauses.
53 *
54 * The <em>dependence graph</em> is augmented with edges that take account of
55 * implicitly declared dependences ({@code requires transitive}) to create a
56 * <em>readability graph</em>. A {@code Configuration} encapsulates the
57 * resulting graph of {@link ResolvedModule resolved modules}.
58 *
59 * <p> Suppose we have the following observable modules: </p>
60 * <pre> {@code
61 * module m1 { requires m2; }
62 * module m2 { requires transitive m3; }
63 * module m3 { }
64 * module m4 { }
65 * } </pre>
66 *
67 * <p> If the module {@code m1} is resolved then the resulting configuration
68 * contains three modules ({@code m1}, {@code m2}, {@code m3}). The edges in
69 * its readability graph are: </p>
70 * <pre> {@code
71 * m1 --> m2 (meaning m1 reads m2)
72 * m1 --> m3
73 * m2 --> m3
74 * } </pre>
75 *
76 * <p> Resolution is an additive process. When computing the transitive closure
77 * then the dependence relation may include dependences on modules in parent
78 * configurations. The result is a <em>relative configuration</em> that is
79 * relative to one or more parent configurations and where the readability graph
80 * may have edges from modules in the configuration to modules in parent
81 * configurations.
82 *
83 * </p>
84 *
85 * <p> Suppose we have the following observable modules: </p>
86 * <pre> {@code
87 * module m1 { requires m2; requires java.xml; }
88 * module m2 { }
89 * } </pre>
90 *
91 * <p> If module {@code m1} is resolved with the configuration for the {@link
92 * java.lang.reflect.Layer#boot() boot} layer as the parent then the resulting
93 * configuration contains two modules ({@code m1}, {@code m2}). The edges in
94 * its readability graph are:
95 * <pre> {@code
96 * m1 --> m2
97 * m1 --> java.xml
98 * } </pre>
99 * where module {@code java.xml} is in the parent configuration. For
100 * simplicity, this example omits the implicitly declared dependence on the
101 * {@code java.base} module.
102 *
103 * <a name="automaticmoduleresolution"></a>
104 * <p> {@link ModuleDescriptor#isAutomatic() Automatic} modules receive special
105 * treatment during resolution. Each automatic module is resolved so that it
106 * reads all other modules in the configuration and all parent configurations.
107 * Each automatic module is also resolved as if it {@code requires transitive}
108 * all other automatic modules in the configuration (and all automatic modules
109 * in parent configurations). </p>
110
111 * <h2><a name="servicebinding">Service binding</a></h2>
112 *
113 * <p> Service binding is the process of augmenting a graph of resolved modules
114 * from the set of observable modules induced by the service-use dependence
115 * ({@code uses} and {@code provides} clauses). Any module that was not
116 * previously in the graph requires resolution to compute its transitive
117 * closure. Service binding is an iterative process in that adding a module
118 * that satisfies some service-use dependence may introduce new service-use
119 * dependences. </p>
120 *
121 * <p> Suppose we have the following observable modules: </p>
122 * <pre> {@code
123 * module m1 { exports p; uses p.S; }
124 * module m2 { requires m1; provides p.S with p2.S2; }
125 * module m3 { requires m1; requires m4; provides p.S with p3.S3; }
126 * module m4 { }
127 * } </pre>
128 *
129 * <p> If the module {@code m1} is resolved then the resulting graph of modules
130 * has one module ({@code m1}). If the graph is augmented with modules induced
131 * by the service-use dependence relation then the configuration will contain
132 * four modules ({@code m1}, {@code m2}, {@code m3}, {@code m4}). The edges in
133 * its readability graph are: </p>
134 * <pre> {@code
135 * m2 --> m1
136 * m3 --> m1
137 * m3 --> m4
138 * } </pre>
139 * <p> The edges in the conceptual service-use graph are: </p>
140 * <pre> {@code
141 * m1 --> m2 (meaning m1 uses a service that is provided by m2)
142 * m1 --> m3
143 * } </pre>
144 *
145 * <p> If this configuration is instantiated as a {@code Layer}, and if code in
146 * module {@code m1} uses {@link java.util.ServiceLoader ServiceLoader} to
147 * iterate over implementations of {@code p.S.class}, then it will iterate over
148 * an instance of {@code p2.S2} and {@code p3.S3}. </p>
149 *
150 * <h3> Example </h3>
151 *
152 * <p> The following example uses the {@code resolveRequires} method to resolve
153 * a module named <em>myapp</em> with the configuration for the boot layer as
154 * the parent configuration. It prints the name of each resolved module and
155 * the names of the modules that each module reads. </p>
156 *
157 * <pre>{@code
158 * ModuleFinder finder = ModuleFinder.of(dir1, dir2, dir3);
159 *
160 * Configuration parent = Layer.boot().configuration();
161 *
162 * Configuration cf = parent.resolveRequires(finder,
163 * ModuleFinder.of(),
164 * Set.of("myapp"));
165 * cf.modules().forEach(m -> {
166 * System.out.format("%s -> %s%n",
167 * m.name(),
168 * m.reads().stream()
169 * .map(ResolvedModule::name)
170 * .collect(Collectors.joining(", ")));
171 * });
172 * }</pre>
173 *
174 * @since 9
175 * @see java.lang.reflect.Layer
176 */
177 public final class Configuration {
178
179 // @see Configuration#empty()
180 private static final Configuration EMPTY_CONFIGURATION = new Configuration();
181
182 // parent configurations, in search order
183 private final List<Configuration> parents;
184
185 private final Map<ResolvedModule, Set<ResolvedModule>> graph;
186 private final Set<ResolvedModule> modules;
187 private final Map<String, ResolvedModule> nameToModule;
188
189 private Configuration() {
190 this.parents = Collections.emptyList();
191 this.graph = Collections.emptyMap();
192 this.modules = Collections.emptySet();
193 this.nameToModule = Collections.emptyMap();
194 }
195
196 private Configuration(List<Configuration> parents,
197 Resolver resolver,
198 boolean check)
199 {
200 Map<ResolvedModule, Set<ResolvedModule>> g = resolver.finish(this, check);
201
202 @SuppressWarnings(value = {"rawtypes", "unchecked"})
203 Entry<String, ResolvedModule>[] nameEntries
204 = (Entry<String, ResolvedModule>[])new Entry[g.size()];
205 ResolvedModule[] moduleArray = new ResolvedModule[g.size()];
206 int i = 0;
207 for (ResolvedModule resolvedModule : g.keySet()) {
208 moduleArray[i] = resolvedModule;
209 nameEntries[i] = Map.entry(resolvedModule.name(), resolvedModule);
210 i++;
211 }
212
213 this.parents = Collections.unmodifiableList(parents);
214 this.graph = g;
215 this.modules = Set.of(moduleArray);
216 this.nameToModule = Map.ofEntries(nameEntries);
217 }
218
219
220 /**
221 * Resolves a collection of root modules, with this configuration as its
222 * parent, to create a new configuration. This method works exactly as
223 * specified by the static {@link
224 * #resolveRequires(ModuleFinder,List,ModuleFinder,Collection) resolveRequires}
225 * method when invoked with this configuration as the parent. In other words,
226 * if this configuration is {@code cf} then this method is equivalent to
227 * invoking:
228 * <pre> {@code
229 * Configuration.resolveRequires(before, List.of(cf), after, roots);
230 * }</pre>
231 *
232 * @param before
233 * The <em>before</em> module finder to find modules
234 * @param after
235 * The <em>after</em> module finder to locate modules when a
236 * module cannot be located by the {@code before} module finder
237 * and the module is not in this configuration
238 * @param roots
239 * The possibly-empty collection of module names of the modules
240 * to resolve
241 *
242 * @return The configuration that is the result of resolving the given
243 * root modules
244 *
245 * @throws ResolutionException
246 * If resolution or the post-resolution checks fail
247 * @throws SecurityException
248 * If locating a module is denied by the security manager
249 */
250 public Configuration resolveRequires(ModuleFinder before,
251 ModuleFinder after,
252 Collection<String> roots)
253 {
254 return resolveRequires(before, List.of(this), after, roots);
255 }
256
257
258 /**
259 * Resolves a collection of root modules, with service binding, and with
260 * this configuration as its parent, to create a new configuration.
261 * This method works exactly as specified by the static {@link
262 * #resolveRequiresAndUses(ModuleFinder,List,ModuleFinder,Collection)
263 * resolveRequiresAndUses} method when invoked with this configuration
264 * as the parent. In other words, if this configuration is {@code cf} then
265 * this method is equivalent to invoking:
266 * <pre> {@code
267 * Configuration.resolveRequiresAndUses(before, List.of(cf), after, roots);
268 * }</pre>
269 *
270 *
271 * @param before
272 * The <em>before</em> module finder to find modules
273 * @param after
274 * The <em>after</em> module finder to locate modules when not
275 * located by the {@code before} module finder and this
276 * configuration
277 * @param roots
278 * The possibly-empty collection of module names of the modules
279 * to resolve
280 *
281 * @return The configuration that is the result of resolving the given
282 * root modules
283 *
284 * @throws ResolutionException
285 * If resolution or the post-resolution checks fail
286 * @throws SecurityException
287 * If locating a module is denied by the security manager
288 */
289 public Configuration resolveRequiresAndUses(ModuleFinder before,
290 ModuleFinder after,
291 Collection<String> roots)
292 {
293 return resolveRequiresAndUses(before, List.of(this), after, roots);
294 }
295
296
297 /**
298 * Resolves a collection of root modules, with service binding, and with
299 * the empty configuration as its parent. The post resolution checks
300 * are optionally run.
301 *
302 * This method is used to create the configuration for the boot layer.
303 */
304 static Configuration resolveRequiresAndUses(ModuleFinder finder,
305 Collection<String> roots,
306 boolean check,
307 PrintStream traceOutput)
308 {
309 List<Configuration> parents = List.of(empty());
310 Resolver resolver = new Resolver(finder, parents, ModuleFinder.of(), traceOutput);
311 resolver.resolveRequires(roots).resolveUses();
312
313 return new Configuration(parents, resolver, check);
314 }
315
316
317 /**
318 * Resolves a collection of root modules to create a configuration.
319 *
320 * <p> Each root module is located using the given {@code before} module
321 * finder. If a module is not found then it is located in the parent
322 * configuration as if by invoking the {@link #findModule(String)
323 * findModule} method on each parent in iteration order. If not found then
324 * the module is located using the given {@code after} module finder. The
325 * same search order is used to locate transitive dependences. Root modules
326 * or dependences that are located in a parent configuration are resolved
327 * no further and are not included in the resulting configuration. </p>
328 *
329 * <p> When all modules have been resolved then the resulting dependency
330 * graph is checked to ensure that it does not contain cycles. A
331 * readability graph is constructed and in conjunction with the module
332 * exports and service use, checked for consistency. </p>
333 *
334 * <p> Resolution and the (post-resolution) consistency checks may fail for
335 * following reasons: </p>
336 *
337 * <ul>
338 * <li><p> A root module, or a direct or transitive dependency, is not
339 * found. </p></li>
340 *
341 * <li><p> An error occurs when attempting to find a module.
342 * Possible errors include I/O errors, errors detected parsing a module
343 * descriptor ({@code module-info.class}) or two versions of the same
344 * module are found in the same directory. </p></li>
345 *
346 * <li><p> A cycle is detected, say where module {@code m1} requires
347 * module {@code m2} and {@code m2} requires {@code m1}. </p></li>
348 *
349 * <li><p> Two or more modules in the configuration export the same
350 * package to a module that reads both. This includes the case where a
351 * module {@code M} containing package {@code p} reads another module
352 * that exports {@code p} to {@code M}. </p></li>
353 *
354 * <li><p> A module {@code M} declares that it "{@code uses p.S}" or
355 * "{@code provides p.S with ...}" but package {@code p} is neither in
356 * module {@code M} nor exported to {@code M} by any module that
357 * {@code M} reads. </p></li>
358 *
359 * <li><p> A module {@code M} declares that it
360 * "{@code provides ... with q.T}" but package {@code q} is not in
361 * module {@code M}. </p></li>
362 *
363 * <li><p> Two or more modules in the configuration are specific to
364 * different {@link ModuleDescriptor#osName() operating systems},
365 * {@link ModuleDescriptor#osArch() architectures}, or {@link
366 * ModuleDescriptor#osVersion() versions}. </p></li>
367 *
368 * <li><p> Other implementation specific checks, for example referential
369 * integrity checks to ensure that different versions of tighly coupled
370 * modules cannot be combined in the same configuration. </p></li>
371 *
372 * </ul>
373 *
374 * @param before
375 * The <em>before</em> module finder to find modules
376 * @param parents
377 * The list parent configurations in search order
378 * @param after
379 * The <em>after</em> module finder to locate modules when not
380 * located by the {@code before} module finder or in parent
381 * configurations
382 * @param roots
383 * The possibly-empty collection of module names of the modules
384 * to resolve
385 *
386 * @return The configuration that is the result of resolving the given
387 * root modules
388 *
389 * @throws ResolutionException
390 * If resolution or the post-resolution checks fail
391 * @throws IllegalArgumentException
392 * If the list of parents is empty
393 * @throws SecurityException
394 * If locating a module is denied by the security manager
395 */
396 public static Configuration resolveRequires(ModuleFinder before,
397 List<Configuration> parents,
398 ModuleFinder after,
399 Collection<String> roots)
400 {
401 Objects.requireNonNull(before);
402 Objects.requireNonNull(after);
403 Objects.requireNonNull(roots);
404
405 List<Configuration> parentList = new ArrayList<>(parents);
406 if (parentList.isEmpty())
407 throw new IllegalArgumentException("'parents' is empty");
408
409 Resolver resolver = new Resolver(before, parentList, after, null);
410 resolver.resolveRequires(roots);
411
412 return new Configuration(parentList, resolver, true);
413 }
414
415 /**
416 * Resolves a collection of root modules, with service binding, to create
417 * configuration.
418 *
419 * <p> This method works exactly as specified by {@link
420 * #resolveRequires(ModuleFinder,List,ModuleFinder,Collection)
421 * resolveRequires} except that the graph of resolved modules is augmented
422 * with modules induced by the service-use dependence relation. </p>
423 *
424 * <p> More specifically, the root modules are resolved as if by calling
425 * {@code resolveRequires}. The resolved modules, and all modules in the
426 * parent configurations, with {@link ModuleDescriptor#uses() service
427 * dependences} are then examined. All modules found by the given module
428 * finders that {@link ModuleDescriptor#provides() provide} an
429 * implementation of one or more of the service types are added to the
430 * module graph and then resolved as if by calling the {@code
431 * resolveRequires} method. Adding modules to the module graph may
432 * introduce new service-use dependences and so the process works
433 * iteratively until no more modules are added. </p>
434 *
435 * <p> As service binding involves resolution then it may fail with {@link
436 * ResolutionException} for exactly the same reasons specified in
437 * {@code resolveRequires}. </p>
438 *
439 * @param before
440 * The <em>before</em> module finder to find modules
441 * @param parents
442 * The list parent configurations in search order
443 * @param after
444 * The <em>after</em> module finder to locate modules when not
445 * located by the {@code before} module finder or in parent
446 * configurations
447 * @param roots
448 * The possibly-empty collection of module names of the modules
449 * to resolve
450 *
451 * @return The configuration that is the result of resolving the given
452 * root modules
453 *
454 * @throws ResolutionException
455 * If resolution or the post-resolution checks fail
456 * @throws IllegalArgumentException
457 * If the list of parents is empty
458 * @throws SecurityException
459 * If locating a module is denied by the security manager
460 */
461 public static Configuration resolveRequiresAndUses(ModuleFinder before,
462 List<Configuration> parents,
463 ModuleFinder after,
464 Collection<String> roots)
465 {
466 Objects.requireNonNull(before);
467 Objects.requireNonNull(after);
468 Objects.requireNonNull(roots);
469
470 List<Configuration> parentList = new ArrayList<>(parents);
471 if (parentList.isEmpty())
472 throw new IllegalArgumentException("'parents' is empty");
473
474 Resolver resolver = new Resolver(before, parentList, after, null);
475 resolver.resolveRequires(roots).resolveUses();
476
477 return new Configuration(parentList, resolver, true);
478 }
479
480
481 /**
482 * Returns the <em>empty</em> configuration. There are no modules in the
483 * empty configuration. It has no parents.
484 *
485 * @return The empty configuration
486 */
487 public static Configuration empty() {
488 return EMPTY_CONFIGURATION;
489 }
490
491
492 /**
493 * Returns an unmodifiable list of this configuration's parents, in search
494 * order. If this is the {@linkplain #empty empty configuration} then an
495 * empty list is returned.
|
1 /*
2 * Copyright (c) 2014, 2017, 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
25
26 package java.lang.module;
27
28 import java.io.PrintStream;
29 import java.util.ArrayDeque;
30 import java.util.ArrayList;
31 import java.util.Collection;
32 import java.util.Collections;
33 import java.util.Deque;
34 import java.util.HashSet;
35 import java.util.List;
36 import java.util.Map;
37 import java.util.Map.Entry;
38 import java.util.Objects;
39 import java.util.Optional;
40 import java.util.Set;
41 import java.util.stream.Collectors;
42 import java.util.stream.Stream;
43
44 /**
45 * A configuration that is the result of <a href="package-summary.html#resolution">
46 * resolution</a> or resolution with <a href="package-summary.html#servicebinding">
47 * service binding</a>.
48 *
49 * <p> A configuration encapsulates the <em>readability graph</em> that is the
50 * output of resolution. A readability graph is a directed graph where the nodes
51 * are of type {@link ResolvedModule} and the edges represent the readability
52 * amongst the modules. {@code Configuration} defines the {@link #modules()
53 * modules()} method to get the set of resolved modules in the graph. {@code
54 * ResolvedModule} defines the {@link ResolvedModule#reads() reads()} method to
55 * get the set of modules that a resolved module reads. The modules that are
56 * read may be in the same configuration or may be in {@link #parents() parent}
57 * configurations. </p>
58 *
59 * <p> Configuration defines the {@link #resolve(ModuleFinder,List,ModuleFinder,Collection)
60 * resolve} method to resolve a collection of root modules, and the {@link
61 * #resolveAndBind(ModuleFinder,List,ModuleFinder,Collection) resolveAndBind}
62 * method to do resolution with service binding. There are instance and
63 * static variants of both methods. The instance methods create a configuration
64 * with the receiver as the parent configuration. The static methods are for
65 * more advanced cases where there can be more than one parent configuration. </p>
66 *
67 * <p> Each {@link java.lang.reflect.Layer layer} of modules in the Java virtual
68 * machine is created from a configuration. The configuration for the {@link
69 * java.lang.reflect.Layer#boot() boot} layer is obtained by invoking {@code
70 * Layer.boot().configuration()}. The configuration for the boot layer will
71 * often be the parent when creating new configurations. </p>
72 *
73 * <h3> Example </h3>
74 *
75 * <p> The following example uses the {@link
76 * #resolve(ModuleFinder,ModuleFinder,Collection) resolve} method to resolve a
77 * module named <em>myapp</em> with the configuration for the boot layer as the
78 * parent configuration. It prints the name of each resolved module and the
79 * names of the modules that each module reads. </p>
80 *
81 * <pre>{@code
82 * ModuleFinder finder = ModuleFinder.of(dir1, dir2, dir3);
83 *
84 * Configuration parent = Layer.boot().configuration();
85 *
86 * Configuration cf = parent.resolve(finder, ModuleFinder.of(), Set.of("myapp"));
87 * cf.modules().forEach(m -> {
88 * System.out.format("%s -> %s%n",
89 * m.name(),
90 * m.reads().stream()
91 * .map(ResolvedModule::name)
92 * .collect(Collectors.joining(", ")));
93 * });
94 * }</pre>
95 *
96 * @since 9
97 * @spec JPMS
98 * @see java.lang.reflect.Layer
99 */
100 public final class Configuration {
101
102 // @see Configuration#empty()
103 private static final Configuration EMPTY_CONFIGURATION = new Configuration();
104
105 // parent configurations, in search order
106 private final List<Configuration> parents;
107
108 private final Map<ResolvedModule, Set<ResolvedModule>> graph;
109 private final Set<ResolvedModule> modules;
110 private final Map<String, ResolvedModule> nameToModule;
111
112 // module constraints on target
113 private final String osName;
114 private final String osArch;
115 private final String osVersion;
116
117 String osName() { return osName; }
118 String osArch() { return osArch; }
119 String osVersion() { return osVersion; }
120
121 private Configuration() {
122 this.parents = Collections.emptyList();
123 this.graph = Collections.emptyMap();
124 this.modules = Collections.emptySet();
125 this.nameToModule = Collections.emptyMap();
126 this.osName = null;
127 this.osArch = null;
128 this.osVersion = null;
129 }
130
131 private Configuration(List<Configuration> parents,
132 Resolver resolver,
133 boolean check)
134 {
135 Map<ResolvedModule, Set<ResolvedModule>> g = resolver.finish(this, check);
136
137 @SuppressWarnings(value = {"rawtypes", "unchecked"})
138 Entry<String, ResolvedModule>[] nameEntries
139 = (Entry<String, ResolvedModule>[])new Entry[g.size()];
140 ResolvedModule[] moduleArray = new ResolvedModule[g.size()];
141 int i = 0;
142 for (ResolvedModule resolvedModule : g.keySet()) {
143 moduleArray[i] = resolvedModule;
144 nameEntries[i] = Map.entry(resolvedModule.name(), resolvedModule);
145 i++;
146 }
147
148 this.parents = Collections.unmodifiableList(parents);
149 this.graph = g;
150 this.modules = Set.of(moduleArray);
151 this.nameToModule = Map.ofEntries(nameEntries);
152
153 this.osName = resolver.osName();
154 this.osArch = resolver.osArch();
155 this.osVersion = resolver.osVersion();
156 }
157
158 /**
159 * Resolves a collection of root modules, with this configuration as its
160 * parent, to create a new configuration. This method works exactly as
161 * specified by the static {@link
162 * #resolve(ModuleFinder,List,ModuleFinder,Collection) resolve}
163 * method when invoked with this configuration as the parent. In other words,
164 * if this configuration is {@code cf} then this method is equivalent to
165 * invoking:
166 * <pre> {@code
167 * Configuration.resolve(before, List.of(cf), after, roots);
168 * }</pre>
169 *
170 * @param before
171 * The <em>before</em> module finder to find modules
172 * @param after
173 * The <em>after</em> module finder to locate modules when not
174 * located by the {@code before} module finder or in parent
175 * configurations
176 * @param roots
177 * The possibly-empty collection of module names of the modules
178 * to resolve
179 *
180 * @return The configuration that is the result of resolving the given
181 * root modules
182 *
183 * @throws FindException
184 * If resolution fails for any of the observability-related reasons
185 * specified by the static {@code resolve} method
186 * @throws ResolutionException
187 * If any of the post-resolution consistency checks specified by
188 * the static {@code resolve} method fail
189 * @throws SecurityException
190 * If locating a module is denied by the security manager
191 */
192 public Configuration resolve(ModuleFinder before,
193 ModuleFinder after,
194 Collection<String> roots)
195 {
196 return resolve(before, List.of(this), after, roots);
197 }
198
199
200 /**
201 * Resolves a collection of root modules, with service binding, and with
202 * this configuration as its parent, to create a new configuration.
203 * This method works exactly as specified by the static {@link
204 * #resolveAndBind(ModuleFinder,List,ModuleFinder,Collection)
205 * resolveAndBind} method when invoked with this configuration
206 * as the parent. In other words, if this configuration is {@code cf} then
207 * this method is equivalent to invoking:
208 * <pre> {@code
209 * Configuration.resolveAndBind(before, List.of(cf), after, roots);
210 * }</pre>
211 *
212 *
213 * @param before
214 * The <em>before</em> module finder to find modules
215 * @param after
216 * The <em>after</em> module finder to locate modules when not
217 * located by the {@code before} module finder or in parent
218 * configurations
219 * @param roots
220 * The possibly-empty collection of module names of the modules
221 * to resolve
222 *
223 * @return The configuration that is the result of resolving, with service
224 * binding, the given root modules
225 *
226 * @throws FindException
227 * If resolution fails for any of the observability-related reasons
228 * specified by the static {@code resolve} method
229 * @throws ResolutionException
230 * If any of the post-resolution consistency checks specified by
231 * the static {@code resolve} method fail
232 * @throws SecurityException
233 * If locating a module is denied by the security manager
234 */
235 public Configuration resolveAndBind(ModuleFinder before,
236 ModuleFinder after,
237 Collection<String> roots)
238 {
239 return resolveAndBind(before, List.of(this), after, roots);
240 }
241
242
243 /**
244 * Resolves a collection of root modules, with service binding, and with
245 * the empty configuration as its parent. The post resolution checks
246 * are optionally run.
247 *
248 * This method is used to create the configuration for the boot layer.
249 */
250 static Configuration resolveAndBind(ModuleFinder finder,
251 Collection<String> roots,
252 boolean check,
253 PrintStream traceOutput)
254 {
255 List<Configuration> parents = List.of(empty());
256 Resolver resolver = new Resolver(finder, parents, ModuleFinder.of(), traceOutput);
257 resolver.resolve(roots).bind();
258
259 return new Configuration(parents, resolver, check);
260 }
261
262
263 /**
264 * Resolves a collection of root modules to create a configuration.
265 *
266 * <p> Each root module is located using the given {@code before} module
267 * finder. If a module is not found then it is located in the parent
268 * configuration as if by invoking the {@link #findModule(String)
269 * findModule} method on each parent in iteration order. If not found then
270 * the module is located using the given {@code after} module finder. The
271 * same search order is used to locate transitive dependences. Root modules
272 * or dependences that are located in a parent configuration are resolved
273 * no further and are not included in the resulting configuration. </p>
274 *
275 * <p> When all modules have been resolved then the resulting dependency
276 * graph is checked to ensure that it does not contain cycles. A
277 * readability graph is constructed, and in conjunction with the module
278 * exports and service use, checked for consistency. </p>
279 *
280 * <p> Resolution may fail with {@code FindException} for the following
281 * <em>observability-related</em> reasons: </p>
282 *
283 * <ul>
284 * <li><p> A root module, or a direct or transitive dependency, is not
285 * found. </p></li>
286 *
287 * <li><p> An error occurs when attempting to find a module.
288 * Possible errors include I/O errors, errors detected parsing a module
289 * descriptor ({@code module-info.class}) or two versions of the same
290 * module are found in the same directory. </p></li>
291 *
292 * <li><p> A module with the required name is found but the module
293 * requires a different {@link ModuleDescriptor#osName() operating
294 * system}, {@link ModuleDescriptor#osArch() architecture}, or {@link
295 * ModuleDescriptor#osVersion() version} to other modules that have
296 * been resolved for the new configuration or modules in the parent
297 * configurations. </p></li>
298 *
299 * </ul>
300 *
301 * <p> Post-resolution consistency checks may fail with {@code
302 * ResolutionException} for the following reasons: </p>
303 *
304 * <ul>
305 *
306 * <li><p> A cycle is detected, say where module {@code m1} requires
307 * module {@code m2} and {@code m2} requires {@code m1}. </p></li>
308 *
309 * <li><p> Two or more modules in the configuration export the same
310 * package to a module that reads both. This includes the case where a
311 * module {@code M} containing package {@code p} reads another module
312 * that exports {@code p} to {@code M}. </p></li>
313 *
314 * <li><p> A module {@code M} declares that it "{@code uses p.S}" or
315 * "{@code provides p.S with ...}" but package {@code p} is neither in
316 * module {@code M} nor exported to {@code M} by any module that
317 * {@code M} reads. </p></li>
318 *
319 * </ul>
320 *
321 * @implNote In the implementation then observability of modules may depend
322 * on referential integrity checks that ensure that different builds of
323 * tightly coupled modules cannot be combined in the same configuration.
324 *
325 * @param before
326 * The <em>before</em> module finder to find modules
327 * @param parents
328 * The list parent configurations in search order
329 * @param after
330 * The <em>after</em> module finder to locate modules when not
331 * located by the {@code before} module finder or in parent
332 * configurations
333 * @param roots
334 * The possibly-empty collection of module names of the modules
335 * to resolve
336 *
337 * @return The configuration that is the result of resolving the given
338 * root modules
339 *
340 * @throws FindException
341 * If resolution fails for an observability-related reason
342 * @throws ResolutionException
343 * If a post-resolution consistency checks fails
344 * @throws IllegalArgumentException
345 * If the list of parents is empty, or the list has two or more
346 * parents with modules for different target operating systems,
347 * architectures, or versions
348 *
349 * @throws SecurityException
350 * If locating a module is denied by the security manager
351 */
352 public static Configuration resolve(ModuleFinder before,
353 List<Configuration> parents,
354 ModuleFinder after,
355 Collection<String> roots)
356 {
357 Objects.requireNonNull(before);
358 Objects.requireNonNull(after);
359 Objects.requireNonNull(roots);
360
361 List<Configuration> parentList = new ArrayList<>(parents);
362 if (parentList.isEmpty())
363 throw new IllegalArgumentException("'parents' is empty");
364
365 Resolver resolver = new Resolver(before, parentList, after, null);
366 resolver.resolve(roots);
367
368 return new Configuration(parentList, resolver, true);
369 }
370
371 /**
372 * Resolves a collection of root modules, with service binding, to create
373 * configuration.
374 *
375 * <p> This method works exactly as specified by {@link
376 * #resolve(ModuleFinder,List,ModuleFinder,Collection)
377 * resolve} except that the graph of resolved modules is augmented
378 * with modules induced by the service-use dependence relation. </p>
379 *
380 * <p> More specifically, the root modules are resolved as if by calling
381 * {@code resolve}. The resolved modules, and all modules in the
382 * parent configurations, with {@link ModuleDescriptor#uses() service
383 * dependences} are then examined. All modules found by the given module
384 * finders that {@link ModuleDescriptor#provides() provide} an
385 * implementation of one or more of the service types are added to the
386 * module graph and then resolved as if by calling the {@code
387 * resolve} method. Adding modules to the module graph may introduce new
388 * service-use dependences and so the process works iteratively until no
389 * more modules are added. </p>
390 *
391 * <p> As service binding involves resolution then it may fail with {@code
392 * FindException} or {@code ResolutionException} for exactly the same
393 * reasons specified in {@code resolve}. </p>
394 *
395 * @param before
396 * The <em>before</em> module finder to find modules
397 * @param parents
398 * The list parent configurations in search order
399 * @param after
400 * The <em>after</em> module finder to locate modules when not
401 * located by the {@code before} module finder or in parent
402 * configurations
403 * @param roots
404 * The possibly-empty collection of module names of the modules
405 * to resolve
406 *
407 * @return The configuration that is the result of resolving, with service
408 * binding, the given root modules
409 *
410 * @throws FindException
411 * If resolution fails for any of the observability-related reasons
412 * specified by the static {@code resolve} method
413 * @throws ResolutionException
414 * If any of the post-resolution consistency checks specified by
415 * the static {@code resolve} method fail
416 * @throws IllegalArgumentException
417 * If the list of parents is empty, or the list has two or more
418 * parents with modules for different target operating systems,
419 * architectures, or versions
420 * @throws SecurityException
421 * If locating a module is denied by the security manager
422 */
423 public static Configuration resolveAndBind(ModuleFinder before,
424 List<Configuration> parents,
425 ModuleFinder after,
426 Collection<String> roots)
427 {
428 Objects.requireNonNull(before);
429 Objects.requireNonNull(after);
430 Objects.requireNonNull(roots);
431
432 List<Configuration> parentList = new ArrayList<>(parents);
433 if (parentList.isEmpty())
434 throw new IllegalArgumentException("'parents' is empty");
435
436 Resolver resolver = new Resolver(before, parentList, after, null);
437 resolver.resolve(roots).bind();
438
439 return new Configuration(parentList, resolver, true);
440 }
441
442
443 /**
444 * Returns the <em>empty</em> configuration. There are no modules in the
445 * empty configuration. It has no parents.
446 *
447 * @return The empty configuration
448 */
449 public static Configuration empty() {
450 return EMPTY_CONFIGURATION;
451 }
452
453
454 /**
455 * Returns an unmodifiable list of this configuration's parents, in search
456 * order. If this is the {@linkplain #empty empty configuration} then an
457 * empty list is returned.
|