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