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