Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/java.base/share/classes/jdk/internal/loader/BuiltinClassLoader.java
41159 views
1
/*
2
* Copyright (c) 2015, 2021, 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
}
1087
}
1088
1089