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