1 /*
2  * Copyright (c) 2014, 2018, 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
23  * questions.
24  */

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 import jdk.internal.misc.VM;
45 import jdk.internal.module.ModuleReferenceImpl;
46 import jdk.internal.module.ModuleTarget;
47 import jdk.internal.vm.annotation.Stable;
48
49 /**
50  * A configuration that is the result of <a href="package-summary.html#resolution">
51  * resolution</a> or resolution with
52  * <a href="{@docRoot}/java.base/java/lang/module/Configuration.html#service-binding">service binding</a>.
53  *
54  * <p> A configuration encapsulates the <em>readability graph</em> that is the
55  * output of resolution. A readability graph is a directed graph whose vertices
56  * are of type {@link ResolvedModule} and the edges represent the readability
57  * amongst the modules. {@code Configuration} defines the {@link #modules()
58  * modules()} method to get the set of resolved modules in the graph. {@code
59  * ResolvedModule} defines the {@link ResolvedModule#reads() reads()} method to
60  * get the set of modules that a resolved module reads. The modules that are
61  * read may be in the same configuration or may be in {@link #parents() parent}
62  * configurations. </p>
63  *
64  * <p> Configuration defines the {@link #resolve(ModuleFinder,List,ModuleFinder,Collection)
65  * resolve} method to resolve a collection of root modules, and the {@link
66  * #resolveAndBind(ModuleFinder,List,ModuleFinder,Collection) resolveAndBind}
67  * method to do resolution with service binding. There are instance and
68  * static variants of both methods. The instance methods create a configuration
69  * with the receiver as the parent configuration. The static methods are for
70  * more advanced cases where there can be more than one parent configuration. </p>
71  *
72  * <p> Each {@link java.lang.ModuleLayer layer} of modules in the Java virtual
73  * machine is created from a configuration. The configuration for the {@link
74  * java.lang.ModuleLayer#boot() boot} layer is obtained by invoking {@code
75  * ModuleLayer.boot().configuration()}. The configuration for the boot layer
76  * will often be the parent when creating new configurations. </p>
77  *
78  * <h3> Example </h3>
79  *
80  * <p> The following example uses the {@link
81  * #resolve(ModuleFinder,ModuleFinder,Collection) resolve} method to resolve a
82  * module named <em>myapp</em> with the configuration for the boot layer as the
83  * parent configuration. It prints the name of each resolved module and the
84  * names of the modules that each module reads. </p>
85  *
86  * <pre>{@code
87  *    ModuleFinder finder = ModuleFinder.of(dir1, dir2, dir3);
88  *
89  *    Configuration parent = ModuleLayer.boot().configuration();
90  *
91  *    Configuration cf = parent.resolve(finder, ModuleFinder.of(), Set.of("myapp"));
92  *    cf.modules().forEach(m -> {
93  *        System.out.format("%s -> %s%n",
94  *            m.name(),
95  *            m.reads().stream()
96  *                .map(ResolvedModule::name)
97  *                .collect(Collectors.joining(", ")));
98  *    });
99  * }</pre>
100  *
101  * @since 9
102  * @spec JPMS
103  * @see java.lang.ModuleLayer
104  */

