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