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