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