1 /*
   2  * Copyright (c) 2015, 2019, 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 jdk.internal.loader;
  27 
  28 import java.io.IOException;
  29 import java.io.InputStream;
  30 import java.lang.module.ModuleDescriptor;
  31 import java.lang.module.ModuleReference;
  32 import java.lang.module.ModuleReader;
  33 import java.lang.ref.SoftReference;
  34 import java.net.MalformedURLException;
  35 import java.net.URI;
  36 import java.net.URL;
  37 import java.nio.ByteBuffer;
  38 import java.security.AccessController;
  39 import java.security.CodeSigner;
  40 import java.security.CodeSource;
  41 import java.security.PermissionCollection;
  42 import java.security.PrivilegedAction;
  43 import java.security.PrivilegedActionException;
  44 import java.security.PrivilegedExceptionAction;
  45 import java.security.SecureClassLoader;
  46 import java.util.ArrayList;
  47 import java.util.Collections;
  48 import java.util.Enumeration;
  49 import java.util.Iterator;
  50 import java.util.List;
  51 import java.util.Map;
  52 import java.util.NoSuchElementException;
  53 import java.util.Optional;
  54 import java.util.concurrent.ConcurrentHashMap;
  55 import java.util.function.Function;
  56 import java.util.jar.Attributes;
  57 import java.util.jar.Manifest;
  58 import java.util.stream.Stream;
  59 
  60 import jdk.internal.access.SharedSecrets;
  61 import jdk.internal.misc.VM;
  62 import jdk.internal.module.ModulePatcher.PatchedModuleReader;
  63 import jdk.internal.module.Resources;
  64 import jdk.internal.vm.annotation.Stable;
  65 import sun.security.util.LazyCodeSourcePermissionCollection;
  66 
  67 
  68 /**
  69  * The platform or application class loader. Resources loaded from modules
  70  * defined to the boot class loader are also loaded via an instance of this
  71  * ClassLoader type.
  72  *
  73  * <p> This ClassLoader supports loading of classes and resources from modules.
  74  * Modules are defined to the ClassLoader by invoking the {@link #loadModule}
  75  * method. Defining a module to this ClassLoader has the effect of making the
  76  * types in the module visible. </p>
  77  *
  78  * <p> This ClassLoader also supports loading of classes and resources from a
  79  * class path of URLs that are specified to the ClassLoader at construction
  80  * time. The class path may expand at runtime (the Class-Path attribute in JAR
  81  * files or via instrumentation agents). </p>
  82  *
  83  * <p> The delegation model used by this ClassLoader differs to the regular
  84  * delegation model. When requested to load a class then this ClassLoader first
  85  * maps the class name to its package name. If there is a module defined to a
  86  * BuiltinClassLoader containing this package then the class loader delegates
  87  * directly to that class loader. If there isn't a module containing the
  88  * package then it delegates the search to the parent class loader and if not
  89  * found in the parent then it searches the class path. The main difference
  90  * between this and the usual delegation model is that it allows the platform
  91  * class loader to delegate to the application class loader, important with
  92  * upgraded modules defined to the platform class loader.
  93  */
  94 
  95 public class BuiltinClassLoader
  96     extends SecureClassLoader
  97 {
  98     static {
  99         if (!ClassLoader.registerAsParallelCapable())
 100             throw new InternalError("Unable to register as parallel capable");
 101     }
 102 
 103     // parent ClassLoader
 104     private final BuiltinClassLoader parent;
 105 
 106     // the URL class path, or null if there is no class path
 107     private final URLClassPath ucp;
 108 
 109 
 110     /**
 111      * A module defined/loaded by a built-in class loader.
 112      *
 113      * A LoadedModule encapsulates a ModuleReference along with its CodeSource
 114      * URL to avoid needing to create this URL when defining classes.
 115      */
 116     private static class LoadedModule {
 117         private final BuiltinClassLoader loader;
 118         private final ModuleReference mref;
 119         private final URI uri;                      // may be null
 120         private @Stable URL codeSourceURL;          // may be null
 121 
 122         LoadedModule(BuiltinClassLoader loader, ModuleReference mref) {
 123             URL url = null;
 124             this.uri = mref.location().orElse(null);
 125 
 126             // for non-jrt schemes we need to resolve the codeSourceURL
 127             // eagerly during bootstrap since the handler might be
 128             // overridden
 129             if (uri != null && !"jrt".equals(uri.getScheme())) {
 130                 url = createURL(uri);
 131             }
 132             this.loader = loader;
 133             this.mref = mref;
 134             this.codeSourceURL = url;
 135         }
 136 
 137         BuiltinClassLoader loader() { return loader; }
 138         ModuleReference mref() { return mref; }
 139         String name() { return mref.descriptor().name(); }
 140 
 141         URL codeSourceURL() {
 142             URL url = codeSourceURL;
 143             if (url == null && uri != null) {
 144                 codeSourceURL = url = createURL(uri);
 145             }
 146             return url;
 147         }
 148 
 149         private URL createURL(URI uri) {
 150             URL url = null;
 151             try {
 152                 url = uri.toURL();
 153             } catch (MalformedURLException | IllegalArgumentException e) {
 154             }
 155             return url;
 156         }
 157     }
 158 
 159 
 160     // maps package name to loaded module for modules in the boot layer
 161     private static final Map<String, LoadedModule> packageToModule
 162         = new ConcurrentHashMap<>(1024);
 163 
 164     // maps a module name to a module reference
 165     private final Map<String, ModuleReference> nameToModule;
 166 
 167     // maps a module reference to a module reader
 168     private final Map<ModuleReference, ModuleReader> moduleToReader;
 169 
 170     // cache of resource name -> list of URLs.
 171     // used only for resources that are not in module packages
 172     private volatile SoftReference<Map<String, List<URL>>> resourceCache;
 173 
 174     /**
 175      * Create a new instance.
 176      */
 177     BuiltinClassLoader(String name, BuiltinClassLoader parent, URLClassPath ucp) {
 178         // ensure getParent() returns null when the parent is the boot loader
 179         super(name, parent == null || parent == ClassLoaders.bootLoader() ? null : parent);
 180 
 181         this.parent = parent;
 182         this.ucp = ucp;
 183 
 184         this.nameToModule = new ConcurrentHashMap<>(32);
 185         this.moduleToReader = new ConcurrentHashMap<>();
 186     }
 187 
 188     /**
 189      * Returns {@code true} if there is a class path associated with this
 190      * class loader.
 191      */
 192     boolean hasClassPath() {
 193         return ucp != null;
 194     }
 195 
 196     /**
 197      * Register a module this class loader. This has the effect of making the
 198      * types in the module visible.
 199      */
 200     public void loadModule(ModuleReference mref) {
 201         String mn = mref.descriptor().name();
 202         if (nameToModule.putIfAbsent(mn, mref) != null) {
 203             throw new InternalError(mn + " already defined to this loader");
 204         }
 205 
 206         LoadedModule loadedModule = new LoadedModule(this, mref);
 207         for (String pn : mref.descriptor().packages()) {
 208             LoadedModule other = packageToModule.putIfAbsent(pn, loadedModule);
 209             if (other != null) {
 210                 throw new InternalError(pn + " in modules " + mn + " and "
 211                                         + other.mref().descriptor().name());
 212             }
 213         }
 214 
 215         // clear resources cache if VM is already initialized
 216         if (VM.isModuleSystemInited() && resourceCache != null) {
 217             resourceCache = null;
 218         }
 219     }
 220 
 221     /**
 222      * Returns the {@code ModuleReference} for the named module defined to
 223      * this class loader; or {@code null} if not defined.
 224      *
 225      * @param name The name of the module to find
 226      */
 227     protected ModuleReference findModule(String name) {
 228         return nameToModule.get(name);
 229     }
 230 
 231 
 232     // -- finding resources
 233 
 234     /**
 235      * Returns a URL to a resource of the given name in a module defined to
 236      * this class loader.
 237      */
 238     @Override
 239     public URL findResource(String mn, String name) throws IOException {
 240         URL url = null;
 241 
 242         if (mn != null) {
 243             // find in module
 244             ModuleReference mref = nameToModule.get(mn);
 245             if (mref != null) {
 246                 url = findResource(mref, name);
 247             }
 248         } else {
 249             // find on class path
 250             url = findResourceOnClassPath(name);
 251         }
 252 
 253         return checkURL(url);  // check access before returning
 254     }
 255 
 256     /**
 257      * Returns an input stream to a resource of the given name in a module
 258      * defined to this class loader.
 259      */
 260     public InputStream findResourceAsStream(String mn, String name)
 261         throws IOException
 262     {
 263         // Need URL to resource when running with a security manager so that
 264         // the right permission check is done.
 265         if (System.getSecurityManager() != null || mn == null) {
 266             URL url = findResource(mn, name);
 267             return (url != null) ? url.openStream() : null;
 268         }
 269 
 270         // find in module defined to this loader, no security manager
 271         ModuleReference mref = nameToModule.get(mn);
 272         if (mref != null) {
 273             return moduleReaderFor(mref).open(name).orElse(null);
 274         } else {
 275             return null;
 276         }
 277     }
 278 
 279     /**
 280      * Finds a resource with the given name in the modules defined to this
 281      * class loader or its class path.
 282      */
 283     @Override
 284     public URL findResource(String name) {
 285         String pn = Resources.toPackageName(name);
 286         LoadedModule module = packageToModule.get(pn);
 287         if (module != null) {
 288 
 289             // resource is in a package of a module defined to this loader
 290             if (module.loader() == this) {
 291                 URL url;
 292                 try {
 293                     url = findResource(module.name(), name); // checks URL
 294                 } catch (IOException ioe) {
 295                     return null;
 296                 }
 297                 if (url != null
 298                     && (name.endsWith(".class")
 299                         || url.toString().endsWith("/")
 300                         || isOpen(module.mref(), pn))) {
 301                     return url;
 302                 }
 303             }
 304 
 305         } else {
 306 
 307             // not in a module package but may be in module defined to this loader
 308             try {
 309                 List<URL> urls = findMiscResource(name);
 310                 if (!urls.isEmpty()) {
 311                     URL url = urls.get(0);
 312                     if (url != null) {
 313                         return checkURL(url); // check access before returning
 314                     }
 315                 }
 316             } catch (IOException ioe) {
 317                 return null;
 318             }
 319 
 320         }
 321 
 322         // search class path
 323         URL url = findResourceOnClassPath(name);
 324         return checkURL(url);
 325     }
 326 
 327     /**
 328      * Returns an enumeration of URL objects to all the resources with the
 329      * given name in modules defined to this class loader or on the class
 330      * path of this loader.
 331      */
 332     @Override
 333     public Enumeration<URL> findResources(String name) throws IOException {
 334         List<URL> checked = new ArrayList<>();  // list of checked URLs
 335 
 336         String pn = Resources.toPackageName(name);
 337         LoadedModule module = packageToModule.get(pn);
 338         if (module != null) {
 339 
 340             // resource is in a package of a module defined to this loader
 341             if (module.loader() == this) {
 342                 URL url = findResource(module.name(), name); // checks URL
 343                 if (url != null
 344                     && (name.endsWith(".class")
 345                         || url.toString().endsWith("/")
 346                         || isOpen(module.mref(), pn))) {
 347                     checked.add(url);
 348                 }
 349             }
 350 
 351         } else {
 352             // not in a package of a module defined to this loader
 353             for (URL url : findMiscResource(name)) {
 354                 url = checkURL(url);
 355                 if (url != null) {
 356                     checked.add(url);
 357                 }
 358             }
 359         }
 360 
 361         // class path (not checked)
 362         Enumeration<URL> e = findResourcesOnClassPath(name);
 363 
 364         // concat the checked URLs and the (not checked) class path
 365         return new Enumeration<>() {
 366             final Iterator<URL> iterator = checked.iterator();
 367             URL next;
 368             private boolean hasNext() {
 369                 if (next != null) {
 370                     return true;
 371                 } else if (iterator.hasNext()) {
 372                     next = iterator.next();
 373                     return true;
 374                 } else {
 375                     // need to check each URL
 376                     while (e.hasMoreElements() && next == null) {
 377                         next = checkURL(e.nextElement());
 378                     }
 379                     return next != null;
 380                 }
 381             }
 382             @Override
 383             public boolean hasMoreElements() {
 384                 return hasNext();
 385             }
 386             @Override
 387             public URL nextElement() {
 388                 if (hasNext()) {
 389                     URL result = next;
 390                     next = null;
 391                     return result;
 392                 } else {
 393                     throw new NoSuchElementException();
 394                 }
 395             }
 396         };
 397 
 398     }
 399 
 400     /**
 401      * Returns the list of URLs to a "miscellaneous" resource in modules
 402      * defined to this loader. A miscellaneous resource is not in a module
 403      * package, e.g. META-INF/services/p.S.
 404      *
 405      * The cache used by this method avoids repeated searching of all modules.
 406      */
 407     private List<URL> findMiscResource(String name) throws IOException {
 408         SoftReference<Map<String, List<URL>>> ref = this.resourceCache;
 409         Map<String, List<URL>> map = (ref != null) ? ref.get() : null;
 410         if (map == null) {
 411             map = new ConcurrentHashMap<>();
 412             this.resourceCache = new SoftReference<>(map);
 413         } else {
 414             List<URL> urls = map.get(name);
 415             if (urls != null)
 416                 return urls;
 417         }
 418 
 419         // search all modules for the resource
 420         List<URL> urls;
 421         try {
 422             urls = AccessController.doPrivileged(
 423                 new PrivilegedExceptionAction<>() {
 424                     @Override
 425                     public List<URL> run() throws IOException {
 426                         List<URL> result = null;
 427                         for (ModuleReference mref : nameToModule.values()) {
 428                             URI u = moduleReaderFor(mref).find(name).orElse(null);
 429                             if (u != null) {
 430                                 try {
 431                                     if (result == null)
 432                                         result = new ArrayList<>();
 433                                     result.add(u.toURL());
 434                                 } catch (MalformedURLException |
 435                                          IllegalArgumentException e) {
 436                                 }
 437                             }
 438                         }
 439                         return (result != null) ? result : Collections.emptyList();
 440                     }
 441                 });
 442         } catch (PrivilegedActionException pae) {
 443             throw (IOException) pae.getCause();
 444         }
 445 
 446         // only cache resources after VM is fully initialized
 447         if (VM.isModuleSystemInited()) {
 448             map.putIfAbsent(name, urls);
 449         }
 450 
 451         return urls;
 452     }
 453 
 454     /**
 455      * Returns the URL to a resource in a module or {@code null} if not found.
 456      */
 457     private URL findResource(ModuleReference mref, String name) throws IOException {
 458         URI u;
 459         if (System.getSecurityManager() == null) {
 460             u = moduleReaderFor(mref).find(name).orElse(null);
 461         } else {
 462             try {
 463                 u = AccessController.doPrivileged(new PrivilegedExceptionAction<> () {
 464                     @Override
 465                     public URI run() throws IOException {
 466                         return moduleReaderFor(mref).find(name).orElse(null);
 467                     }
 468                 });
 469             } catch (PrivilegedActionException pae) {
 470                 throw (IOException) pae.getCause();
 471             }
 472         }
 473         if (u != null) {
 474             try {
 475                 return u.toURL();
 476             } catch (MalformedURLException | IllegalArgumentException e) { }
 477         }
 478         return null;
 479     }
 480 
 481     /**
 482      * Returns the URL to a resource in a module. Returns {@code null} if not found
 483      * or an I/O error occurs.
 484      */
 485     private URL findResourceOrNull(ModuleReference mref, String name) {
 486         try {
 487             return findResource(mref, name);
 488         } catch (IOException ignore) {
 489             return null;
 490         }
 491     }
 492 
 493     /**
 494      * Returns a URL to a resource on the class path.
 495      */
 496     private URL findResourceOnClassPath(String name) {
 497         if (hasClassPath()) {
 498             if (System.getSecurityManager() == null) {
 499                 return ucp.findResource(name, false);
 500             } else {
 501                 PrivilegedAction<URL> pa = () -> ucp.findResource(name, false);
 502                 return AccessController.doPrivileged(pa);
 503             }
 504         } else {
 505             // no class path
 506             return null;
 507         }
 508     }
 509 
 510     /**
 511      * Returns the URLs of all resources of the given name on the class path.
 512      */
 513     private Enumeration<URL> findResourcesOnClassPath(String name) {
 514         if (hasClassPath()) {
 515             if (System.getSecurityManager() == null) {
 516                 return ucp.findResources(name, false);
 517             } else {
 518                 PrivilegedAction<Enumeration<URL>> pa;
 519                 pa = () -> ucp.findResources(name, false);
 520                 return AccessController.doPrivileged(pa);
 521             }
 522         } else {
 523             // no class path
 524             return Collections.emptyEnumeration();
 525         }
 526     }
 527 
 528     // -- finding/loading classes
 529 
 530     /**
 531      * Finds the class with the specified binary name.
 532      */
 533     @Override
 534     protected Class<?> findClass(String cn) throws ClassNotFoundException {
 535         // no class loading until VM is fully initialized
 536         if (!VM.isModuleSystemInited())
 537             throw new ClassNotFoundException(cn);
 538 
 539         // find the candidate module for this class
 540         LoadedModule loadedModule = findLoadedModule(cn);
 541 
 542         Class<?> c = null;
 543         if (loadedModule != null) {
 544 
 545             // attempt to load class in module defined to this loader
 546             if (loadedModule.loader() == this) {
 547                 c = findClassInModuleOrNull(loadedModule, cn);
 548             }
 549 
 550         } else {
 551 
 552             // search class path
 553             if (hasClassPath()) {
 554                 c = findClassOnClassPathOrNull(cn);
 555             }
 556 
 557         }
 558 
 559         // not found
 560         if (c == null)
 561             throw new ClassNotFoundException(cn);
 562 
 563         return c;
 564     }
 565 
 566     /**
 567      * Finds the class with the specified binary name in a module.
 568      * This method returns {@code null} if the class cannot be found
 569      * or not defined in the specified module.
 570      */
 571     @Override
 572     protected Class<?> findClass(String mn, String cn) {
 573         if (mn != null) {
 574             // find the candidate module for this class
 575             LoadedModule loadedModule = findLoadedModule(mn, cn);
 576             if (loadedModule == null) {
 577                 return null;
 578             }
 579 
 580             // attempt to load class in module defined to this loader
 581             assert loadedModule.loader() == this;
 582             return findClassInModuleOrNull(loadedModule, cn);
 583         }
 584 
 585         // search class path
 586         if (hasClassPath()) {
 587             return findClassOnClassPathOrNull(cn);
 588         }
 589 
 590         return null;
 591     }
 592 
 593     /**
 594      * Loads the class with the specified binary name.
 595      */
 596     @Override
 597     protected Class<?> loadClass(String cn, boolean resolve)
 598         throws ClassNotFoundException
 599     {
 600         Class<?> c = loadClassOrNull(cn, resolve);
 601         if (c == null)
 602             throw new ClassNotFoundException(cn);
 603         return c;
 604     }
 605 
 606     /**
 607      * A variation of {@code loadClass} to load a class with the specified
 608      * binary name. This method returns {@code null} when the class is not
 609      * found.
 610      */
 611     protected Class<?> loadClassOrNull(String cn, boolean resolve) {
 612         synchronized (getClassLoadingLock(cn)) {
 613             // check if already loaded
 614             Class<?> c = findLoadedClass(cn);
 615 
 616             if (c == null) {
 617 
 618                 // find the candidate module for this class
 619                 LoadedModule loadedModule = findLoadedModule(cn);
 620                 if (loadedModule != null) {
 621 
 622                     // package is in a module
 623                     BuiltinClassLoader loader = loadedModule.loader();
 624                     if (loader == this) {
 625                         if (VM.isModuleSystemInited()) {
 626                             c = findClassInModuleOrNull(loadedModule, cn);
 627                         }
 628                     } else {
 629                         // delegate to the other loader
 630                         c = loader.loadClassOrNull(cn);
 631                     }
 632 
 633                 } else {
 634 
 635                     // check parent
 636                     if (parent != null) {
 637                         c = parent.loadClassOrNull(cn);
 638                     }
 639 
 640                     // check class path
 641                     if (c == null && hasClassPath() && VM.isModuleSystemInited()) {
 642                         c = findClassOnClassPathOrNull(cn);
 643                     }
 644                 }
 645 
 646             }
 647 
 648             if (resolve && c != null)
 649                 resolveClass(c);
 650 
 651             return c;
 652         }
 653     }
 654 
 655     /**
 656      * A variation of {@code loadClass} to load a class with the specified
 657      * binary name. This method returns {@code null} when the class is not
 658      * found.
 659      */
 660     protected final Class<?> loadClassOrNull(String cn) {
 661         return loadClassOrNull(cn, false);
 662     }
 663 
 664     /**
 665      * Finds the candidate loaded module for the given class name.
 666      * Returns {@code null} if none of the modules defined to this
 667      * class loader contain the API package for the class.
 668      */
 669     private LoadedModule findLoadedModule(String cn) {
 670         int pos = cn.lastIndexOf('.');
 671         if (pos < 0)
 672             return null; // unnamed package
 673 
 674         String pn = cn.substring(0, pos);
 675         return packageToModule.get(pn);
 676     }
 677 
 678     /**
 679      * Finds the candidate loaded module for the given class name
 680      * in the named module.  Returns {@code null} if the named module
 681      * is not defined to this class loader or does not contain
 682      * the API package for the class.
 683      */
 684     private LoadedModule findLoadedModule(String mn, String cn) {
 685         LoadedModule loadedModule = findLoadedModule(cn);
 686         if (loadedModule != null && mn.equals(loadedModule.name())) {
 687             return loadedModule;
 688         } else {
 689             return null;
 690         }
 691     }
 692 
 693     /**
 694      * Finds the class with the specified binary name if in a module
 695      * defined to this ClassLoader.
 696      *
 697      * @return the resulting Class or {@code null} if not found
 698      */
 699     private Class<?> findClassInModuleOrNull(LoadedModule loadedModule, String cn) {
 700         if (System.getSecurityManager() == null) {
 701             return defineClass(cn, loadedModule);
 702         } else {
 703             PrivilegedAction<Class<?>> pa = () -> defineClass(cn, loadedModule);
 704             return AccessController.doPrivileged(pa);
 705         }
 706     }
 707 
 708     /**
 709      * Finds the class with the specified binary name on the class path.
 710      *
 711      * @return the resulting Class or {@code null} if not found
 712      */
 713     private Class<?> findClassOnClassPathOrNull(String cn) {
 714         String path = cn.replace('.', '/').concat(".class");
 715         if (System.getSecurityManager() == null) {
 716             Resource res = ucp.getResource(path, false);
 717             if (res != null) {
 718                 try {
 719                     return defineClass(cn, res);
 720                 } catch (IOException ioe) {
 721                     // TBD on how I/O errors should be propagated
 722                 }
 723             }
 724             return null;
 725         } else {
 726             // avoid use of lambda here
 727             PrivilegedAction<Class<?>> pa = new PrivilegedAction<>() {
 728                 public Class<?> run() {
 729                     Resource res = ucp.getResource(path, false);
 730                     if (res != null) {
 731                         try {
 732                             return defineClass(cn, res);
 733                         } catch (IOException ioe) {
 734                             // TBD on how I/O errors should be propagated
 735                         }
 736                     }
 737                     return null;
 738                 }
 739             };
 740             return AccessController.doPrivileged(pa);
 741         }
 742     }
 743 
 744     /**
 745      * Defines the given binary class name to the VM, loading the class
 746      * bytes from the given module.
 747      *
 748      * @return the resulting Class or {@code null} if an I/O error occurs
 749      */
 750     private Class<?> defineClass(String cn, LoadedModule loadedModule) {
 751         ModuleReference mref = loadedModule.mref();
 752         ModuleReader reader = moduleReaderFor(mref);
 753 
 754         try {
 755             ByteBuffer bb = null;
 756             URL csURL = null;
 757 
 758             // locate class file, special handling for patched modules to
 759             // avoid locating the resource twice
 760             String rn = cn.replace('.', '/').concat(".class");
 761             if (reader instanceof PatchedModuleReader) {
 762                 Resource r = ((PatchedModuleReader)reader).findResource(rn);
 763                 if (r != null) {
 764                     bb = r.getByteBuffer();
 765                     csURL = r.getCodeSourceURL();
 766                 }
 767             } else {
 768                 bb = reader.read(rn).orElse(null);
 769                 csURL = loadedModule.codeSourceURL();
 770             }
 771 
 772             if (bb == null) {
 773                 // class not found
 774                 return null;
 775             }
 776 
 777             CodeSource cs = new CodeSource(csURL, (CodeSigner[]) null);
 778             try {
 779                 // define class to VM
 780                 return defineClass(cn, bb, cs);
 781 
 782             } finally {
 783                 reader.release(bb);
 784             }
 785 
 786         } catch (IOException ioe) {
 787             // TBD on how I/O errors should be propagated
 788             return null;
 789         }
 790     }
 791 
 792     /**
 793      * Defines the given binary class name to the VM, loading the class
 794      * bytes via the given Resource object.
 795      *
 796      * @return the resulting Class
 797      * @throws IOException if reading the resource fails
 798      * @throws SecurityException if there is a sealing violation (JAR spec)
 799      */
 800     private Class<?> defineClass(String cn, Resource res) throws IOException {
 801         URL url = res.getCodeSourceURL();
 802 
 803         // if class is in a named package then ensure that the package is defined
 804         int pos = cn.lastIndexOf('.');
 805         if (pos != -1) {
 806             String pn = cn.substring(0, pos);
 807             Manifest man = res.getManifest();
 808             defineOrCheckPackage(pn, man, url);
 809         }
 810 
 811         // defines the class to the runtime
 812         ByteBuffer bb = res.getByteBuffer();
 813         if (bb != null) {
 814             CodeSigner[] signers = res.getCodeSigners();
 815             CodeSource cs = new CodeSource(url, signers);
 816             return defineClass(cn, bb, cs);
 817         } else {
 818             byte[] b = res.getBytes();
 819             CodeSigner[] signers = res.getCodeSigners();
 820             CodeSource cs = new CodeSource(url, signers);
 821             return defineClass(cn, b, 0, b.length, cs);
 822         }
 823     }
 824 
 825 
 826     // -- packages
 827 
 828     /**
 829      * Defines a package in this ClassLoader. If the package is already defined
 830      * then its sealing needs to be checked if sealed by the legacy sealing
 831      * mechanism.
 832      *
 833      * @throws SecurityException if there is a sealing violation (JAR spec)
 834      */
 835     protected Package defineOrCheckPackage(String pn, Manifest man, URL url) {
 836         Package pkg = getAndVerifyPackage(pn, man, url);
 837         if (pkg == null) {
 838             try {
 839                 if (man != null) {
 840                     pkg = definePackage(pn, man, url);
 841                 } else {
 842                     pkg = definePackage(pn, null, null, null, null, null, null, null);
 843                 }
 844             } catch (IllegalArgumentException iae) {
 845                 // defined by another thread so need to re-verify
 846                 pkg = getAndVerifyPackage(pn, man, url);
 847                 if (pkg == null)
 848                     throw new InternalError("Cannot find package: " + pn);
 849             }
 850         }
 851         return pkg;
 852     }
 853 
 854     /**
 855      * Gets the Package with the specified package name. If defined
 856      * then verifies it against the manifest and code source.
 857      *
 858      * @throws SecurityException if there is a sealing violation (JAR spec)
 859      */
 860     private Package getAndVerifyPackage(String pn, Manifest man, URL url) {
 861         Package pkg = getDefinedPackage(pn);
 862         if (pkg != null) {
 863             if (pkg.isSealed()) {
 864                 if (!pkg.isSealed(url)) {
 865                     throw new SecurityException(
 866                         "sealing violation: package " + pn + " is sealed");
 867                 }
 868             } else {
 869                 // can't seal package if already defined without sealing
 870                 if ((man != null) && isSealed(pn, man)) {
 871                     throw new SecurityException(
 872                         "sealing violation: can't seal package " + pn +
 873                         ": already defined");
 874                 }
 875             }
 876         }
 877         return pkg;
 878     }
 879 
 880     /**
 881      * Defines a new package in this ClassLoader. The attributes in the specified
 882      * Manifest are used to get the package version and sealing information.
 883      *
 884      * @throws IllegalArgumentException if the package name duplicates an
 885      *      existing package either in this class loader or one of its ancestors
 886      * @throws SecurityException if the package name is untrusted in the manifest
 887      */
 888     private Package definePackage(String pn, Manifest man, URL url) {
 889         String specTitle = null;
 890         String specVersion = null;
 891         String specVendor = null;
 892         String implTitle = null;
 893         String implVersion = null;
 894         String implVendor = null;
 895         String sealed = null;
 896         URL sealBase = null;
 897 
 898         if (man != null) {
 899             Attributes attr = SharedSecrets.javaUtilJarAccess()
 900                     .getTrustedAttributes(man, pn.replace('.', '/').concat("/"));
 901             if (attr != null) {
 902                 specTitle = attr.getValue(Attributes.Name.SPECIFICATION_TITLE);
 903                 specVersion = attr.getValue(Attributes.Name.SPECIFICATION_VERSION);
 904                 specVendor = attr.getValue(Attributes.Name.SPECIFICATION_VENDOR);
 905                 implTitle = attr.getValue(Attributes.Name.IMPLEMENTATION_TITLE);
 906                 implVersion = attr.getValue(Attributes.Name.IMPLEMENTATION_VERSION);
 907                 implVendor = attr.getValue(Attributes.Name.IMPLEMENTATION_VENDOR);
 908                 sealed = attr.getValue(Attributes.Name.SEALED);
 909             }
 910 
 911             attr = man.getMainAttributes();
 912             if (attr != null) {
 913                 if (specTitle == null)
 914                     specTitle = attr.getValue(Attributes.Name.SPECIFICATION_TITLE);
 915                 if (specVersion == null)
 916                     specVersion = attr.getValue(Attributes.Name.SPECIFICATION_VERSION);
 917                 if (specVendor == null)
 918                     specVendor = attr.getValue(Attributes.Name.SPECIFICATION_VENDOR);
 919                 if (implTitle == null)
 920                     implTitle = attr.getValue(Attributes.Name.IMPLEMENTATION_TITLE);
 921                 if (implVersion == null)
 922                     implVersion = attr.getValue(Attributes.Name.IMPLEMENTATION_VERSION);
 923                 if (implVendor == null)
 924                     implVendor = attr.getValue(Attributes.Name.IMPLEMENTATION_VENDOR);
 925                 if (sealed == null)
 926                     sealed = attr.getValue(Attributes.Name.SEALED);
 927             }
 928 
 929             // package is sealed
 930             if ("true".equalsIgnoreCase(sealed))
 931                 sealBase = url;
 932         }
 933         return definePackage(pn,
 934                 specTitle,
 935                 specVersion,
 936                 specVendor,
 937                 implTitle,
 938                 implVersion,
 939                 implVendor,
 940                 sealBase);
 941     }
 942 
 943     /**
 944      * Returns {@code true} if the specified package name is sealed according to
 945      * the given manifest.
 946      *
 947      * @throws SecurityException if the package name is untrusted in the manifest
 948      */
 949     private boolean isSealed(String pn, Manifest man) {
 950         Attributes attr = SharedSecrets.javaUtilJarAccess()
 951                 .getTrustedAttributes(man, pn.replace('.', '/').concat("/"));
 952         String sealed = null;
 953         if (attr != null)
 954             sealed = attr.getValue(Attributes.Name.SEALED);
 955         if (sealed == null && (attr = man.getMainAttributes()) != null)
 956             sealed = attr.getValue(Attributes.Name.SEALED);
 957         return "true".equalsIgnoreCase(sealed);
 958     }
 959 
 960     // -- permissions
 961 
 962     /**
 963      * Returns the permissions for the given CodeSource.
 964      */
 965     @Override
 966     protected PermissionCollection getPermissions(CodeSource cs) {
 967         PermissionCollection perms = super.getPermissions(cs);
 968 
 969         // add the permission to access the resource
 970         URL url = cs.getLocation();
 971         if (url == null)
 972             return perms;
 973 
 974         // avoid opening connection when URL is to resource in run-time image
 975         if (url.getProtocol().equals("jrt")) {
 976             perms.add(new RuntimePermission("accessSystemModules"));
 977             return perms;
 978         }
 979 
 980         return new LazyCodeSourcePermissionCollection(perms, cs);
 981     }
 982 
 983     // -- miscellaneous supporting methods
 984 
 985     /**
 986      * Returns the ModuleReader for the given module, creating it if needed.
 987      */
 988     private ModuleReader moduleReaderFor(ModuleReference mref) {
 989         ModuleReader reader = moduleToReader.get(mref);
 990         if (reader == null) {
 991             // avoid method reference during startup
 992             Function<ModuleReference, ModuleReader> create = new Function<>() {
 993                 public ModuleReader apply(ModuleReference moduleReference) {
 994                     try {
 995                         return mref.open();
 996                     } catch (IOException e) {
 997                         // Return a null module reader to avoid a future class
 998                         // load attempting to open the module again.
 999                         return new NullModuleReader();
1000                     }
1001                 }
1002             };
1003             reader = moduleToReader.computeIfAbsent(mref, create);
1004         }
1005         return reader;
1006     }
1007 
1008     /**
1009      * A ModuleReader that doesn't read any resources.
1010      */
1011     private static class NullModuleReader implements ModuleReader {
1012         @Override
1013         public Optional<URI> find(String name) {
1014             return Optional.empty();
1015         }
1016         @Override
1017         public Stream<String> list() {
1018             return Stream.empty();
1019         }
1020         @Override
1021         public void close() {
1022             throw new InternalError("Should not get here");
1023         }
1024     };
1025 
1026     /**
1027      * Returns true if the given module opens the given package
1028      * unconditionally.
1029      *
1030      * @implNote This method currently iterates over each of the open
1031      * packages. This will be replaced once the ModuleDescriptor.Opens
1032      * API is updated.
1033      */
1034     private boolean isOpen(ModuleReference mref, String pn) {
1035         ModuleDescriptor descriptor = mref.descriptor();
1036         if (descriptor.isOpen() || descriptor.isAutomatic())
1037             return true;
1038         for (ModuleDescriptor.Opens opens : descriptor.opens()) {
1039             String source = opens.source();
1040             if (!opens.isQualified() && source.equals(pn)) {
1041                 return true;
1042             }
1043         }
1044         return false;
1045     }
1046 
1047     /**
1048      * Checks access to the given URL. We use URLClassPath for consistent
1049      * checking with java.net.URLClassLoader.
1050      */
1051     private static URL checkURL(URL url) {
1052         return URLClassPath.checkURL(url);
1053     }
1054 }