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