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 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 /** 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. 496 * 497 * @return A possibly-empty unmodifiable list of this parent configurations 498 */ 499 public List<Configuration> parents() { 500 return parents; 501 } 502 503 504 /** 505 * Returns an immutable set of the resolved modules in this configuration. 506 * 507 * @return A possibly-empty unmodifiable set of the resolved modules 508 * in this configuration 509 */ 510 public Set<ResolvedModule> modules() { 511 return modules; 512 } 513 514 515 /** 516 * Finds a resolved module in this configuration, or if not in this 517 * configuration, the {@linkplain #parents parent} configurations. 518 * Finding a module in parent configurations is equivalent to invoking 519 * {@code findModule} on each parent, in search order, until the module 520 * is found or all parents have been searched. In a <em>tree of 521 * configurations</em> then this is equivalent to a depth-first search. 522 * 523 * @param name 524 * The module name of the resolved module to find 525 * 526 * @return The resolved module with the given name or an empty {@code 527 * Optional} if there isn't a module with this name in this 528 * configuration or any parent configurations 529 */ 530 public Optional<ResolvedModule> findModule(String name) { 531 Objects.requireNonNull(name); 532 ResolvedModule m = nameToModule.get(name); 533 if (m != null) 534 return Optional.of(m); 535 536 if (!parents.isEmpty()) { 537 return configurations() 538 .skip(1) // skip this configuration 539 .map(cf -> cf.nameToModule) 540 .filter(map -> map.containsKey(name)) 541 .map(map -> map.get(name)) 542 .findFirst(); 543 } 544 545 return Optional.empty(); 546 } 547 548 549 Set<ModuleDescriptor> descriptors() { 550 if (modules.isEmpty()) { 551 return Collections.emptySet(); 552 } else { 553 return modules.stream() 554 .map(ResolvedModule::reference) 555 .map(ModuleReference::descriptor) 556 .collect(Collectors.toSet()); 557 } 558 } 559 560 Set<ResolvedModule> reads(ResolvedModule m) { 561 return Collections.unmodifiableSet(graph.get(m)); 562 } 563 564 /** 565 * Returns an ordered stream of configurations. The first element is this 566 * configuration, the remaining elements are the parent configurations 567 * in DFS order. 568 * 569 * @implNote For now, the assumption is that the number of elements will 570 * be very low and so this method does not use a specialized spliterator. 571 */ 572 Stream<Configuration> configurations() { 573 List<Configuration> allConfigurations = this.allConfigurations; 574 if (allConfigurations == null) { 575 allConfigurations = new ArrayList<>(); 576 Set<Configuration> visited = new HashSet<>(); 577 Deque<Configuration> stack = new ArrayDeque<>(); 578 visited.add(this); 579 stack.push(this); 580 while (!stack.isEmpty()) { 581 Configuration layer = stack.pop(); 582 allConfigurations.add(layer); 583 584 // push in reverse order 585 for (int i = layer.parents.size() - 1; i >= 0; i--) { 586 Configuration parent = layer.parents.get(i); 587 if (!visited.contains(parent)) { 588 visited.add(parent); 589 stack.push(parent); 590 } 591 } 592 } 593 this.allConfigurations = Collections.unmodifiableList(allConfigurations); 594 } 595 return allConfigurations.stream(); 596 } 597 598 private volatile List<Configuration> allConfigurations; 599 600 601 /** 602 * Returns a string describing this configuration. 603 * 604 * @return A possibly empty string describing this configuration 605 */ 606 @Override 607 public String toString() { 608 return modules().stream() 609 .map(ResolvedModule::name) 610 .collect(Collectors.joining(", ")); 611 } 612 }