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