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 23 * questions. 24 */ 25 26 package java.lang.reflect; 27 28 import java.lang.module.Configuration; 29 import java.lang.module.ModuleDescriptor; 30 import java.lang.module.ResolvedModule; 31 import java.util.ArrayDeque; 32 import java.util.ArrayList; 33 import java.util.Collections; 34 import java.util.Deque; 35 import java.util.HashMap; 36 import java.util.HashSet; 37 import java.util.List; 38 import java.util.Map; 39 import java.util.Objects; 40 import java.util.Optional; 41 import java.util.Set; 42 import java.util.concurrent.CopyOnWriteArrayList; 43 import java.util.function.Function; 44 import java.util.stream.Collectors; 45 import java.util.stream.Stream; 46 47 import jdk.internal.loader.ClassLoaderValue; 48 import jdk.internal.loader.Loader; 49 import jdk.internal.loader.LoaderPool; 50 import jdk.internal.misc.SharedSecrets; 51 import jdk.internal.module.Modules; 52 import jdk.internal.module.ServicesCatalog; 53 import sun.security.util.SecurityConstants; 54 55 56 /** 57 * A layer of modules in the Java virtual machine. 58 * 59 * <p> A layer is created from a graph of modules in a {@link Configuration} 60 * and a function that maps each module to a {@link ClassLoader}. 61 * Creating a layer informs the Java virtual machine about the classes that 62 * may be loaded from the modules so that the Java virtual machine knows which 63 * module that each class is a member of. </p> 64 * 65 * <p> Creating a layer creates a {@link Module} object for each {@link 66 * ResolvedModule} in the configuration. For each resolved module that is 67 * {@link ResolvedModule#reads() read}, the {@code Module} {@link 68 * Module#canRead reads} the corresponding run-time {@code Module}, which may 69 * be in the same layer or a {@link #parents() parent} layer. The {@code Module} 70 * {@link Module#isExported(String) exports} and {@link Module#isOpen(String) 71 * opens} the packages described by its {@link ModuleDescriptor}. </p> 72 * 73 * <p> The {@link #defineModulesWithOneLoader defineModulesWithOneLoader} and 74 * {@link #defineModulesWithManyLoaders defineModulesWithManyLoaders} methods 75 * provide convenient ways to create a {@code Layer} where all modules are 76 * mapped to a single class loader or where each module is mapped to its own 77 * class loader. The {@link #defineModules defineModules} method is for more 78 * advanced cases where modules are mapped to custom class loaders by means of 79 * a function specified to the method. Each of these methods has an instance 80 * and static variant. The instance methods create a layer with the receiver 81 * as the parent layer. The static methods are for more advanced cases where 82 * there can be more than one parent layer or where a {@link Layer.Controller 83 * Controller} is needed to control modules in the layer. </p> 84 * 85 * <p> A Java virtual machine has at least one non-empty layer, the {@link 86 * #boot() boot} layer, that is created when the Java virtual machine is 87 * started. The boot layer contains module {@code java.base} and is the only 88 * layer in the Java virtual machine with a module named "{@code java.base}". 89 * The modules in the boot layer are mapped to the bootstrap class loader and 90 * other class loaders that are <a href="../ClassLoader.html#builtinLoaders"> 91 * built-in</a> into the Java virtual machine. The boot layer will often be 92 * the {@link #parents() parent} when creating additional layers. </p> 93 * 94 * <p> As when creating a {@code Configuration}, 95 * {@link ModuleDescriptor#isAutomatic() automatic} modules receive special 96 * treatment when creating a layer. An automatic module is created in the 97 * Java virtual machine as a {@code Module} that reads every unnamed {@code 98 * Module} in the Java virtual machine. </p> 99 * 100 * <p> Unless otherwise specified, passing a {@code null} argument to a method 101 * in this class causes a {@link NullPointerException NullPointerException} to 102 * be thrown. </p> 103 * 104 * <h3> Example usage: </h3> 105 * 106 * <p> This example creates a configuration by resolving a module named 107 * "{@code myapp}" with the configuration for the boot layer as the parent. It 108 * then creates a new layer with the modules in this configuration. All modules 109 * are defined to the same class loader. </p> 110 * 111 * <pre>{@code 112 * ModuleFinder finder = ModuleFinder.of(dir1, dir2, dir3); 113 * 114 * Layer parent = Layer.boot(); 115 * 116 * Configuration cf = parent.configuration().resolve(finder, ModuleFinder.of(), Set.of("myapp")); 117 * 118 * ClassLoader scl = ClassLoader.getSystemClassLoader(); 119 * 120 * Layer layer = parent.defineModulesWithOneLoader(cf, scl); 121 * 122 * Class<?> c = layer.findLoader("myapp").loadClass("app.Main"); 123 * }</pre> 124 * 125 * @since 9 126 * @spec JPMS 127 * @see Module#getLayer() 128 */ 129 130 public final class Layer { 131 132 // the empty Layer 133 private static final Layer EMPTY_LAYER 134 = new Layer(Configuration.empty(), List.of(), null); 135 136 // the configuration from which this Layer was created 137 private final Configuration cf; 138 139 // parent layers, empty in the case of the empty layer 140 private final List<Layer> parents; 141 142 // maps module name to jlr.Module 143 private final Map<String, Module> nameToModule; 144 145 /** 146 * Creates a new Layer from the modules in the given configuration. 147 */ 148 private Layer(Configuration cf, 149 List<Layer> parents, 150 Function<String, ClassLoader> clf) 151 { 152 this.cf = cf; 153 this.parents = parents; // no need to do defensive copy 154 155 Map<String, Module> map; 156 if (parents.isEmpty()) { 157 map = Collections.emptyMap(); 158 } else { 159 map = Module.defineModules(cf, clf, this); 160 } 161 this.nameToModule = map; // no need to do defensive copy 162 } 163 164 /** 165 * Controls a layer. The static methods defined by {@link Layer} to create 166 * module layers return a {@code Controller} that can be used to control 167 * modules in the layer. 168 * 169 * <p> Unless otherwise specified, passing a {@code null} argument to a 170 * method in this class causes a {@link NullPointerException 171 * NullPointerException} to be thrown. </p> 172 * 173 * @apiNote Care should be taken with {@code Controller} objects, they 174 * should never be shared with untrusted code. 175 * 176 * @since 9 177 * @spec JPMS 178 */ 179 public static final class Controller { 180 private final Layer layer; 181 182 Controller(Layer layer) { 183 this.layer = layer; 184 } 185 186 /** 187 * Returns the layer that this object controls. 188 * 189 * @return the layer 190 */ 191 public Layer layer() { 192 return layer; 193 } 194 195 private void ensureInLayer(Module source) { 196 if (!layer.modules().contains(source)) 197 throw new IllegalArgumentException(source + " not in layer"); 198 } 199 200 201 /** 202 * Updates module {@code source} in the layer to read module 203 * {@code target}. This method is a no-op if {@code source} already 204 * reads {@code target}. 205 * 206 * @implNote <em>Read edges</em> added by this method are <em>weak</em> 207 * and do not prevent {@code target} from being GC'ed when {@code source} 208 * is strongly reachable. 209 * 210 * @param source 211 * The source module 212 * @param target 213 * The target module to read 214 * 215 * @return This controller 216 * 217 * @throws IllegalArgumentException 218 * If {@code source} is not in the layer 219 * 220 * @see Module#addReads 221 */ 222 public Controller addReads(Module source, Module target) { 223 Objects.requireNonNull(source); 224 Objects.requireNonNull(target); 225 ensureInLayer(source); 226 Modules.addReads(source, target); 227 return this; 228 } 229 230 /** 231 * Updates module {@code source} in the layer to open a package to 232 * module {@code target}. This method is a no-op if {@code source} 233 * already opens the package to at least {@code target}. 234 * 235 * @param source 236 * The source module 237 * @param pn 238 * The package name 239 * @param target 240 * The target module to read 241 * 242 * @return This controller 243 * 244 * @throws IllegalArgumentException 245 * If {@code source} is not in the layer or the package is not 246 * in the source module 247 * 248 * @see Module#addOpens 249 */ 250 public Controller addOpens(Module source, String pn, Module target) { 251 Objects.requireNonNull(source); 252 Objects.requireNonNull(target); 253 ensureInLayer(source); 254 Modules.addOpens(source, pn, target); 255 return this; 256 } 257 } 258 259 260 /** 261 * Creates a new layer, with this layer as its parent, by defining the 262 * modules in the given {@code Configuration} to the Java virtual machine. 263 * This method creates one class loader and defines all modules to that 264 * class loader. The {@link ClassLoader#getParent() parent} of each class 265 * loader is the given parent class loader. This method works exactly as 266 * specified by the static {@link 267 * #defineModulesWithOneLoader(Configuration,List,ClassLoader) 268 * defineModulesWithOneLoader} method when invoked with this layer as the 269 * parent. In other words, if this layer is {@code thisLayer} then this 270 * method is equivalent to invoking: 271 * <pre> {@code 272 * Layer.defineModulesWithOneLoader(cf, List.of(thisLayer), parentLoader).layer(); 273 * }</pre> 274 * 275 * @param cf 276 * The configuration for the layer 277 * @param parentLoader 278 * The parent class loader for the class loader created by this 279 * method; may be {@code null} for the bootstrap class loader 280 * 281 * @return The newly created layer 282 * 283 * @throws IllegalArgumentException 284 * If the parent of the given configuration is not the configuration 285 * for this layer 286 * @throws LayerInstantiationException 287 * If the layer cannot be created for any of the reasons specified 288 * by the static {@code defineModulesWithOneLoader} method 289 * @throws SecurityException 290 * If {@code RuntimePermission("createClassLoader")} or 291 * {@code RuntimePermission("getClassLoader")} is denied by 292 * the security manager 293 * 294 * @see #findLoader 295 */ 296 public Layer defineModulesWithOneLoader(Configuration cf, 297 ClassLoader parentLoader) { 298 return defineModulesWithOneLoader(cf, List.of(this), parentLoader).layer(); 299 } 300 301 302 /** 303 * Creates a new layer, with this layer as its parent, by defining the 304 * modules in the given {@code Configuration} to the Java virtual machine. 305 * Each module is defined to its own {@link ClassLoader} created by this 306 * method. The {@link ClassLoader#getParent() parent} of each class loader 307 * is the given parent class loader. This method works exactly as specified 308 * by the static {@link 309 * #defineModulesWithManyLoaders(Configuration,List,ClassLoader) 310 * defineModulesWithManyLoaders} method when invoked with this layer as the 311 * parent. In other words, if this layer is {@code thisLayer} then this 312 * method is equivalent to invoking: 313 * <pre> {@code 314 * Layer.defineModulesWithManyLoaders(cf, List.of(thisLayer), parentLoader).layer(); 315 * }</pre> 316 * 317 * @param cf 318 * The configuration for the layer 319 * @param parentLoader 320 * The parent class loader for each of the class loaders created by 321 * this method; may be {@code null} for the bootstrap class loader 322 * 323 * @return The newly created layer 324 * 325 * @throws IllegalArgumentException 326 * If the parent of the given configuration is not the configuration 327 * for this layer 328 * @throws LayerInstantiationException 329 * If the layer cannot be created for any of the reasons specified 330 * by the static {@code defineModulesWithManyLoaders} method 331 * @throws SecurityException 332 * If {@code RuntimePermission("createClassLoader")} or 333 * {@code RuntimePermission("getClassLoader")} is denied by 334 * the security manager 335 * 336 * @see #findLoader 337 */ 338 public Layer defineModulesWithManyLoaders(Configuration cf, 339 ClassLoader parentLoader) { 340 return defineModulesWithManyLoaders(cf, List.of(this), parentLoader).layer(); 341 } 342 343 344 /** 345 * Creates a new layer, with this layer as its parent, by defining the 346 * modules in the given {@code Configuration} to the Java virtual machine. 347 * Each module is mapped, by name, to its class loader by means of the 348 * given function. This method works exactly as specified by the static 349 * {@link #defineModules(Configuration,List,Function) defineModules} 350 * method when invoked with this layer as the parent. In other words, if 351 * this layer is {@code thisLayer} then this method is equivalent to 352 * invoking: 353 * <pre> {@code 354 * Layer.defineModules(cf, List.of(thisLayer), clf).layer(); 355 * }</pre> 356 * 357 * @param cf 358 * The configuration for the layer 359 * @param clf 360 * The function to map a module name to a class loader 361 * 362 * @return The newly created layer 363 * 364 * @throws IllegalArgumentException 365 * If the parent of the given configuration is not the configuration 366 * for this layer 367 * @throws LayerInstantiationException 368 * If the layer cannot be created for any of the reasons specified 369 * by the static {@code defineModules} method 370 * @throws SecurityException 371 * If {@code RuntimePermission("getClassLoader")} is denied by 372 * the security manager 373 */ 374 public Layer defineModules(Configuration cf, 375 Function<String, ClassLoader> clf) { 376 return defineModules(cf, List.of(this), clf).layer(); 377 } 378 379 /** 380 * Creates a new layer by defining the modules in the given {@code 381 * Configuration} to the Java virtual machine. This method creates one 382 * class loader and defines all modules to that class loader. 383 * 384 * <p> The class loader created by this method implements <em>direct 385 * delegation</em> when loading types from modules. When its {@link 386 * ClassLoader#loadClass(String, boolean) loadClass} method is invoked to 387 * load a class then it uses the package name of the class to map it to a 388 * module. This may be a module in this layer and hence defined to the same 389 * class loader. It may be a package in a module in a parent layer that is 390 * exported to one or more of the modules in this layer. The class 391 * loader delegates to the class loader of the module, throwing {@code 392 * ClassNotFoundException} if not found by that class loader. 393 * When {@code loadClass} is invoked to load classes that do not map to a 394 * module then it delegates to the parent class loader. </p> 395 * 396 * <p> Attempting to create a layer with all modules defined to the same 397 * class loader can fail for the following reasons: 398 * 399 * <ul> 400 * 401 * <li><p> <em>Overlapping packages</em>: Two or more modules in the 402 * configuration have the same package. </p></li> 403 * 404 * <li><p> <em>Split delegation</em>: The resulting class loader would 405 * need to delegate to more than one class loader in order to load types 406 * in a specific package. </p></li> 407 * 408 * </ul> 409 * 410 * <p> In addition, a layer cannot be created if the configuration contains 411 * a module named "{@code java.base}" or a module with a package name 412 * starting with "{@code java.}". </p> 413 * 414 * <p> If there is a security manager then the class loader created by 415 * this method will load classes and resources with privileges that are 416 * restricted by the calling context of this method. </p> 417 * 418 * @param cf 419 * The configuration for the layer 420 * @param parentLayers 421 * The list parent layers in search order 422 * @param parentLoader 423 * The parent class loader for the class loader created by this 424 * method; may be {@code null} for the bootstrap class loader 425 * 426 * @return A controller that controls the newly created layer 427 * 428 * @throws IllegalArgumentException 429 * If the parent configurations do not match the configuration of 430 * the parent layers, including order 431 * @throws LayerInstantiationException 432 * If all modules cannot be defined to the same class loader for any 433 * of the reasons listed above 434 * @throws SecurityException 435 * If {@code RuntimePermission("createClassLoader")} or 436 * {@code RuntimePermission("getClassLoader")} is denied by 437 * the security manager 438 * 439 * @see #findLoader 440 */ 441 public static Controller defineModulesWithOneLoader(Configuration cf, 442 List<Layer> parentLayers, 443 ClassLoader parentLoader) 444 { 445 List<Layer> parents = new ArrayList<>(parentLayers); 446 checkConfiguration(cf, parents); 447 448 checkCreateClassLoaderPermission(); 449 checkGetClassLoaderPermission(); 450 451 try { 452 Loader loader = new Loader(cf.modules(), parentLoader); 453 loader.initRemotePackageMap(cf, parents); 454 Layer layer = new Layer(cf, parents, mn -> loader); 455 return new Controller(layer); 456 } catch (IllegalArgumentException | IllegalStateException e) { 457 throw new LayerInstantiationException(e.getMessage()); 458 } 459 } 460 461 /** 462 * Creates a new layer by defining the modules in the given {@code 463 * Configuration} to the Java virtual machine. Each module is defined to 464 * its own {@link ClassLoader} created by this method. The {@link 465 * ClassLoader#getParent() parent} of each class loader is the given parent 466 * class loader. 467 * 468 * <p> The class loaders created by this method implement <em>direct 469 * delegation</em> when loading types from modules. When {@link 470 * ClassLoader#loadClass(String, boolean) loadClass} method is invoked to 471 * load a class then it uses the package name of the class to map it to a 472 * module. The package may be in the module defined to the class loader. 473 * The package may be exported by another module in this layer to the 474 * module defined to the class loader. It may be in a package exported by a 475 * module in a parent layer. The class loader delegates to the class loader 476 * of the module, throwing {@code ClassNotFoundException} if not found by 477 * that class loader. 478 * When {@code loadClass} is invoked to load classes that do not map to a 479 * module then it delegates to the parent class loader. </p> 480 * 481 * <p> If there is a security manager then the class loaders created by 482 * this method will load classes and resources with privileges that are 483 * restricted by the calling context of this method. </p> 484 * 485 * @param cf 486 * The configuration for the layer 487 * @param parentLayers 488 * The list parent layers in search order 489 * @param parentLoader 490 * The parent class loader for each of the class loaders created by 491 * this method; may be {@code null} for the bootstrap class loader 492 * 493 * @return A controller that controls the newly created layer 494 * 495 * @throws IllegalArgumentException 496 * If the parent configurations do not match the configuration of 497 * the parent layers, including order 498 * @throws LayerInstantiationException 499 * If the layer cannot be created because the configuration contains 500 * a module named "{@code java.base}" or a module with a package 501 * name starting with "{@code java.}" 502 * @throws SecurityException 503 * If {@code RuntimePermission("createClassLoader")} or 504 * {@code RuntimePermission("getClassLoader")} is denied by 505 * the security manager 506 * 507 * @see #findLoader 508 */ 509 public static Controller defineModulesWithManyLoaders(Configuration cf, 510 List<Layer> parentLayers, 511 ClassLoader parentLoader) 512 { 513 List<Layer> parents = new ArrayList<>(parentLayers); 514 checkConfiguration(cf, parents); 515 516 checkCreateClassLoaderPermission(); 517 checkGetClassLoaderPermission(); 518 519 LoaderPool pool = new LoaderPool(cf, parents, parentLoader); 520 try { 521 Layer layer = new Layer(cf, parents, pool::loaderFor); 522 return new Controller(layer); 523 } catch (IllegalArgumentException | IllegalStateException e) { 524 throw new LayerInstantiationException(e.getMessage()); 525 } 526 } 527 528 /** 529 * Creates a new layer by defining the modules in the given {@code 530 * Configuration} to the Java virtual machine. The given function maps each 531 * module in the configuration, by name, to a class loader. Creating the 532 * layer informs the Java virtual machine about the classes that may be 533 * loaded so that the Java virtual machine knows which module that each 534 * class is a member of. 535 * 536 * <p> The class loader delegation implemented by the class loaders must 537 * respect module readability. The class loaders should be 538 * {@link ClassLoader#registerAsParallelCapable parallel-capable} so as to 539 * avoid deadlocks during class loading. In addition, the entity creating 540 * a new layer with this method should arrange that the class loaders be 541 * ready to load from these modules before there are any attempts to load 542 * classes or resources. </p> 543 * 544 * <p> Creating a {@code Layer} can fail for the following reasons: </p> 545 * 546 * <ul> 547 * 548 * <li><p> Two or more modules with the same package are mapped to the 549 * same class loader. </p></li> 550 * 551 * <li><p> A module is mapped to a class loader that already has a 552 * module of the same name defined to it. </p></li> 553 * 554 * <li><p> A module is mapped to a class loader that has already 555 * defined types in any of the packages in the module. </p></li> 556 * 557 * </ul> 558 * 559 * <p> In addition, a layer cannot be created if the configuration contains 560 * a module named "{@code java.base}", a configuration contains a module 561 * with a package name starting with "{@code java.}" is mapped to a class 562 * loader other than the {@link ClassLoader#getPlatformClassLoader() 563 * platform class loader}, or the function to map a module name to a class 564 * loader returns {@code null}. </p> 565 * 566 * <p> If the function to map a module name to class loader throws an error 567 * or runtime exception then it is propagated to the caller of this method. 568 * </p> 569 * 570 * @apiNote It is implementation specific as to whether creating a Layer 571 * with this method is an atomic operation or not. Consequentially it is 572 * possible for this method to fail with some modules, but not all, defined 573 * to the Java virtual machine. 574 * 575 * @param cf 576 * The configuration for the layer 577 * @param parentLayers 578 * The list parent layers in search order 579 * @param clf 580 * The function to map a module name to a class loader 581 * 582 * @return A controller that controls the newly created layer 583 * 584 * @throws IllegalArgumentException 585 * If the parent configurations do not match the configuration of 586 * the parent layers, including order 587 * @throws LayerInstantiationException 588 * If creating the layer fails for any of the reasons listed above 589 * @throws SecurityException 590 * If {@code RuntimePermission("getClassLoader")} is denied by 591 * the security manager 592 */ 593 public static Controller defineModules(Configuration cf, 594 List<Layer> parentLayers, 595 Function<String, ClassLoader> clf) 596 { 597 List<Layer> parents = new ArrayList<>(parentLayers); 598 checkConfiguration(cf, parents); 599 Objects.requireNonNull(clf); 600 601 checkGetClassLoaderPermission(); 602 603 // The boot layer is checked during module system initialization 604 if (boot() != null) { 605 checkForDuplicatePkgs(cf, clf); 606 } 607 608 try { 609 Layer layer = new Layer(cf, parents, clf); 610 return new Controller(layer); 611 } catch (IllegalArgumentException | IllegalStateException e) { 612 throw new LayerInstantiationException(e.getMessage()); 613 } 614 } 615 616 617 /** 618 * Checks that the parent configurations match the configuration of 619 * the parent layers. 620 */ 621 private static void checkConfiguration(Configuration cf, 622 List<Layer> parentLayers) 623 { 624 Objects.requireNonNull(cf); 625 626 List<Configuration> parentConfigurations = cf.parents(); 627 if (parentLayers.size() != parentConfigurations.size()) 628 throw new IllegalArgumentException("wrong number of parents"); 629 630 int index = 0; 631 for (Layer parent : parentLayers) { 632 if (parent.configuration() != parentConfigurations.get(index)) { 633 throw new IllegalArgumentException( 634 "Parent of configuration != configuration of this Layer"); 635 } 636 index++; 637 } 638 } 639 640 private static void checkCreateClassLoaderPermission() { 641 SecurityManager sm = System.getSecurityManager(); 642 if (sm != null) 643 sm.checkPermission(SecurityConstants.CREATE_CLASSLOADER_PERMISSION); 644 } 645 646 private static void checkGetClassLoaderPermission() { 647 SecurityManager sm = System.getSecurityManager(); 648 if (sm != null) 649 sm.checkPermission(SecurityConstants.GET_CLASSLOADER_PERMISSION); 650 } 651 652 /** 653 * Checks a configuration and the module-to-loader mapping to ensure that 654 * no two modules mapped to the same class loader have the same package. 655 * It also checks that no two automatic modules have the same package. 656 * 657 * @throws LayerInstantiationException 658 */ 659 private static void checkForDuplicatePkgs(Configuration cf, 660 Function<String, ClassLoader> clf) 661 { 662 // HashMap allows null keys 663 Map<ClassLoader, Set<String>> loaderToPackages = new HashMap<>(); 664 for (ResolvedModule resolvedModule : cf.modules()) { 665 ModuleDescriptor descriptor = resolvedModule.reference().descriptor(); 666 ClassLoader loader = clf.apply(descriptor.name()); 667 668 Set<String> loaderPackages 669 = loaderToPackages.computeIfAbsent(loader, k -> new HashSet<>()); 670 671 for (String pkg : descriptor.packages()) { 672 boolean added = loaderPackages.add(pkg); 673 if (!added) { 674 throw fail("More than one module with package %s mapped" + 675 " to the same class loader", pkg); 676 } 677 } 678 } 679 } 680 681 /** 682 * Creates a LayerInstantiationException with the a message formatted from 683 * the given format string and arguments. 684 */ 685 private static LayerInstantiationException fail(String fmt, Object ... args) { 686 String msg = String.format(fmt, args); 687 return new LayerInstantiationException(msg); 688 } 689 690 691 /** 692 * Returns the configuration for this layer. 693 * 694 * @return The configuration for this layer 695 */ 696 public Configuration configuration() { 697 return cf; 698 } 699 700 701 /** 702 * Returns the list of this layer's parents unless this is the 703 * {@linkplain #empty empty layer}, which has no parents and so an 704 * empty list is returned. 705 * 706 * @return The list of this layer's parents 707 */ 708 public List<Layer> parents() { 709 return parents; 710 } 711 712 713 /** 714 * Returns an ordered stream of layers. The first element is is this layer, 715 * the remaining elements are the parent layers in DFS order. 716 * 717 * @implNote For now, the assumption is that the number of elements will 718 * be very low and so this method does not use a specialized spliterator. 719 */ 720 Stream<Layer> layers() { 721 List<Layer> allLayers = this.allLayers; 722 if (allLayers != null) 723 return allLayers.stream(); 724 725 allLayers = new ArrayList<>(); 726 Set<Layer> visited = new HashSet<>(); 727 Deque<Layer> stack = new ArrayDeque<>(); 728 visited.add(this); 729 stack.push(this); 730 731 while (!stack.isEmpty()) { 732 Layer layer = stack.pop(); 733 allLayers.add(layer); 734 735 // push in reverse order 736 for (int i = layer.parents.size() - 1; i >= 0; i--) { 737 Layer parent = layer.parents.get(i); 738 if (!visited.contains(parent)) { 739 visited.add(parent); 740 stack.push(parent); 741 } 742 } 743 } 744 745 this.allLayers = allLayers = Collections.unmodifiableList(allLayers); 746 return allLayers.stream(); 747 } 748 749 private volatile List<Layer> allLayers; 750 751 /** 752 * Returns the set of the modules in this layer. 753 * 754 * @return A possibly-empty unmodifiable set of the modules in this layer 755 */ 756 public Set<Module> modules() { 757 return Collections.unmodifiableSet( 758 nameToModule.values().stream().collect(Collectors.toSet())); 759 } 760 761 762 /** 763 * Returns the module with the given name in this layer, or if not in this 764 * layer, the {@linkplain #parents parent} layers. Finding a module in 765 * parent layers is equivalent to invoking {@code findModule} on each 766 * parent, in search order, until the module is found or all parents have 767 * been searched. In a <em>tree of layers</em> then this is equivalent to 768 * a depth-first search. 769 * 770 * @param name 771 * The name of the module to find 772 * 773 * @return The module with the given name or an empty {@code Optional} 774 * if there isn't a module with this name in this layer or any 775 * parent layer 776 */ 777 public Optional<Module> findModule(String name) { 778 Objects.requireNonNull(name); 779 Module m = nameToModule.get(name); 780 if (m != null) 781 return Optional.of(m); 782 783 return layers() 784 .skip(1) // skip this layer 785 .map(l -> l.nameToModule) 786 .filter(map -> map.containsKey(name)) 787 .map(map -> map.get(name)) 788 .findAny(); 789 } 790 791 792 /** 793 * Returns the {@code ClassLoader} for the module with the given name. If 794 * a module of the given name is not in this layer then the {@link #parents 795 * parent} layers are searched in the manner specified by {@link 796 * #findModule(String) findModule}. 797 * 798 * <p> If there is a security manager then its {@code checkPermission} 799 * method is called with a {@code RuntimePermission("getClassLoader")} 800 * permission to check that the caller is allowed to get access to the 801 * class loader. </p> 802 * 803 * @apiNote This method does not return an {@code Optional<ClassLoader>} 804 * because `null` must be used to represent the bootstrap class loader. 805 * 806 * @param name 807 * The name of the module to find 808 * 809 * @return The ClassLoader that the module is defined to 810 * 811 * @throws IllegalArgumentException if a module of the given name is not 812 * defined in this layer or any parent of this layer 813 * 814 * @throws SecurityException if denied by the security manager 815 */ 816 public ClassLoader findLoader(String name) { 817 Optional<Module> om = findModule(name); 818 819 // can't use map(Module::getClassLoader) as class loader can be null 820 if (om.isPresent()) { 821 return om.get().getClassLoader(); 822 } else { 823 throw new IllegalArgumentException("Module " + name 824 + " not known to this layer"); 825 } 826 } 827 828 /** 829 * Returns a string describing this layer. 830 * 831 * @return A possibly empty string describing this layer 832 */ 833 @Override 834 public String toString() { 835 return modules().stream() 836 .map(Module::getName) 837 .collect(Collectors.joining(", ")); 838 } 839 840 /** 841 * Returns the <em>empty</em> layer. There are no modules in the empty 842 * layer. It has no parents. 843 * 844 * @return The empty layer 845 */ 846 public static Layer empty() { 847 return EMPTY_LAYER; 848 } 849 850 851 /** 852 * Returns the boot layer. The boot layer contains at least one module, 853 * {@code java.base}. Its parent is the {@link #empty() empty} layer. 854 * 855 * @apiNote This method returns {@code null} during startup and before 856 * the boot layer is fully initialized. 857 * 858 * @return The boot layer 859 */ 860 public static Layer boot() { 861 return SharedSecrets.getJavaLangAccess().getBootLayer(); 862 } 863 864 865 /** 866 * Returns the ServicesCatalog for this Layer, creating it if not 867 * already created. 868 */ 869 ServicesCatalog getServicesCatalog() { 870 ServicesCatalog servicesCatalog = this.servicesCatalog; 871 if (servicesCatalog != null) 872 return servicesCatalog; 873 874 synchronized (this) { 875 servicesCatalog = this.servicesCatalog; 876 if (servicesCatalog == null) { 877 servicesCatalog = ServicesCatalog.create(); 878 nameToModule.values().forEach(servicesCatalog::register); 879 this.servicesCatalog = servicesCatalog; 880 } 881 } 882 883 return servicesCatalog; 884 } 885 886 private volatile ServicesCatalog servicesCatalog; 887 888 889 /** 890 * Record that this layer has at least one module defined to the given 891 * class loader. 892 */ 893 void bindToLoader(ClassLoader loader) { 894 // CLV.computeIfAbsent(loader, (cl, clv) -> new CopyOnWriteArrayList<>()) 895 List<Layer> list = CLV.get(loader); 896 if (list == null) { 897 list = new CopyOnWriteArrayList<>(); 898 List<Layer> previous = CLV.putIfAbsent(loader, list); 899 if (previous != null) list = previous; 900 } 901 list.add(this); 902 } 903 904 /** 905 * Returns a stream of the layers that have at least one module defined to 906 * the given class loader. 907 */ 908 static Stream<Layer> layers(ClassLoader loader) { 909 List<Layer> list = CLV.get(loader); 910 if (list != null) { 911 return list.stream(); 912 } else { 913 return Stream.empty(); 914 } 915 } 916 917 // the list of layers with modules defined to a class loader 918 private static final ClassLoaderValue<List<Layer>> CLV = new ClassLoaderValue<>(); 919 }