105 public final class Configuration {
106
107     // @see Configuration#empty()
108     // EMPTY_CONFIGURATION may be initialized from the CDS archive.
109     private static @Stable Configuration EMPTY_CONFIGURATION;
110
111     static {
112         // Initialize EMPTY_CONFIGURATION from the archive.
113         VM.initializeFromArchive(Configuration.class);
114         // Create a new empty Configuration if there is no archived version.
115         if (EMPTY_CONFIGURATION == null) {
116             EMPTY_CONFIGURATION = new Configuration();
117         }
118     }
119
120     // parent configurations, in search order
121     private final List<Configuration> parents;
122
123     private final Map<ResolvedModule, Set<ResolvedModule>> graph;
124     private final Set<ResolvedModule> modules;
125     private final Map<String, ResolvedModule> nameToModule;
126
127     // constraint on target platform
128     private final String targetPlatform;
129
130     String targetPlatform() { return targetPlatform; }
131
132     private Configuration() {
133         this.parents = List.of();
134         this.graph = Map.of();
135         this.modules = Set.of();
136         this.nameToModule = Map.of();
137         this.targetPlatform = null;
138     }
139
140     private Configuration(List<Configuration> parents, Resolver resolver) {
141         Map<ResolvedModule, Set<ResolvedModule>> g = resolver.finish(this);
142
143         @SuppressWarnings(value = {"rawtypes""unchecked"})
144         Entry<String, ResolvedModule>[] nameEntries
145             = (Entry<String, ResolvedModule>[])new Entry[g.size()];
146         ResolvedModule[] moduleArray = new ResolvedModule[g.size()];
147         int i = 0;
148         for (ResolvedModule resolvedModule : g.keySet()) {
149             moduleArray[i] = resolvedModule;
150             nameEntries[i] = Map.entry(resolvedModule.name(), resolvedModule);
151             i++;
152         }
153
154         this.parents = List.copyOf(parents);
155         this.graph = g;
156         this.modules = Set.of(moduleArray);
157         this.nameToModule = Map.ofEntries(nameEntries);
158
159         this.targetPlatform = resolver.targetPlatform();
160     }
161
162     /**
163      * Creates the Configuration for the boot layer from a pre-generated
164      * readability graph.
165      *
166      * @apiNote This method is coded for startup performance.
167      */

168     Configuration(ModuleFinder finder, Map<String, Set<String>> map) {
169         int moduleCount = map.size();
170
171         // create map of name -> ResolvedModule
172         @SuppressWarnings(value = {"rawtypes""unchecked"})
173         Entry<String, ResolvedModule>[] nameEntries
174             = (Entry<String, ResolvedModule>[])new Entry[moduleCount];
175         ResolvedModule[] moduleArray = new ResolvedModule[moduleCount];
176         String targetPlatform = null;
177         int i = 0;
178         for (String name : map.keySet()) {
179             ModuleReference mref = finder.find(name).orElse(null);
180             assert mref != null;
181
182             if (targetPlatform == null && mref instanceof ModuleReferenceImpl) {
183                 ModuleTarget target = ((ModuleReferenceImpl)mref).moduleTarget();
184                 if (target != null) {
185                     targetPlatform = target.targetPlatform();
186                 }
187             }
188
189             ResolvedModule resolvedModule = new ResolvedModule(this, mref);
190             moduleArray[i] = resolvedModule;
191             nameEntries[i] = Map.entry(name, resolvedModule);
192             i++;
193         }
194         Map<String, ResolvedModule> nameToModule = Map.ofEntries(nameEntries);
195
196         // create entries for readability graph
197         @SuppressWarnings(value = {"rawtypes""unchecked"})
198         Entry<ResolvedModule, Set<ResolvedModule>>[] moduleEntries
199             = (Entry<ResolvedModule, Set<ResolvedModule>>[])new Entry[moduleCount];
200         i = 0;
201         for (ResolvedModule resolvedModule : moduleArray) {
202             Set<String> names = map.get(resolvedModule.name());
203             ResolvedModule[] readsArray = new ResolvedModule[names.size()];
204             int j = 0;
205             for (String name : names) {
206                 readsArray[j++] = nameToModule.get(name);
207             }
208             moduleEntries[i++] = Map.entry(resolvedModule, Set.of(readsArray));
209         }
210
211         this.parents = List.of(empty());
212         this.graph = Map.ofEntries(moduleEntries);
213         this.modules = Set.of(moduleArray);
214         this.nameToModule = nameToModule;
215         this.targetPlatform = targetPlatform;
216     }
217
218     /**
219      * Resolves a collection of root modules, with this configuration as its
220      * parent, to create a new configuration. This method works exactly as
221      * specified by the static {@link
222      * #resolve(ModuleFinder,List,ModuleFinder,Collection) resolve}
223      * method when invoked with this configuration as the parent. In other words,
224      * if this configuration is {@code cf} then this method is equivalent to
225      * invoking:
226      * <pre> {@code
227      *     Configuration.resolve(before, List.of(cf), after, roots);
228      * }</pre>
229      *
230      * @param  before
231      *         The <em>before</em> module finder to find modules
232      * @param  after
233      *         The <em>after</em> module finder to locate modules when not
234      *         located by the {@code before} module finder or in parent
235      *         configurations
236      * @param  roots
237      *         The possibly-empty collection of module names of the modules
238      *         to resolve
239      *
240      * @return The configuration that is the result of resolving the given
241      *         root modules
242      *
243      * @throws FindException
244      *         If resolution fails for any of the observability-related reasons
245      *         specified by the static {@code resolve} method
246      * @throws ResolutionException
247      *         If resolution fails any of the consistency checks specified by
248      *         the static {@code resolve} method
249      * @throws SecurityException
250      *         If locating a module is denied by the security manager
251      */

252     public Configuration resolve(ModuleFinder before,
253                                  ModuleFinder after,
254                                  Collection<String> roots)
255     {
256         return resolve(before, List.of(this), after, roots);
257     }
258
259
260     /**
261      * Resolves a collection of root modules, with service binding, and with
262      * this configuration as its parent, to create a new configuration.
263      * This method works exactly as specified by the static {@link
264      * #resolveAndBind(ModuleFinder,List,ModuleFinder,Collection)
265      * resolveAndBind} method when invoked with this configuration
266      * as the parent. In other words, if this configuration is {@code cf} then
267      * this method is equivalent to invoking:
268      * <pre> {@code
269      *     Configuration.resolveAndBind(before, List.of(cf), after, roots);
270      * }</pre>
271      *
272      *
273      * @param  before
274      *         The <em>before</em> module finder to find modules
275      * @param  after
276      *         The <em>after</em> module finder to locate modules when not
277      *         located by the {@code before} module finder or in parent
278      *         configurations
279      * @param  roots
280      *         The possibly-empty collection of module names of the modules
281      *         to resolve
282      *
283      * @return The configuration that is the result of resolving, with service
284      *         binding, the given root modules
285      *
286      * @throws FindException
287      *         If resolution fails for any of the observability-related reasons
288      *         specified by the static {@code resolve} method
289      * @throws ResolutionException
290      *         If resolution fails any of the consistency checks specified by
291      *         the static {@code resolve} method
292      * @throws SecurityException
293      *         If locating a module is denied by the security manager
294      */

295     public Configuration resolveAndBind(ModuleFinder before,
296                                         ModuleFinder after,
297                                         Collection<String> roots)
298     {
299         return resolveAndBind(before, List.of(this), after, roots);
300     }
301
302
303     /**
304      * Resolves a collection of root modules, with service binding, and with
305      * the empty configuration as its parent.
306      *
307      * This method is used to create the configuration for the boot layer.
308      */

309     static Configuration resolveAndBind(ModuleFinder finder,
310                                         Collection<String> roots,
311                                         PrintStream traceOutput)
312     {
313         List<Configuration> parents = List.of(empty());
314         Resolver resolver = new Resolver(finder, parents, ModuleFinder.of(), traceOutput);
315         resolver.resolve(roots).bind();
316         return new Configuration(parents, resolver);
317     }
318
319     /**
320      * Resolves a collection of root modules to create a configuration.
321      *
322      * <p> Each root module is located using the given {@code before} module
323      * finder. If a module is not found then it is located in the parent
324      * configuration as if by invoking the {@link #findModule(String)
325      * findModule} method on each parent in iteration order. If not found then
326      * the module is located using the given {@code after} module finder. The
327      * same search order is used to locate transitive dependences. Root modules
328      * or dependences that are located in a parent configuration are resolved
329      * no further and are not included in the resulting configuration. </p>
330      *
331      * <p> When all modules have been enumerated then a readability graph
332      * is computed, and in conjunction with the module exports and service use,
333      * checked for consistency. </p>
334      *
335      * <p> Resolution may fail with {@code FindException} for the following
336      * <em>observability-related</em> reasons: </p>
337      *
338      * <ul>
339      *
340      *     <li><p> A root module, or a direct or transitive dependency, is not
341      *     found. </p></li>
342      *
343      *     <li><p> An error occurs when attempting to find a module.
344      *     Possible errors include I/O errors, errors detected parsing a module
345      *     descriptor ({@code module-info.class}) or two versions of the same
346      *     module are found in the same directory. </p></li>
347      *
348      * </ul>
349      *
350      * <p> Resolution may fail with {@code ResolutionException} if any of the
351      * following consistency checks fail: </p>
352      *
353      * <ul>
354      *
355      *     <li><p> A cycle is detected, say where module {@code m1} requires
356      *     module {@code m2} and {@code m2} requires {@code m1}. </p></li>
357      *
358      *     <li><p> A module reads two or more modules with the same name. This
359      *     includes the case where a module reads another with the same name as
360      *     itself. </p></li>
361      *
362      *     <li><p> Two or more modules in the configuration export the same
363      *     package to a module that reads both. This includes the case where a
364      *     module {@code M} containing package {@code p} reads another module
365      *     that exports {@code p} to {@code M}. </p></li>
366      *
367      *     <li><p> A module {@code M} declares that it "{@code uses p.S}" or
368      *     "{@code provides p.S with ...}" but package {@code p} is neither in
369      *     module {@code M} nor exported to {@code M} by any module that
370      *     {@code M} reads. </p></li>
371      *
372      * </ul>
373      *
374      * @implNote In the implementation then observability of modules may depend
375      * on referential integrity or other checks that ensure different builds of
376      * tightly coupled modules or modules for specific operating systems or
377      * architectures are not combined in the same configuration.
378      *
379      * @param  before
380      *         The <em>before</em> module finder to find modules
381      * @param  parents
382      *         The list parent configurations in search order
383      * @param  after
384      *         The <em>after</em> module finder to locate modules when not
385      *         located by the {@code before} module finder or in parent
386      *         configurations
387      * @param  roots
388      *         The possibly-empty collection of module names of the modules
389      *         to resolve
390      *
391      * @return The configuration that is the result of resolving the given
392      *         root modules
393      *
394      * @throws FindException
395      *         If resolution fails for any of observability-related reasons
396      *         specified above
397      * @throws ResolutionException
398      *         If resolution fails for any of the consistency checks specified
399      *         above
400      * @throws IllegalArgumentException
401      *         If the list of parents is empty, or the list has two or more
402      *         parents with modules for different target operating systems,
403      *         architectures, or versions
404      *
405      * @throws SecurityException
406      *         If locating a module is denied by the security manager
407      */

408     public static Configuration resolve(ModuleFinder before,
409                                         List<Configuration> parents,
410                                         ModuleFinder after,
411                                         Collection<String> roots)
412     {
413         Objects.requireNonNull(before);
414         Objects.requireNonNull(after);
415         Objects.requireNonNull(roots);
416
417         List<Configuration> parentList = new ArrayList<>(parents);
418         if (parentList.isEmpty())
419             throw new IllegalArgumentException("'parents' is empty");
420
421         Resolver resolver = new Resolver(before, parentList, after, null);
422         resolver.resolve(roots);
423
424         return new Configuration(parentList, resolver);
425     }
426
427     /**
428      * Resolves a collection of root modules, with service binding, to create
429      * configuration.
430      *
431      * <p> This method works exactly as specified by {@link
432      * #resolve(ModuleFinder,List,ModuleFinder,Collection)
433      * resolve} except that the graph of resolved modules is augmented
434      * with modules induced by the service-use dependence relation. </p>
435      *
436      * <p><a id="service-binding"></a>More specifically, the root modules are
437      * resolved as if by calling {@code resolve}. The resolved modules, and
438      * all modules in the parent configurations, with {@link ModuleDescriptor#uses()
439      * service dependences} are then examined. All modules found by the given
440      * module finders that {@link ModuleDescriptor#provides() provide} an
441      * implementation of one or more of the service types are added to the
442      * module graph and then resolved as if by calling the {@code
443      * resolve} method. Adding modules to the module graph may introduce new
444      * service-use dependences and so the process works iteratively until no
445      * more modules are added. </p>
446      *
447      * <p> As service binding involves resolution then it may fail with {@code
448      * FindException} or {@code ResolutionException} for exactly the same
449      * reasons specified in {@code resolve}. </p>
450      *
451      * @param  before
452      *         The <em>before</em> module finder to find modules
453      * @param  parents
454      *         The list parent configurations in search order
455      * @param  after
456      *         The <em>after</em> module finder to locate modules when not
457      *         located by the {@code before} module finder or in parent
458      *         configurations
459      * @param  roots
460      *         The possibly-empty collection of module names of the modules
461      *         to resolve
462      *
463      * @return The configuration that is the result of resolving, with service
464      *         binding, the given root modules
465      *
466      * @throws FindException
467      *         If resolution fails for any of the observability-related reasons
468      *         specified by the static {@code resolve} method
469      * @throws ResolutionException
470      *         If resolution fails any of the consistency checks specified by
471      *         the static {@code resolve} method
472      * @throws IllegalArgumentException
473      *         If the list of parents is empty, or the list has two or more
474      *         parents with modules for different target operating systems,
475      *         architectures, or versions
476      * @throws SecurityException
477      *         If locating a module is denied by the security manager
478      */

479     public static Configuration resolveAndBind(ModuleFinder before,
480                                                List<Configuration> parents,
481                                                ModuleFinder after,
482                                                Collection<String> roots)
483     {
484         Objects.requireNonNull(before);
485         Objects.requireNonNull(after);
486         Objects.requireNonNull(roots);
487
488         List<Configuration> parentList = new ArrayList<>(parents);
489         if (parentList.isEmpty())
490             throw new IllegalArgumentException("'parents' is empty");
491
492         Resolver resolver = new Resolver(before, parentList, after, null);
493         resolver.resolve(roots).bind();
494
495         return new Configuration(parentList, resolver);
496     }
497
498
499     /**
500      * Returns the <em>empty</em> configuration. There are no modules in the
501      * empty configuration. It has no parents.
502      *
503      * @return The empty configuration
504      */

505     public static Configuration empty() {
506         return EMPTY_CONFIGURATION;
507     }
508
509
510     /**
511      * Returns an unmodifiable list of this configuration's parents, in search
512      * order. If this is the {@linkplain #empty empty configuration} then an
513      * empty list is returned.
514      *
515      * @return A possibly-empty unmodifiable list of this parent configurations
516      */

517     public List<Configuration> parents() {
518         return parents;
519     }
520
521
522     /**
523      * Returns an immutable set of the resolved modules in this configuration.
524      *
525      * @return A possibly-empty unmodifiable set of the resolved modules
526      *         in this configuration
527      */

528     public Set<ResolvedModule> modules() {
529         return modules;
530     }
531
532
533     /**
534      * Finds a resolved module in this configuration, or if not in this
535      * configuration, the {@linkplain #parents() parent} configurations.
536      * Finding a module in parent configurations is equivalent to invoking
537      * {@code findModule} on each parent, in search order, until the module
538      * is found or all parents have been searched. In a <em>tree of
539      * configurations</em> then this is equivalent to a depth-first search.
540      *
541      * @param  name
542      *         The module name of the resolved module to find
543      *
544      * @return The resolved module with the given name or an empty {@code
545      *         Optional} if there isn't a module with this name in this
546      *         configuration or any parent configurations
547      */

548     public Optional<ResolvedModule> findModule(String name) {
549         Objects.requireNonNull(name);
550         ResolvedModule m = nameToModule.get(name);
551         if (m != null)
552             return Optional.of(m);
553
554         if (!parents.isEmpty()) {
555             return configurations()
556                     .skip(1)  // skip this configuration
557                     .map(cf -> cf.nameToModule.get(name))
558                     .filter(Objects::nonNull)
559                     .findFirst();
560         }
561
562         return Optional.empty();
563     }
564
565
566     Set<ModuleDescriptor> descriptors() {
567         if (modules.isEmpty()) {
568             return Set.of();
569         } else {
570             return modules.stream()
571                     .map(ResolvedModule::reference)
572                     .map(ModuleReference::descriptor)
573                     .collect(Collectors.toSet());
574         }
575     }
576
577     Set<ResolvedModule> reads(ResolvedModule m) {
578         return Collections.unmodifiableSet(graph.get(m));
579     }
580
581     /**
582      * Returns an ordered stream of configurations. The first element is this
583      * configuration, the remaining elements are the parent configurations
584      * in DFS order.
585      *
586      * @implNote For now, the assumption is that the number of elements will
587      * be very low and so this method does not use a specialized spliterator.
588      */

589     Stream<Configuration> configurations() {
590         List<Configuration> allConfigurations = this.allConfigurations;
591         if (allConfigurations == null) {
592             allConfigurations = new ArrayList<>();
593             Set<Configuration> visited = new HashSet<>();
594             Deque<Configuration> stack = new ArrayDeque<>();
595             visited.add(this);
596             stack.push(this);
597             while (!stack.isEmpty()) {
598                 Configuration layer = stack.pop();
599                 allConfigurations.add(layer);
600
601                 // push in reverse order
602                 for (int i = layer.parents.size() - 1; i >= 0; i--) {
603                     Configuration parent = layer.parents.get(i);
604                     if (!visited.contains(parent)) {
605                         visited.add(parent);
606                         stack.push(parent);
607                     }
608                 }
609             }
610             this.allConfigurations = allConfigurations; // no need to do defensive copy
611         }
612         return allConfigurations.stream();
613     }
614
615     private volatile List<Configuration> allConfigurations;
616
617
618     /**
619      * Returns a string describing this configuration.
620      *
621      * @return A possibly empty string describing this configuration
622      */

623     @Override
624     public String toString() {
625         return modules().stream()
626                 .map(ResolvedModule::name)
627                 .collect(Collectors.joining(", "));
628     }
629 }
630