Merge
This commit is contained in:
commit
1b7c55e27b
@ -440,3 +440,4 @@ a6c830ee8a6798b186730475e700027cdf4598aa jdk-10+15
|
||||
ec4159ebe7050fcc5dcee8a2d150cf948ecc97db jdk-9+178
|
||||
252475ccfd84cc249f8d6faf4b7806b5e2c384ce jdk-9+179
|
||||
a133a7d1007b1456bc62824382fd8ac93b45d329 jdk-10+17
|
||||
536b81db8075486ca0fe3225d8e59313df5b936c jdk-10+18
|
||||
|
@ -440,3 +440,4 @@ b82b62ed5debda2d98dda597506ef29cf947fbae jdk-10+16
|
||||
9c1e9712648921ae389d623042d22561fad82d75 jdk-9+178
|
||||
24390da83c5ee9e23ceafbcaff4460a01e37bb3a jdk-9+179
|
||||
50ff1fd66362f212a8db6de76089d9d0ffa4df0f jdk-10+17
|
||||
a923b3f30e7bddb4f960059ddfc7978fc63e2e6e jdk-10+18
|
||||
|
@ -600,3 +600,4 @@ c1f3649a3a42f124b418a5a916dbad13d059b757 jdk-10+15
|
||||
9d032191f82fca5ba0aac98682f69c4ff0f1283d jdk-9+178
|
||||
d2661aa42bff322badbe6c1337fc638d2e0f5730 jdk-9+179
|
||||
73e2cb8700bfa51304bd4b02f224620859a3f600 jdk-10+17
|
||||
c9d3317623d48da3327232c81e3f8cfc0d29d888 jdk-10+18
|
||||
|
@ -440,3 +440,4 @@ e069834e2c518a7bc2ffadc8c7e3cd7ec69fa8a0 jdk-10+15
|
||||
443025bee731eb2225371b92c1c74b519b7baf33 jdk-9+178
|
||||
06df1ce4b9b887d05ce6a13f4def3547e434dd1a jdk-9+179
|
||||
d93f2fd542b7d7855c2cd49ae15ebcc3d441a83b jdk-10+17
|
||||
c4b709bad6c5d29294124de5e74e1e2ac84fcf1f jdk-10+18
|
||||
|
@ -31,6 +31,8 @@ import java.security.InvalidKeyException;
|
||||
import javax.crypto.SecretKey;
|
||||
import javax.crypto.spec.DESKeySpec;
|
||||
|
||||
import jdk.internal.ref.CleanerFactory;
|
||||
|
||||
/**
|
||||
* This class represents a DES key.
|
||||
*
|
||||
@ -74,6 +76,11 @@ final class DESKey implements SecretKey {
|
||||
this.key = new byte[DESKeySpec.DES_KEY_LEN];
|
||||
System.arraycopy(key, offset, this.key, 0, DESKeySpec.DES_KEY_LEN);
|
||||
DESKeyGenerator.setParityBit(this.key, 0);
|
||||
|
||||
// Use the cleaner to zero the key when no longer referenced
|
||||
final byte[] k = this.key;
|
||||
CleanerFactory.cleaner().register(this,
|
||||
() -> java.util.Arrays.fill(k, (byte)0x00));
|
||||
}
|
||||
|
||||
public byte[] getEncoded() {
|
||||
@ -144,20 +151,4 @@ final class DESKey implements SecretKey {
|
||||
getFormat(),
|
||||
getEncoded());
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures that the bytes of this key are
|
||||
* set to zero when there are no more references to it.
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
protected void finalize() throws Throwable {
|
||||
try {
|
||||
if (this.key != null) {
|
||||
java.util.Arrays.fill(this.key, (byte)0x00);
|
||||
this.key = null;
|
||||
}
|
||||
} finally {
|
||||
super.finalize();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -31,6 +31,8 @@ import java.security.InvalidKeyException;
|
||||
import javax.crypto.SecretKey;
|
||||
import javax.crypto.spec.DESedeKeySpec;
|
||||
|
||||
import jdk.internal.ref.CleanerFactory;
|
||||
|
||||
/**
|
||||
* This class represents a DES-EDE key.
|
||||
*
|
||||
@ -76,6 +78,11 @@ final class DESedeKey implements SecretKey {
|
||||
DESKeyGenerator.setParityBit(this.key, 0);
|
||||
DESKeyGenerator.setParityBit(this.key, 8);
|
||||
DESKeyGenerator.setParityBit(this.key, 16);
|
||||
|
||||
// Use the cleaner to zero the key when no longer referenced
|
||||
final byte[] k = this.key;
|
||||
CleanerFactory.cleaner().register(this,
|
||||
() -> java.util.Arrays.fill(k, (byte)0x00));
|
||||
}
|
||||
|
||||
public byte[] getEncoded() {
|
||||
@ -145,20 +152,4 @@ final class DESedeKey implements SecretKey {
|
||||
getFormat(),
|
||||
getEncoded());
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures that the bytes of this key are
|
||||
* set to zero when there are no more references to it.
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
protected void finalize() throws Throwable {
|
||||
try {
|
||||
if (this.key != null) {
|
||||
java.util.Arrays.fill(this.key, (byte)0x00);
|
||||
this.key = null;
|
||||
}
|
||||
} finally {
|
||||
super.finalize();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -32,6 +32,8 @@ import java.util.Locale;
|
||||
import javax.crypto.SecretKey;
|
||||
import javax.crypto.spec.PBEKeySpec;
|
||||
|
||||
import jdk.internal.ref.CleanerFactory;
|
||||
|
||||
/**
|
||||
* This class represents a PBE key.
|
||||
*
|
||||
@ -49,7 +51,7 @@ final class PBEKey implements SecretKey {
|
||||
/**
|
||||
* Creates a PBE key from a given PBE key specification.
|
||||
*
|
||||
* @param key the given PBE key specification
|
||||
* @param keytype the given PBE key specification
|
||||
*/
|
||||
PBEKey(PBEKeySpec keySpec, String keytype) throws InvalidKeySpecException {
|
||||
char[] passwd = keySpec.getPassword();
|
||||
@ -70,6 +72,11 @@ final class PBEKey implements SecretKey {
|
||||
this.key[i] = (byte) (passwd[i] & 0x7f);
|
||||
java.util.Arrays.fill(passwd, ' ');
|
||||
type = keytype;
|
||||
|
||||
// Use the cleaner to zero the key when no longer referenced
|
||||
final byte[] k = this.key;
|
||||
CleanerFactory.cleaner().register(this,
|
||||
() -> java.util.Arrays.fill(k, (byte)0x00));
|
||||
}
|
||||
|
||||
public byte[] getEncoded() {
|
||||
@ -140,20 +147,4 @@ final class PBEKey implements SecretKey {
|
||||
getFormat(),
|
||||
getEncoded());
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures that the password bytes of this key are
|
||||
* set to zero when there are no more references to it.
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
protected void finalize() throws Throwable {
|
||||
try {
|
||||
if (this.key != null) {
|
||||
java.util.Arrays.fill(this.key, (byte)0x00);
|
||||
this.key = null;
|
||||
}
|
||||
} finally {
|
||||
super.finalize();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -40,6 +40,8 @@ import javax.crypto.Mac;
|
||||
import javax.crypto.SecretKey;
|
||||
import javax.crypto.spec.PBEKeySpec;
|
||||
|
||||
import jdk.internal.ref.CleanerFactory;
|
||||
|
||||
/**
|
||||
* This class represents a PBE key derived using PBKDF2 defined
|
||||
* in PKCS#5 v2.0. meaning that
|
||||
@ -76,7 +78,8 @@ final class PBKDF2KeyImpl implements javax.crypto.interfaces.PBEKey {
|
||||
/**
|
||||
* Creates a PBE key from a given PBE key specification.
|
||||
*
|
||||
* @param key the given PBE key specification
|
||||
* @param keySpec the given PBE key specification
|
||||
* @param prfAlgo the given PBE key algorithm
|
||||
*/
|
||||
PBKDF2KeyImpl(PBEKeySpec keySpec, String prfAlgo)
|
||||
throws InvalidKeySpecException {
|
||||
@ -120,6 +123,15 @@ final class PBKDF2KeyImpl implements javax.crypto.interfaces.PBEKey {
|
||||
throw ike;
|
||||
}
|
||||
this.key = deriveKey(prf, passwdBytes, salt, iterCount, keyLength);
|
||||
|
||||
// Use the cleaner to zero the key when no longer referenced
|
||||
final byte[] k = this.key;
|
||||
final char[] p = this.passwd;
|
||||
CleanerFactory.cleaner().register(this,
|
||||
() -> {
|
||||
java.util.Arrays.fill(k, (byte)0x00);
|
||||
java.util.Arrays.fill(p, '0');
|
||||
});
|
||||
}
|
||||
|
||||
private static byte[] deriveKey(final Mac prf, final byte[] password,
|
||||
@ -262,24 +274,4 @@ final class PBKDF2KeyImpl implements javax.crypto.interfaces.PBEKey {
|
||||
return new KeyRep(KeyRep.Type.SECRET, getAlgorithm(),
|
||||
getFormat(), getEncoded());
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures that the password bytes of this key are
|
||||
* erased when there are no more references to it.
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
protected void finalize() throws Throwable {
|
||||
try {
|
||||
if (this.passwd != null) {
|
||||
java.util.Arrays.fill(this.passwd, '0');
|
||||
this.passwd = null;
|
||||
}
|
||||
if (this.key != null) {
|
||||
java.util.Arrays.fill(this.key, (byte)0x00);
|
||||
this.key = null;
|
||||
}
|
||||
} finally {
|
||||
super.finalize();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -432,18 +432,21 @@ public final class Class<T> implements java.io.Serializable,
|
||||
Objects.requireNonNull(module);
|
||||
Objects.requireNonNull(name);
|
||||
|
||||
Class<?> caller = Reflection.getCallerClass();
|
||||
if (caller != null && caller.getModule() != module) {
|
||||
// if caller is null, Class.forName is the last java frame on the stack.
|
||||
// java.base has all permissions
|
||||
SecurityManager sm = System.getSecurityManager();
|
||||
if (sm != null) {
|
||||
ClassLoader cl;
|
||||
SecurityManager sm = System.getSecurityManager();
|
||||
if (sm != null) {
|
||||
Class<?> caller = Reflection.getCallerClass();
|
||||
if (caller != null && caller.getModule() != module) {
|
||||
// if caller is null, Class.forName is the last java frame on the stack.
|
||||
// java.base has all permissions
|
||||
sm.checkPermission(SecurityConstants.GET_CLASSLOADER_PERMISSION);
|
||||
}
|
||||
PrivilegedAction<ClassLoader> pa = module::getClassLoader;
|
||||
cl = AccessController.doPrivileged(pa);
|
||||
} else {
|
||||
cl = module.getClassLoader();
|
||||
}
|
||||
|
||||
PrivilegedAction<ClassLoader> pa = module::getClassLoader;
|
||||
ClassLoader cl = AccessController.doPrivileged(pa);
|
||||
if (cl != null) {
|
||||
return cl.loadClass(module, name);
|
||||
} else {
|
||||
|
@ -246,7 +246,6 @@ public final class Module implements AnnotatedElement {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
// --
|
||||
|
||||
// special Module to mean "all unnamed modules"
|
||||
@ -257,17 +256,38 @@ public final class Module implements AnnotatedElement {
|
||||
private static final Module EVERYONE_MODULE = new Module(null);
|
||||
private static final Set<Module> EVERYONE_SET = Set.of(EVERYONE_MODULE);
|
||||
|
||||
/**
|
||||
* The holder of data structures to support readability, exports, and
|
||||
* service use added at runtime with the reflective APIs.
|
||||
*/
|
||||
private static class ReflectionData {
|
||||
/**
|
||||
* A module (1st key) reads another module (2nd key)
|
||||
*/
|
||||
static final WeakPairMap<Module, Module, Boolean> reads =
|
||||
new WeakPairMap<>();
|
||||
|
||||
/**
|
||||
* A module (1st key) exports or opens a package to another module
|
||||
* (2nd key). The map value is a map of package name to a boolean
|
||||
* that indicates if the package is opened.
|
||||
*/
|
||||
static final WeakPairMap<Module, Module, Map<String, Boolean>> exports =
|
||||
new WeakPairMap<>();
|
||||
|
||||
/**
|
||||
* A module (1st key) uses a service (2nd key)
|
||||
*/
|
||||
static final WeakPairMap<Module, Class<?>, Boolean> uses =
|
||||
new WeakPairMap<>();
|
||||
}
|
||||
|
||||
|
||||
// -- readability --
|
||||
|
||||
// the modules that this module reads
|
||||
private volatile Set<Module> reads;
|
||||
|
||||
// additional module (2nd key) that some module (1st key) reflectively reads
|
||||
private static final WeakPairMap<Module, Module, Boolean> reflectivelyReads
|
||||
= new WeakPairMap<>();
|
||||
|
||||
|
||||
/**
|
||||
* Indicates if this module reads the given module. This method returns
|
||||
* {@code true} if invoked to test if this module reads itself. It also
|
||||
@ -300,13 +320,13 @@ public final class Module implements AnnotatedElement {
|
||||
}
|
||||
|
||||
// check if this module reads the other module reflectively
|
||||
if (reflectivelyReads.containsKeyPair(this, other))
|
||||
if (ReflectionData.reads.containsKeyPair(this, other))
|
||||
return true;
|
||||
|
||||
// if other is an unnamed module then check if this module reads
|
||||
// all unnamed modules
|
||||
if (!other.isNamed()
|
||||
&& reflectivelyReads.containsKeyPair(this, ALL_UNNAMED_MODULE))
|
||||
&& ReflectionData.reads.containsKeyPair(this, ALL_UNNAMED_MODULE))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
@ -393,7 +413,7 @@ public final class Module implements AnnotatedElement {
|
||||
}
|
||||
|
||||
// add reflective read
|
||||
reflectivelyReads.putIfAbsent(this, other, Boolean.TRUE);
|
||||
ReflectionData.reads.putIfAbsent(this, other, Boolean.TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
@ -408,13 +428,6 @@ public final class Module implements AnnotatedElement {
|
||||
// if the value contains EVERYONE_MODULE then the package is exported to all
|
||||
private volatile Map<String, Set<Module>> exportedPackages;
|
||||
|
||||
// additional exports or opens added at run-time
|
||||
// this module (1st key), other module (2nd key)
|
||||
// (package name, open?) (value)
|
||||
private static final WeakPairMap<Module, Module, Map<String, Boolean>>
|
||||
reflectivelyExports = new WeakPairMap<>();
|
||||
|
||||
|
||||
/**
|
||||
* Returns {@code true} if this module exports the given package to at
|
||||
* least the given module.
|
||||
@ -600,7 +613,7 @@ public final class Module implements AnnotatedElement {
|
||||
*/
|
||||
private boolean isReflectivelyExportedOrOpen(String pn, Module other, boolean open) {
|
||||
// exported or open to all modules
|
||||
Map<String, Boolean> exports = reflectivelyExports.get(this, EVERYONE_MODULE);
|
||||
Map<String, Boolean> exports = ReflectionData.exports.get(this, EVERYONE_MODULE);
|
||||
if (exports != null) {
|
||||
Boolean b = exports.get(pn);
|
||||
if (b != null) {
|
||||
@ -612,7 +625,7 @@ public final class Module implements AnnotatedElement {
|
||||
if (other != EVERYONE_MODULE) {
|
||||
|
||||
// exported or open to other
|
||||
exports = reflectivelyExports.get(this, other);
|
||||
exports = ReflectionData.exports.get(this, other);
|
||||
if (exports != null) {
|
||||
Boolean b = exports.get(pn);
|
||||
if (b != null) {
|
||||
@ -623,7 +636,7 @@ public final class Module implements AnnotatedElement {
|
||||
|
||||
// other is an unnamed module && exported or open to all unnamed
|
||||
if (!other.isNamed()) {
|
||||
exports = reflectivelyExports.get(this, ALL_UNNAMED_MODULE);
|
||||
exports = ReflectionData.exports.get(this, ALL_UNNAMED_MODULE);
|
||||
if (exports != null) {
|
||||
Boolean b = exports.get(pn);
|
||||
if (b != null) {
|
||||
@ -886,8 +899,8 @@ public final class Module implements AnnotatedElement {
|
||||
}
|
||||
}
|
||||
|
||||
// add package name to reflectivelyExports if absent
|
||||
Map<String, Boolean> map = reflectivelyExports
|
||||
// add package name to exports if absent
|
||||
Map<String, Boolean> map = ReflectionData.exports
|
||||
.computeIfAbsent(this, other,
|
||||
(m1, m2) -> new ConcurrentHashMap<>());
|
||||
if (open) {
|
||||
@ -932,10 +945,6 @@ public final class Module implements AnnotatedElement {
|
||||
|
||||
// -- services --
|
||||
|
||||
// additional service type (2nd key) that some module (1st key) uses
|
||||
private static final WeakPairMap<Module, Class<?>, Boolean> reflectivelyUses
|
||||
= new WeakPairMap<>();
|
||||
|
||||
/**
|
||||
* If the caller's module is this module then update this module to add a
|
||||
* service dependence on the given service type. This method is intended
|
||||
@ -980,7 +989,7 @@ public final class Module implements AnnotatedElement {
|
||||
*/
|
||||
void implAddUses(Class<?> service) {
|
||||
if (!canUse(service)) {
|
||||
reflectivelyUses.putIfAbsent(this, service, Boolean.TRUE);
|
||||
ReflectionData.uses.putIfAbsent(this, service, Boolean.TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1011,7 +1020,7 @@ public final class Module implements AnnotatedElement {
|
||||
return true;
|
||||
|
||||
// uses added via addUses
|
||||
return reflectivelyUses.containsKeyPair(this, service);
|
||||
return ReflectionData.uses.containsKeyPair(this, service);
|
||||
}
|
||||
|
||||
|
||||
@ -1060,8 +1069,11 @@ public final class Module implements AnnotatedElement {
|
||||
Function<String, ClassLoader> clf,
|
||||
ModuleLayer layer)
|
||||
{
|
||||
Map<String, Module> nameToModule = new HashMap<>();
|
||||
Map<String, ClassLoader> moduleToLoader = new HashMap<>();
|
||||
boolean isBootLayer = (ModuleLayer.boot() == null);
|
||||
|
||||
int cap = (int)(cf.modules().size() / 0.75f + 1.0f);
|
||||
Map<String, Module> nameToModule = new HashMap<>(cap);
|
||||
Map<String, ClassLoader> nameToLoader = new HashMap<>(cap);
|
||||
|
||||
Set<ClassLoader> loaders = new HashSet<>();
|
||||
boolean hasPlatformModules = false;
|
||||
@ -1070,7 +1082,7 @@ public final class Module implements AnnotatedElement {
|
||||
for (ResolvedModule resolvedModule : cf.modules()) {
|
||||
String name = resolvedModule.name();
|
||||
ClassLoader loader = clf.apply(name);
|
||||
moduleToLoader.put(name, loader);
|
||||
nameToLoader.put(name, loader);
|
||||
if (loader == null || loader == ClassLoaders.platformClassLoader()) {
|
||||
if (!(clf instanceof ModuleLoaderMap.Mapper)) {
|
||||
throw new IllegalArgumentException("loader can't be 'null'"
|
||||
@ -1087,20 +1099,19 @@ public final class Module implements AnnotatedElement {
|
||||
ModuleReference mref = resolvedModule.reference();
|
||||
ModuleDescriptor descriptor = mref.descriptor();
|
||||
String name = descriptor.name();
|
||||
URI uri = mref.location().orElse(null);
|
||||
ClassLoader loader = moduleToLoader.get(resolvedModule.name());
|
||||
ClassLoader loader = nameToLoader.get(name);
|
||||
Module m;
|
||||
if (loader == null && name.equals("java.base")) {
|
||||
// java.base is already defined to the VM
|
||||
m = Object.class.getModule();
|
||||
} else {
|
||||
URI uri = mref.location().orElse(null);
|
||||
m = new Module(layer, loader, descriptor, uri);
|
||||
}
|
||||
nameToModule.put(name, m);
|
||||
moduleToLoader.put(name, loader);
|
||||
}
|
||||
|
||||
// setup readability and exports
|
||||
// setup readability and exports/opens
|
||||
for (ResolvedModule resolvedModule : cf.modules()) {
|
||||
ModuleReference mref = resolvedModule.reference();
|
||||
ModuleDescriptor descriptor = mref.descriptor();
|
||||
@ -1146,7 +1157,18 @@ public final class Module implements AnnotatedElement {
|
||||
}
|
||||
|
||||
// exports and opens
|
||||
initExportsAndOpens(m, nameToSource, nameToModule, layer.parents());
|
||||
if (descriptor.isOpen() || descriptor.isAutomatic()) {
|
||||
// The VM doesn't special case open or automatic modules yet
|
||||
// so need to export all packages
|
||||
for (String source : descriptor.packages()) {
|
||||
addExportsToAll0(m, source);
|
||||
}
|
||||
} else if (isBootLayer && descriptor.opens().isEmpty()) {
|
||||
// no open packages, no qualified exports to modules in parent layers
|
||||
initExports(m, nameToModule);
|
||||
} else {
|
||||
initExportsAndOpens(m, nameToSource, nameToModule, layer.parents());
|
||||
}
|
||||
}
|
||||
|
||||
// if there are modules defined to the boot or platform class loaders
|
||||
@ -1161,7 +1183,7 @@ public final class Module implements AnnotatedElement {
|
||||
if (!descriptor.provides().isEmpty()) {
|
||||
String name = descriptor.name();
|
||||
Module m = nameToModule.get(name);
|
||||
ClassLoader loader = moduleToLoader.get(name);
|
||||
ClassLoader loader = nameToLoader.get(name);
|
||||
if (loader == null) {
|
||||
bootCatalog.register(m);
|
||||
} else if (loader == pcl) {
|
||||
@ -1179,7 +1201,6 @@ public final class Module implements AnnotatedElement {
|
||||
return nameToModule;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Find the runtime Module corresponding to the given ResolvedModule
|
||||
* in the given parent layer (or its parents).
|
||||
@ -1201,25 +1222,55 @@ public final class Module implements AnnotatedElement {
|
||||
.orElse(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize/setup a module's exports.
|
||||
*
|
||||
* @param m the module
|
||||
* @param nameToModule map of module name to Module (for qualified exports)
|
||||
*/
|
||||
private static void initExports(Module m, Map<String, Module> nameToModule) {
|
||||
Map<String, Set<Module>> exportedPackages = new HashMap<>();
|
||||
|
||||
for (Exports exports : m.getDescriptor().exports()) {
|
||||
String source = exports.source();
|
||||
if (exports.isQualified()) {
|
||||
// qualified exports
|
||||
Set<Module> targets = new HashSet<>();
|
||||
for (String target : exports.targets()) {
|
||||
Module m2 = nameToModule.get(target);
|
||||
if (m2 != null) {
|
||||
addExports0(m, source, m2);
|
||||
targets.add(m2);
|
||||
}
|
||||
}
|
||||
if (!targets.isEmpty()) {
|
||||
exportedPackages.put(source, targets);
|
||||
}
|
||||
} else {
|
||||
// unqualified exports
|
||||
addExportsToAll0(m, source);
|
||||
exportedPackages.put(source, EVERYONE_SET);
|
||||
}
|
||||
}
|
||||
|
||||
if (!exportedPackages.isEmpty())
|
||||
m.exportedPackages = exportedPackages;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the maps of exported and open packages for module m.
|
||||
* Initialize/setup a module's exports.
|
||||
*
|
||||
* @param m the module
|
||||
* @param nameToSource map of module name to Module for modules that m reads
|
||||
* @param nameToModule map of module name to Module for modules in the layer
|
||||
* under construction
|
||||
* @param parents the parent layers
|
||||
*/
|
||||
private static void initExportsAndOpens(Module m,
|
||||
Map<String, Module> nameToSource,
|
||||
Map<String, Module> nameToModule,
|
||||
List<ModuleLayer> parents) {
|
||||
// The VM doesn't special case open or automatic modules so need to
|
||||
// export all packages
|
||||
ModuleDescriptor descriptor = m.getDescriptor();
|
||||
if (descriptor.isOpen() || descriptor.isAutomatic()) {
|
||||
assert descriptor.opens().isEmpty();
|
||||
for (String source : descriptor.packages()) {
|
||||
addExportsToAll0(m, source);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
Map<String, Set<Module>> openPackages = new HashMap<>();
|
||||
Map<String, Set<Module>> exportedPackages = new HashMap<>();
|
||||
|
||||
@ -1272,7 +1323,6 @@ public final class Module implements AnnotatedElement {
|
||||
if (!targets.isEmpty()) {
|
||||
exportedPackages.put(source, targets);
|
||||
}
|
||||
|
||||
} else {
|
||||
// unqualified exports
|
||||
addExportsToAll0(m, source);
|
||||
|
@ -313,6 +313,10 @@ public final class System {
|
||||
* @see java.lang.RuntimePermission
|
||||
*/
|
||||
public static void setSecurityManager(final SecurityManager s) {
|
||||
if (security == null) {
|
||||
// ensure image reader is initialized
|
||||
Object.class.getResource("java/lang/ANY");
|
||||
}
|
||||
if (s != null) {
|
||||
try {
|
||||
s.checkPackageAccess("java.lang");
|
||||
|
@ -31,6 +31,7 @@ import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Deque;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@ -41,6 +42,9 @@ import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import jdk.internal.module.ModuleReferenceImpl;
|
||||
import jdk.internal.module.ModuleTarget;
|
||||
|
||||
/**
|
||||
* A configuration that is the result of <a href="package-summary.html#resolution">
|
||||
* resolution</a> or resolution with <a href="#service-binding">service binding</a>.
|
||||
@ -121,11 +125,8 @@ public final class Configuration {
|
||||
this.targetPlatform = null;
|
||||
}
|
||||
|
||||
private Configuration(List<Configuration> parents,
|
||||
Resolver resolver,
|
||||
boolean check)
|
||||
{
|
||||
Map<ResolvedModule, Set<ResolvedModule>> g = resolver.finish(this, check);
|
||||
private Configuration(List<Configuration> parents, Resolver resolver) {
|
||||
Map<ResolvedModule, Set<ResolvedModule>> g = resolver.finish(this);
|
||||
|
||||
@SuppressWarnings(value = {"rawtypes", "unchecked"})
|
||||
Entry<String, ResolvedModule>[] nameEntries
|
||||
@ -146,6 +147,62 @@ public final class Configuration {
|
||||
this.targetPlatform = resolver.targetPlatform();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the Configuration for the boot layer from a pre-generated
|
||||
* readability graph.
|
||||
*
|
||||
* @apiNote This method is coded for startup performance.
|
||||
*/
|
||||
Configuration(ModuleFinder finder, Map<String, Set<String>> map) {
|
||||
int moduleCount = map.size();
|
||||
|
||||
// create map of name -> ResolvedModule
|
||||
@SuppressWarnings(value = {"rawtypes", "unchecked"})
|
||||
Entry<String, ResolvedModule>[] nameEntries
|
||||
= (Entry<String, ResolvedModule>[])new Entry[moduleCount];
|
||||
ResolvedModule[] moduleArray = new ResolvedModule[moduleCount];
|
||||
String targetPlatform = null;
|
||||
int i = 0;
|
||||
for (String name : map.keySet()) {
|
||||
ModuleReference mref = finder.find(name).orElse(null);
|
||||
assert mref != null;
|
||||
|
||||
if (targetPlatform == null && mref instanceof ModuleReferenceImpl) {
|
||||
ModuleTarget target = ((ModuleReferenceImpl)mref).moduleTarget();
|
||||
if (target != null) {
|
||||
targetPlatform = target.targetPlatform();
|
||||
}
|
||||
}
|
||||
|
||||
ResolvedModule resolvedModule = new ResolvedModule(this, mref);
|
||||
moduleArray[i] = resolvedModule;
|
||||
nameEntries[i] = Map.entry(name, resolvedModule);
|
||||
i++;
|
||||
}
|
||||
Map<String, ResolvedModule> nameToModule = Map.ofEntries(nameEntries);
|
||||
|
||||
// create entries for readability graph
|
||||
@SuppressWarnings(value = {"rawtypes", "unchecked"})
|
||||
Entry<ResolvedModule, Set<ResolvedModule>>[] moduleEntries
|
||||
= (Entry<ResolvedModule, Set<ResolvedModule>>[])new Entry[moduleCount];
|
||||
i = 0;
|
||||
for (ResolvedModule resolvedModule : moduleArray) {
|
||||
Set<String> names = map.get(resolvedModule.name());
|
||||
ResolvedModule[] readsArray = new ResolvedModule[names.size()];
|
||||
int j = 0;
|
||||
for (String name : names) {
|
||||
readsArray[j++] = nameToModule.get(name);
|
||||
}
|
||||
moduleEntries[i++] = Map.entry(resolvedModule, Set.of(readsArray));
|
||||
}
|
||||
|
||||
this.parents = List.of(empty());
|
||||
this.graph = Map.ofEntries(moduleEntries);
|
||||
this.modules = Set.of(moduleArray);
|
||||
this.nameToModule = nameToModule;
|
||||
this.targetPlatform = targetPlatform;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves a collection of root modules, with this configuration as its
|
||||
* parent, to create a new configuration. This method works exactly as
|
||||
@ -233,24 +290,20 @@ public final class Configuration {
|
||||
|
||||
/**
|
||||
* Resolves a collection of root modules, with service binding, and with
|
||||
* the empty configuration as its parent. The consistency checks
|
||||
* are optionally run.
|
||||
* the empty configuration as its parent.
|
||||
*
|
||||
* This method is used to create the configuration for the boot layer.
|
||||
*/
|
||||
static Configuration resolveAndBind(ModuleFinder finder,
|
||||
Collection<String> roots,
|
||||
boolean check,
|
||||
PrintStream traceOutput)
|
||||
{
|
||||
List<Configuration> parents = List.of(empty());
|
||||
Resolver resolver = new Resolver(finder, parents, ModuleFinder.of(), traceOutput);
|
||||
resolver.resolve(roots).bind();
|
||||
|
||||
return new Configuration(parents, resolver, check);
|
||||
return new Configuration(parents, resolver);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Resolves a collection of root modules to create a configuration.
|
||||
*
|
||||
@ -356,7 +409,7 @@ public final class Configuration {
|
||||
Resolver resolver = new Resolver(before, parentList, after, null);
|
||||
resolver.resolve(roots);
|
||||
|
||||
return new Configuration(parentList, resolver, true);
|
||||
return new Configuration(parentList, resolver);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -427,7 +480,7 @@ public final class Configuration {
|
||||
Resolver resolver = new Resolver(before, parentList, after, null);
|
||||
resolver.resolve(roots).bind();
|
||||
|
||||
return new Configuration(parentList, resolver, true);
|
||||
return new Configuration(parentList, resolver);
|
||||
}
|
||||
|
||||
|
||||
|
@ -2728,10 +2728,15 @@ public class ModuleDescriptor
|
||||
@Override
|
||||
public Configuration resolveAndBind(ModuleFinder finder,
|
||||
Collection<String> roots,
|
||||
boolean check,
|
||||
PrintStream traceOutput)
|
||||
{
|
||||
return Configuration.resolveAndBind(finder, roots, check, traceOutput);
|
||||
return Configuration.resolveAndBind(finder, roots, traceOutput);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Configuration newConfiguration(ModuleFinder finder,
|
||||
Map<String, Set<String>> graph) {
|
||||
return new Configuration(finder, graph);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -25,9 +25,7 @@
|
||||
|
||||
package java.lang.module;
|
||||
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.security.AccessController;
|
||||
import java.security.Permission;
|
||||
import java.security.PrivilegedAction;
|
||||
@ -40,10 +38,8 @@ import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
|
||||
import jdk.internal.module.ModuleBootstrap;
|
||||
import jdk.internal.module.ModulePatcher;
|
||||
import jdk.internal.module.ModulePath;
|
||||
import jdk.internal.module.SystemModuleFinder;
|
||||
import jdk.internal.module.SystemModuleFinders;
|
||||
|
||||
/**
|
||||
* A finder of modules. A {@code ModuleFinder} is used to find modules during
|
||||
@ -157,52 +153,13 @@ public interface ModuleFinder {
|
||||
SecurityManager sm = System.getSecurityManager();
|
||||
if (sm != null) {
|
||||
sm.checkPermission(new RuntimePermission("accessSystemModules"));
|
||||
PrivilegedAction<ModuleFinder> pa = ModuleFinder::privilegedOfSystem;
|
||||
PrivilegedAction<ModuleFinder> pa = SystemModuleFinders::ofSystem;
|
||||
return AccessController.doPrivileged(pa);
|
||||
} else {
|
||||
return privilegedOfSystem();
|
||||
return SystemModuleFinders.ofSystem();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a module finder that locates the system modules. This method
|
||||
* assumes it has permissions to access the runtime image.
|
||||
*/
|
||||
private static ModuleFinder privilegedOfSystem() {
|
||||
String home = System.getProperty("java.home");
|
||||
Path modules = Paths.get(home, "lib", "modules");
|
||||
if (Files.isRegularFile(modules)) {
|
||||
return SystemModuleFinder.getInstance();
|
||||
} else {
|
||||
Path dir = Paths.get(home, "modules");
|
||||
if (Files.isDirectory(dir)) {
|
||||
return privilegedOf(ModuleBootstrap.patcher(), dir);
|
||||
} else {
|
||||
throw new InternalError("Unable to detect the run-time image");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a module finder that locates the system modules in an exploded
|
||||
* image. The image may be patched.
|
||||
*/
|
||||
private static ModuleFinder privilegedOf(ModulePatcher patcher, Path dir) {
|
||||
ModuleFinder finder = ModulePath.of(patcher, dir);
|
||||
return new ModuleFinder() {
|
||||
@Override
|
||||
public Optional<ModuleReference> find(String name) {
|
||||
PrivilegedAction<Optional<ModuleReference>> pa = () -> finder.find(name);
|
||||
return AccessController.doPrivileged(pa);
|
||||
}
|
||||
@Override
|
||||
public Set<ModuleReference> findAll() {
|
||||
PrivilegedAction<Set<ModuleReference>> pa = finder::findAll;
|
||||
return AccessController.doPrivileged(pa);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a module finder that locates modules on the file system by
|
||||
* searching a sequence of directories and/or packaged modules.
|
||||
|
@ -353,25 +353,13 @@ final class Resolver {
|
||||
|
||||
/**
|
||||
* Execute post-resolution checks and returns the module graph of resolved
|
||||
* modules as {@code Map}. The resolved modules will be in the given
|
||||
* configuration.
|
||||
*
|
||||
* @param check {@true} to execute the post resolution checks
|
||||
* modules as a map.
|
||||
*/
|
||||
Map<ResolvedModule, Set<ResolvedModule>> finish(Configuration cf,
|
||||
boolean check)
|
||||
{
|
||||
if (check) {
|
||||
detectCycles();
|
||||
checkHashes();
|
||||
}
|
||||
|
||||
Map<ResolvedModule, Set<ResolvedModule>> finish(Configuration cf) {
|
||||
detectCycles();
|
||||
checkHashes();
|
||||
Map<ResolvedModule, Set<ResolvedModule>> graph = makeGraph(cf);
|
||||
|
||||
if (check) {
|
||||
checkExportSuppliers(graph);
|
||||
}
|
||||
|
||||
checkExportSuppliers(graph);
|
||||
return graph;
|
||||
}
|
||||
|
||||
|
@ -409,7 +409,7 @@ public final class URL implements java.io.Serializable {
|
||||
}
|
||||
}
|
||||
|
||||
protocol = protocol.toLowerCase(Locale.ROOT);
|
||||
protocol = toLowerCase(protocol);
|
||||
this.protocol = protocol;
|
||||
if (host != null) {
|
||||
|
||||
@ -585,7 +585,7 @@ public final class URL implements java.io.Serializable {
|
||||
for (i = start ; !aRef && (i < limit) &&
|
||||
((c = spec.charAt(i)) != '/') ; i++) {
|
||||
if (c == ':') {
|
||||
String s = spec.substring(start, i).toLowerCase(Locale.ROOT);
|
||||
String s = toLowerCase(spec.substring(start, i));
|
||||
if (isValidProtocol(s)) {
|
||||
newProtocol = s;
|
||||
start = i + 1;
|
||||
@ -1318,6 +1318,17 @@ public final class URL implements java.io.Serializable {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the protocol in lower case. Special cases known protocols
|
||||
* to avoid loading locale classes during startup.
|
||||
*/
|
||||
static String toLowerCase(String protocol) {
|
||||
if (protocol.equals("jrt") || protocol.equals("file") || protocol.equals("jar")) {
|
||||
return protocol;
|
||||
} else {
|
||||
return protocol.toLowerCase(Locale.ROOT);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Non-overrideable protocols: "jrt" and "file"
|
||||
|
@ -55,13 +55,13 @@ import java.util.Map;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.function.Function;
|
||||
import java.util.jar.Attributes;
|
||||
import java.util.jar.Manifest;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import jdk.internal.misc.VM;
|
||||
import jdk.internal.module.ModulePatcher.PatchedModuleReader;
|
||||
import jdk.internal.module.SystemModules;
|
||||
import jdk.internal.module.Resources;
|
||||
|
||||
|
||||
@ -139,7 +139,7 @@ public class BuiltinClassLoader
|
||||
|
||||
// maps package name to loaded module for modules in the boot layer
|
||||
private static final Map<String, LoadedModule> packageToModule
|
||||
= new ConcurrentHashMap<>(SystemModules.PACKAGES_IN_BOOT_LAYER);
|
||||
= new ConcurrentHashMap<>(1024);
|
||||
|
||||
// maps a module name to a module reference
|
||||
private final Map<String, ModuleReference> nameToModule;
|
||||
@ -946,9 +946,16 @@ public class BuiltinClassLoader
|
||||
URL url = cs.getLocation();
|
||||
if (url == null)
|
||||
return perms;
|
||||
Permission p = null;
|
||||
|
||||
// avoid opening connection when URL is to resource in run-time image
|
||||
if (url.getProtocol().equals("jrt")) {
|
||||
perms.add(new RuntimePermission("accessSystemModules"));
|
||||
return perms;
|
||||
}
|
||||
|
||||
// open connection to determine the permission needed
|
||||
try {
|
||||
p = url.openConnection().getPermission();
|
||||
Permission p = url.openConnection().getPermission();
|
||||
if (p != null) {
|
||||
// for directories then need recursive access
|
||||
if (p instanceof FilePermission) {
|
||||
@ -969,23 +976,26 @@ public class BuiltinClassLoader
|
||||
// -- miscellaneous supporting methods
|
||||
|
||||
/**
|
||||
* Returns the ModuleReader for the given module.
|
||||
* Returns the ModuleReader for the given module, creating it if needed
|
||||
*/
|
||||
private ModuleReader moduleReaderFor(ModuleReference mref) {
|
||||
return moduleToReader.computeIfAbsent(mref, BuiltinClassLoader::createModuleReader);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a ModuleReader for the given module.
|
||||
*/
|
||||
private static ModuleReader createModuleReader(ModuleReference mref) {
|
||||
try {
|
||||
return mref.open();
|
||||
} catch (IOException e) {
|
||||
// Return a null module reader to avoid a future class load
|
||||
// attempting to open the module again.
|
||||
return new NullModuleReader();
|
||||
ModuleReader reader = moduleToReader.get(mref);
|
||||
if (reader == null) {
|
||||
// avoid method reference during startup
|
||||
Function<ModuleReference, ModuleReader> create = new Function<>() {
|
||||
public ModuleReader apply(ModuleReference moduleReference) {
|
||||
try {
|
||||
return mref.open();
|
||||
} catch (IOException e) {
|
||||
// Return a null module reader to avoid a future class
|
||||
// load attempting to open the module again.
|
||||
return new NullModuleReader();
|
||||
}
|
||||
}
|
||||
};
|
||||
reader = moduleToReader.computeIfAbsent(mref, create);
|
||||
}
|
||||
return reader;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -25,7 +25,6 @@
|
||||
|
||||
package jdk.internal.loader;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.nio.file.InvalidPathException;
|
||||
@ -38,7 +37,6 @@ import jdk.internal.misc.JavaLangAccess;
|
||||
import jdk.internal.misc.SharedSecrets;
|
||||
import jdk.internal.misc.VM;
|
||||
|
||||
|
||||
/**
|
||||
* Creates and provides access to the built-in platform and application class
|
||||
* loaders. It also creates the class loader that is used to locate resources
|
||||
@ -61,23 +59,30 @@ public class ClassLoaders {
|
||||
*/
|
||||
static {
|
||||
|
||||
// -Xbootclasspth/a or -javaagent Boot-Class-Path
|
||||
// -Xbootclasspath/a or -javaagent with Boot-Class-Path attribute
|
||||
URLClassPath bcp = null;
|
||||
String s = VM.getSavedProperty("jdk.boot.class.path.append");
|
||||
if (s != null && s.length() > 0)
|
||||
bcp = toURLClassPath(s);
|
||||
bcp = new URLClassPath(s, true);
|
||||
|
||||
// we have a class path if -cp is specified or -m is not specified.
|
||||
// If neither is specified then default to -cp <working directory>
|
||||
// If -cp is not specified and -m is specified, the value of
|
||||
// java.class.path is an empty string, then no class path.
|
||||
URLClassPath ucp = new URLClassPath(new URL[0]);
|
||||
String mainMid = System.getProperty("jdk.module.main");
|
||||
String cp = System.getProperty("java.class.path");
|
||||
if (cp == null)
|
||||
cp = "";
|
||||
if (mainMid == null || cp.length() > 0)
|
||||
addClassPathToUCP(cp, ucp);
|
||||
if (mainMid == null) {
|
||||
// no main module specified so class path required
|
||||
if (cp == null) {
|
||||
cp = "";
|
||||
}
|
||||
} else {
|
||||
// main module specified, ignore empty class path
|
||||
if (cp != null && cp.length() == 0) {
|
||||
cp = null;
|
||||
}
|
||||
}
|
||||
URLClassPath ucp = new URLClassPath(cp, false);
|
||||
|
||||
// create the class loaders
|
||||
BOOT_LOADER = new BootClassLoader(bcp);
|
||||
@ -198,7 +203,7 @@ public class ClassLoaders {
|
||||
* @see java.lang.instrument.Instrumentation#appendToSystemClassLoaderSearch
|
||||
*/
|
||||
void appendToClassPathForInstrumentation(String path) {
|
||||
addClassPathToUCP(path, ucp);
|
||||
ucp.addFile(path);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -219,41 +224,12 @@ public class ClassLoaders {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@code URLClassPath} of file URLs to each of the elements in
|
||||
* the given class path.
|
||||
*/
|
||||
private static URLClassPath toURLClassPath(String cp) {
|
||||
URLClassPath ucp = new URLClassPath(new URL[0]);
|
||||
addClassPathToUCP(cp, ucp);
|
||||
return ucp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the elements in the given class path to file URLs and adds
|
||||
* them to the given URLClassPath.
|
||||
*/
|
||||
private static void addClassPathToUCP(String cp, URLClassPath ucp) {
|
||||
int off = 0;
|
||||
int next;
|
||||
while ((next = cp.indexOf(File.pathSeparator, off)) != -1) {
|
||||
URL url = toFileURL(cp.substring(off, next));
|
||||
if (url != null)
|
||||
ucp.addURL(url);
|
||||
off = next + 1;
|
||||
}
|
||||
|
||||
// remaining
|
||||
URL url = toFileURL(cp.substring(off));
|
||||
if (url != null)
|
||||
ucp.addURL(url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to convert the given string to a file URL.
|
||||
*
|
||||
* @apiNote This is called by the VM
|
||||
*/
|
||||
@Deprecated
|
||||
private static URL toFileURL(String s) {
|
||||
try {
|
||||
// Use an intermediate File object to construct a URI/URL without
|
||||
@ -265,5 +241,4 @@ public class ClassLoaders {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -46,6 +46,7 @@ import java.security.Permission;
|
||||
import java.security.PrivilegedExceptionAction;
|
||||
import java.security.cert.Certificate;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashMap;
|
||||
@ -66,7 +67,6 @@ import java.util.jar.Attributes.Name;
|
||||
import java.util.zip.ZipFile;
|
||||
|
||||
import jdk.internal.misc.JavaNetURLAccess;
|
||||
import jdk.internal.misc.JavaNetURLClassLoaderAccess;
|
||||
import jdk.internal.misc.JavaUtilZipFileAccess;
|
||||
import jdk.internal.misc.SharedSecrets;
|
||||
import jdk.internal.util.jar.InvalidJarIndexError;
|
||||
@ -100,19 +100,19 @@ public class URLClassPath {
|
||||
}
|
||||
|
||||
/* The original search path of URLs. */
|
||||
private ArrayList<URL> path = new ArrayList<>();
|
||||
private final List<URL> path;
|
||||
|
||||
/* The stack of unopened URLs */
|
||||
Stack<URL> urls = new Stack<>();
|
||||
private final Stack<URL> urls = new Stack<>();
|
||||
|
||||
/* The resulting search path of Loaders */
|
||||
ArrayList<Loader> loaders = new ArrayList<>();
|
||||
private final ArrayList<Loader> loaders = new ArrayList<>();
|
||||
|
||||
/* Map of each URL opened to its corresponding Loader */
|
||||
HashMap<String, Loader> lmap = new HashMap<>();
|
||||
private final HashMap<String, Loader> lmap = new HashMap<>();
|
||||
|
||||
/* The jar protocol handler to use when creating new URLs */
|
||||
private URLStreamHandler jarHandler;
|
||||
private final URLStreamHandler jarHandler;
|
||||
|
||||
/* Whether this URLClassLoader has been closed yet */
|
||||
private boolean closed = false;
|
||||
@ -137,12 +137,16 @@ public class URLClassPath {
|
||||
public URLClassPath(URL[] urls,
|
||||
URLStreamHandlerFactory factory,
|
||||
AccessControlContext acc) {
|
||||
for (int i = 0; i < urls.length; i++) {
|
||||
path.add(urls[i]);
|
||||
List<URL> path = new ArrayList<>(urls.length);
|
||||
for (URL url : urls) {
|
||||
path.add(url);
|
||||
}
|
||||
this.path = path;
|
||||
push(urls);
|
||||
if (factory != null) {
|
||||
jarHandler = factory.createURLStreamHandler("jar");
|
||||
} else {
|
||||
jarHandler = null;
|
||||
}
|
||||
if (DISABLE_ACC_CHECKING)
|
||||
this.acc = null;
|
||||
@ -150,18 +154,52 @@ public class URLClassPath {
|
||||
this.acc = acc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a URLClassPath with no additional security restrictions.
|
||||
* Used by code that implements the class path.
|
||||
*/
|
||||
public URLClassPath(URL[] urls) {
|
||||
this(urls, null, null);
|
||||
}
|
||||
|
||||
public URLClassPath(URL[] urls, AccessControlContext acc) {
|
||||
this(urls, null, acc);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a URLClassPath from a class path string.
|
||||
*
|
||||
* @param cp the class path string
|
||||
* @param skipEmptyElements indicates if empty elements are ignored or
|
||||
* treated as the current working directory
|
||||
*
|
||||
* @apiNote Used to create the application class path.
|
||||
*/
|
||||
URLClassPath(String cp, boolean skipEmptyElements) {
|
||||
List<URL> path = new ArrayList<>();
|
||||
if (cp != null) {
|
||||
// map each element of class path to a file URL
|
||||
int off = 0;
|
||||
int next;
|
||||
while ((next = cp.indexOf(File.pathSeparator, off)) != -1) {
|
||||
String element = cp.substring(off, next);
|
||||
if (element.length() > 0 || !skipEmptyElements) {
|
||||
URL url = toFileURL(element);
|
||||
if (url != null) path.add(url);
|
||||
}
|
||||
off = next + 1;
|
||||
}
|
||||
|
||||
// remaining element
|
||||
String element = cp.substring(off);
|
||||
if (element.length() > 0 || !skipEmptyElements) {
|
||||
URL url = toFileURL(element);
|
||||
if (url != null) path.add(url);
|
||||
}
|
||||
|
||||
// push the URLs
|
||||
for (int i = path.size() - 1; i >= 0; --i) {
|
||||
urls.push(path.get(i));
|
||||
}
|
||||
}
|
||||
|
||||
this.path = path;
|
||||
this.jarHandler = null;
|
||||
this.acc = null;
|
||||
}
|
||||
|
||||
public synchronized List<IOException> closeLoaders() {
|
||||
if (closed) {
|
||||
return Collections.emptyList();
|
||||
@ -197,6 +235,28 @@ public class URLClassPath {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends the specified file path as a file URL to the search path.
|
||||
*/
|
||||
public void addFile(String s) {
|
||||
URL url = toFileURL(s);
|
||||
if (url != null) {
|
||||
addURL(url);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a file URL for the given file path.
|
||||
*/
|
||||
private static URL toFileURL(String s) {
|
||||
try {
|
||||
File f = new File(s).getCanonicalFile();
|
||||
return ParseUtil.fileToEncodedURL(f);
|
||||
} catch (IOException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the original search path of URLs.
|
||||
*/
|
||||
|
@ -34,16 +34,10 @@ import java.lang.module.ModuleDescriptor.Requires;
|
||||
import java.lang.module.ModuleDescriptor.Provides;
|
||||
import java.lang.module.ModuleDescriptor.Version;
|
||||
import java.lang.module.ModuleFinder;
|
||||
import java.lang.module.ModuleReader;
|
||||
import java.lang.module.ModuleReference;
|
||||
import java.net.URI;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import jdk.internal.module.ModuleHashes;
|
||||
|
||||
/**
|
||||
* Provides access to non-public methods in java.lang.module.
|
||||
@ -131,12 +125,16 @@ public interface JavaLangModuleAccess {
|
||||
|
||||
/**
|
||||
* Resolves a collection of root modules, with service binding
|
||||
* and the empty configuration as the parent. The post resolution
|
||||
* checks are optionally run.
|
||||
* and the empty configuration as the parent.
|
||||
*/
|
||||
Configuration resolveAndBind(ModuleFinder finder,
|
||||
Collection<String> roots,
|
||||
boolean check,
|
||||
PrintStream traceOutput);
|
||||
|
||||
/**
|
||||
* Creates a configuration from a pre-generated readability graph.
|
||||
*/
|
||||
Configuration newConfiguration(ModuleFinder finder,
|
||||
Map<String, Set<String>> graph);
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,93 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package jdk.internal.module;
|
||||
|
||||
import java.lang.module.ModuleDescriptor;
|
||||
import java.lang.module.ModuleFinder;
|
||||
import java.lang.module.ModuleReference;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Defines methods to compute the default set of root modules for the unnamed
|
||||
* module.
|
||||
*/
|
||||
|
||||
public final class DefaultRoots {
|
||||
private static final String JAVA_SE = "java.se";
|
||||
|
||||
private DefaultRoots() { }
|
||||
|
||||
/**
|
||||
* Returns the default set of root modules for the unnamed module computed from
|
||||
* the system modules observable with the given module finder.
|
||||
*/
|
||||
static Set<String> compute(ModuleFinder systemModuleFinder, ModuleFinder finder) {
|
||||
Set<String> roots = new HashSet<>();
|
||||
|
||||
boolean hasJava = false;
|
||||
if (systemModuleFinder.find(JAVA_SE).isPresent()) {
|
||||
if (finder == systemModuleFinder || finder.find(JAVA_SE).isPresent()) {
|
||||
// java.se is a system module
|
||||
hasJava = true;
|
||||
roots.add(JAVA_SE);
|
||||
}
|
||||
}
|
||||
|
||||
for (ModuleReference mref : systemModuleFinder.findAll()) {
|
||||
String mn = mref.descriptor().name();
|
||||
if (hasJava && mn.startsWith("java.")) {
|
||||
// not a root
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ModuleResolution.doNotResolveByDefault(mref)) {
|
||||
// not a root
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((finder == systemModuleFinder || finder.find(mn).isPresent())) {
|
||||
// add as root if exports at least one package to all modules
|
||||
ModuleDescriptor descriptor = mref.descriptor();
|
||||
for (ModuleDescriptor.Exports e : descriptor.exports()) {
|
||||
if (!e.isQualified()) {
|
||||
roots.add(mn);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return roots;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the default set of root modules for the unnamed module from the
|
||||
* modules observable with the given module finder.
|
||||
*/
|
||||
public static Set<String> compute(ModuleFinder finder) {
|
||||
return compute(finder, finder);
|
||||
}
|
||||
}
|
@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.internal.module;
|
||||
|
||||
import java.lang.module.ModuleDescriptor;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* A dummy SystemModules for use with exploded builds or testing.
|
||||
*/
|
||||
|
||||
class ExplodedSystemModules implements SystemModules {
|
||||
@Override
|
||||
public boolean hasSplitPackages() {
|
||||
return true; // not known
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasIncubatorModules() {
|
||||
return true; // not known
|
||||
}
|
||||
|
||||
@Override
|
||||
public ModuleDescriptor[] moduleDescriptors() {
|
||||
throw new InternalError();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ModuleTarget[] moduleTargets() {
|
||||
throw new InternalError();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ModuleHashes[] moduleHashes() {
|
||||
throw new InternalError();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ModuleResolution[] moduleResolutions() {
|
||||
throw new InternalError();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Set<String>> moduleReads() {
|
||||
throw new InternalError();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Set<String>> concealedPackagesToOpen() {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Set<String>> exportedPackagesToOpen() {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
}
|
@ -40,16 +40,20 @@ import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import jdk.internal.loader.BootLoader;
|
||||
import jdk.internal.loader.BuiltinClassLoader;
|
||||
import jdk.internal.misc.JavaLangAccess;
|
||||
import jdk.internal.misc.JavaLangModuleAccess;
|
||||
import jdk.internal.misc.SharedSecrets;
|
||||
import jdk.internal.perf.PerfCounter;
|
||||
|
||||
@ -70,8 +74,6 @@ public final class ModuleBootstrap {
|
||||
|
||||
private static final String JAVA_BASE = "java.base";
|
||||
|
||||
private static final String JAVA_SE = "java.se";
|
||||
|
||||
// the token for "all default modules"
|
||||
private static final String ALL_DEFAULT = "ALL-DEFAULT";
|
||||
|
||||
@ -84,13 +86,13 @@ public final class ModuleBootstrap {
|
||||
// the token for "all modules on the module path"
|
||||
private static final String ALL_MODULE_PATH = "ALL-MODULE-PATH";
|
||||
|
||||
// access to java.lang/module
|
||||
private static final JavaLangModuleAccess JLMA
|
||||
= SharedSecrets.getJavaLangModuleAccess();
|
||||
|
||||
// The ModulePatcher for the initial configuration
|
||||
private static final ModulePatcher patcher = initModulePatcher();
|
||||
|
||||
// ModuleFinders for the initial configuration
|
||||
private static ModuleFinder unlimitedFinder;
|
||||
private static ModuleFinder limitedFinder;
|
||||
|
||||
/**
|
||||
* Returns the ModulePatcher for the initial configuration.
|
||||
*/
|
||||
@ -98,21 +100,38 @@ public final class ModuleBootstrap {
|
||||
return patcher;
|
||||
}
|
||||
|
||||
// ModuleFinders for the initial configuration
|
||||
private static volatile ModuleFinder unlimitedFinder;
|
||||
private static volatile ModuleFinder limitedFinder;
|
||||
|
||||
/**
|
||||
* Returns the ModuleFinder for the initial configuration before observability
|
||||
* is limited by the --limit-modules command line option.
|
||||
* Returns the ModuleFinder for the initial configuration before
|
||||
* observability is limited by the --limit-modules command line option.
|
||||
*
|
||||
* @apiNote Used to support locating modules {@code java.instrument} and
|
||||
* {@code jdk.management.agent} modules when they are loaded dynamically.
|
||||
*/
|
||||
public static ModuleFinder unlimitedFinder() {
|
||||
assert unlimitedFinder != null;
|
||||
return unlimitedFinder;
|
||||
ModuleFinder finder = unlimitedFinder;
|
||||
if (finder == null) {
|
||||
return ModuleFinder.ofSystem();
|
||||
} else {
|
||||
return finder;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the ModuleFinder for the initial configuration.
|
||||
*
|
||||
* @apiNote Used to support "{@code java --list-modules}".
|
||||
*/
|
||||
public static ModuleFinder limitedFinder() {
|
||||
assert limitedFinder != null;
|
||||
return limitedFinder;
|
||||
ModuleFinder finder = limitedFinder;
|
||||
if (finder == null) {
|
||||
return unlimitedFinder();
|
||||
} else {
|
||||
return finder;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -120,13 +139,60 @@ public final class ModuleBootstrap {
|
||||
*
|
||||
* @see java.lang.System#initPhase2()
|
||||
*/
|
||||
public static ModuleLayer boot() {
|
||||
public static ModuleLayer boot() throws Exception {
|
||||
|
||||
// Step 1: Locate system modules (may be patched)
|
||||
// Step 0: Command line options
|
||||
|
||||
long t0 = System.nanoTime();
|
||||
|
||||
ModuleFinder upgradeModulePath = finderFor("jdk.module.upgrade.path");
|
||||
ModuleFinder appModulePath = finderFor("jdk.module.path");
|
||||
boolean isPatched = patcher.hasPatches();
|
||||
|
||||
String mainModule = System.getProperty("jdk.module.main");
|
||||
Set<String> addModules = addModules();
|
||||
Set<String> limitModules = limitModules();
|
||||
|
||||
PrintStream traceOutput = null;
|
||||
String trace = getAndRemoveProperty("jdk.module.showModuleResolution");
|
||||
if (trace != null && Boolean.parseBoolean(trace))
|
||||
traceOutput = System.out;
|
||||
|
||||
|
||||
// Step 1: The observable system modules, either all system modules
|
||||
// or the system modules pre-generated for the initial module (the
|
||||
// initial module may be the unnamed module). If the system modules
|
||||
// are pre-generated for the initial module then resolution can be
|
||||
// skipped.
|
||||
|
||||
long t1 = System.nanoTime();
|
||||
ModuleFinder systemModules = ModuleFinder.ofSystem();
|
||||
PerfCounters.systemModulesTime.addElapsedTimeFrom(t1);
|
||||
|
||||
SystemModules systemModules = null;
|
||||
ModuleFinder systemModuleFinder;
|
||||
|
||||
boolean haveModulePath = (appModulePath != null || upgradeModulePath != null);
|
||||
boolean needResolution = true;
|
||||
|
||||
if (!haveModulePath && addModules.isEmpty() && limitModules.isEmpty()) {
|
||||
systemModules = SystemModuleFinders.systemModules(mainModule);
|
||||
if (systemModules != null && !isPatched && (traceOutput == null)) {
|
||||
needResolution = false;
|
||||
}
|
||||
}
|
||||
if (systemModules == null) {
|
||||
// all system modules are observable
|
||||
systemModules = SystemModuleFinders.allSystemModules();
|
||||
}
|
||||
if (systemModules != null) {
|
||||
// images build
|
||||
systemModuleFinder = SystemModuleFinders.of(systemModules);
|
||||
} else {
|
||||
// exploded build or testing
|
||||
systemModules = new ExplodedSystemModules();
|
||||
systemModuleFinder = SystemModuleFinders.ofSystem();
|
||||
}
|
||||
|
||||
Counters.add("jdk.module.boot.1.systemModulesTime", t1);
|
||||
|
||||
|
||||
// Step 2: Define and load java.base. This patches all classes loaded
|
||||
@ -136,7 +202,7 @@ public final class ModuleBootstrap {
|
||||
|
||||
long t2 = System.nanoTime();
|
||||
|
||||
ModuleReference base = systemModules.find(JAVA_BASE).orElse(null);
|
||||
ModuleReference base = systemModuleFinder.find(JAVA_BASE).orElse(null);
|
||||
if (base == null)
|
||||
throw new InternalError(JAVA_BASE + " not found");
|
||||
URI baseUri = base.location().orElse(null);
|
||||
@ -145,171 +211,138 @@ public final class ModuleBootstrap {
|
||||
BootLoader.loadModule(base);
|
||||
Modules.defineModule(null, base.descriptor(), baseUri);
|
||||
|
||||
PerfCounters.defineBaseTime.addElapsedTimeFrom(t2);
|
||||
Counters.add("jdk.module.boot.2.defineBaseTime", t2);
|
||||
|
||||
|
||||
// Step 2a: If --validate-modules is specified then the VM needs to
|
||||
// start with only java.base, all other options are ignored.
|
||||
|
||||
String propValue = getAndRemoveProperty("jdk.module.minimumBoot");
|
||||
if (propValue != null) {
|
||||
if (getAndRemoveProperty("jdk.module.minimumBoot") != null) {
|
||||
return createMinimalBootLayer();
|
||||
}
|
||||
|
||||
|
||||
// Step 3: Construct the module path and the set of root modules to
|
||||
// resolve. If --limit-modules is specified then it limits the set
|
||||
// modules that are observable.
|
||||
// Step 3: If resolution is needed then create the module finder and
|
||||
// the set of root modules to resolve.
|
||||
|
||||
long t3 = System.nanoTime();
|
||||
|
||||
// --upgrade-module-path option specified to launcher
|
||||
ModuleFinder upgradeModulePath
|
||||
= createModulePathFinder("jdk.module.upgrade.path");
|
||||
if (upgradeModulePath != null)
|
||||
systemModules = ModuleFinder.compose(upgradeModulePath, systemModules);
|
||||
ModuleFinder savedModuleFinder = null;
|
||||
ModuleFinder finder;
|
||||
Set<String> roots;
|
||||
if (needResolution) {
|
||||
|
||||
// --module-path option specified to the launcher
|
||||
ModuleFinder appModulePath = createModulePathFinder("jdk.module.path");
|
||||
// upgraded modules override the modules in the run-time image
|
||||
if (upgradeModulePath != null)
|
||||
systemModuleFinder = ModuleFinder.compose(upgradeModulePath,
|
||||
systemModuleFinder);
|
||||
|
||||
// The module finder: [--upgrade-module-path] system [--module-path]
|
||||
ModuleFinder finder = systemModules;
|
||||
if (appModulePath != null)
|
||||
finder = ModuleFinder.compose(finder, appModulePath);
|
||||
|
||||
// The root modules to resolve
|
||||
Set<String> roots = new HashSet<>();
|
||||
|
||||
// launcher -m option to specify the main/initial module
|
||||
String mainModule = System.getProperty("jdk.module.main");
|
||||
if (mainModule != null)
|
||||
roots.add(mainModule);
|
||||
|
||||
// additional module(s) specified by --add-modules
|
||||
boolean addAllDefaultModules = false;
|
||||
boolean addAllSystemModules = false;
|
||||
boolean addAllApplicationModules = false;
|
||||
for (String mod: getExtraAddModules()) {
|
||||
switch (mod) {
|
||||
case ALL_DEFAULT:
|
||||
addAllDefaultModules = true;
|
||||
break;
|
||||
case ALL_SYSTEM:
|
||||
addAllSystemModules = true;
|
||||
break;
|
||||
case ALL_MODULE_PATH:
|
||||
addAllApplicationModules = true;
|
||||
break;
|
||||
default :
|
||||
roots.add(mod);
|
||||
// The module finder: [--upgrade-module-path] system [--module-path]
|
||||
if (appModulePath != null) {
|
||||
finder = ModuleFinder.compose(systemModuleFinder, appModulePath);
|
||||
} else {
|
||||
finder = systemModuleFinder;
|
||||
}
|
||||
}
|
||||
|
||||
// --limit-modules
|
||||
unlimitedFinder = finder;
|
||||
propValue = getAndRemoveProperty("jdk.module.limitmods");
|
||||
if (propValue != null) {
|
||||
Set<String> mods = new HashSet<>();
|
||||
for (String mod: propValue.split(",")) {
|
||||
mods.add(mod);
|
||||
}
|
||||
finder = limitFinder(finder, mods, roots);
|
||||
}
|
||||
limitedFinder = finder;
|
||||
// The root modules to resolve
|
||||
roots = new HashSet<>();
|
||||
|
||||
// If there is no initial module specified then assume that the initial
|
||||
// module is the unnamed module of the application class loader. This
|
||||
// is implemented by resolving "java.se" and all (non-java.*) modules
|
||||
// that export an API. If "java.se" is not observable then all java.*
|
||||
// modules are resolved. Modules that have the DO_NOT_RESOLVE_BY_DEFAULT
|
||||
// bit set in their ModuleResolution attribute flags are excluded from
|
||||
// the default set of roots.
|
||||
if (mainModule == null || addAllDefaultModules) {
|
||||
boolean hasJava = false;
|
||||
if (systemModules.find(JAVA_SE).isPresent()) {
|
||||
// java.se is a system module
|
||||
if (finder == systemModules || finder.find(JAVA_SE).isPresent()) {
|
||||
// java.se is observable
|
||||
hasJava = true;
|
||||
roots.add(JAVA_SE);
|
||||
// launcher -m option to specify the main/initial module
|
||||
if (mainModule != null)
|
||||
roots.add(mainModule);
|
||||
|
||||
// additional module(s) specified by --add-modules
|
||||
boolean addAllDefaultModules = false;
|
||||
boolean addAllSystemModules = false;
|
||||
boolean addAllApplicationModules = false;
|
||||
for (String mod : addModules) {
|
||||
switch (mod) {
|
||||
case ALL_DEFAULT:
|
||||
addAllDefaultModules = true;
|
||||
break;
|
||||
case ALL_SYSTEM:
|
||||
addAllSystemModules = true;
|
||||
break;
|
||||
case ALL_MODULE_PATH:
|
||||
addAllApplicationModules = true;
|
||||
break;
|
||||
default:
|
||||
roots.add(mod);
|
||||
}
|
||||
}
|
||||
|
||||
for (ModuleReference mref : systemModules.findAll()) {
|
||||
String mn = mref.descriptor().name();
|
||||
if (hasJava && mn.startsWith("java."))
|
||||
continue;
|
||||
|
||||
if (ModuleResolution.doNotResolveByDefault(mref))
|
||||
continue;
|
||||
|
||||
// add as root if observable and exports at least one package
|
||||
if ((finder == systemModules || finder.find(mn).isPresent())) {
|
||||
ModuleDescriptor descriptor = mref.descriptor();
|
||||
for (ModuleDescriptor.Exports e : descriptor.exports()) {
|
||||
if (!e.isQualified()) {
|
||||
roots.add(mn);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// --limit-modules
|
||||
savedModuleFinder = finder;
|
||||
if (!limitModules.isEmpty()) {
|
||||
finder = limitFinder(finder, limitModules, roots);
|
||||
}
|
||||
|
||||
// If there is no initial module specified then assume that the initial
|
||||
// module is the unnamed module of the application class loader. This
|
||||
// is implemented by resolving "java.se" and all (non-java.*) modules
|
||||
// that export an API. If "java.se" is not observable then all java.*
|
||||
// modules are resolved. Modules that have the DO_NOT_RESOLVE_BY_DEFAULT
|
||||
// bit set in their ModuleResolution attribute flags are excluded from
|
||||
// the default set of roots.
|
||||
if (mainModule == null || addAllDefaultModules) {
|
||||
roots.addAll(DefaultRoots.compute(systemModuleFinder, finder));
|
||||
}
|
||||
|
||||
// If `--add-modules ALL-SYSTEM` is specified then all observable system
|
||||
// modules will be resolved.
|
||||
if (addAllSystemModules) {
|
||||
ModuleFinder f = finder; // observable modules
|
||||
systemModuleFinder.findAll()
|
||||
.stream()
|
||||
.map(ModuleReference::descriptor)
|
||||
.map(ModuleDescriptor::name)
|
||||
.filter(mn -> f.find(mn).isPresent()) // observable
|
||||
.forEach(mn -> roots.add(mn));
|
||||
}
|
||||
|
||||
// If `--add-modules ALL-MODULE-PATH` is specified then all observable
|
||||
// modules on the application module path will be resolved.
|
||||
if (appModulePath != null && addAllApplicationModules) {
|
||||
ModuleFinder f = finder; // observable modules
|
||||
appModulePath.findAll()
|
||||
.stream()
|
||||
.map(ModuleReference::descriptor)
|
||||
.map(ModuleDescriptor::name)
|
||||
.filter(mn -> f.find(mn).isPresent()) // observable
|
||||
.forEach(mn -> roots.add(mn));
|
||||
}
|
||||
} else {
|
||||
// no resolution case
|
||||
finder = systemModuleFinder;
|
||||
roots = null;
|
||||
}
|
||||
|
||||
// If `--add-modules ALL-SYSTEM` is specified then all observable system
|
||||
// modules will be resolved.
|
||||
if (addAllSystemModules) {
|
||||
ModuleFinder f = finder; // observable modules
|
||||
systemModules.findAll()
|
||||
.stream()
|
||||
.map(ModuleReference::descriptor)
|
||||
.map(ModuleDescriptor::name)
|
||||
.filter(mn -> f.find(mn).isPresent()) // observable
|
||||
.forEach(mn -> roots.add(mn));
|
||||
}
|
||||
|
||||
// If `--add-modules ALL-MODULE-PATH` is specified then all observable
|
||||
// modules on the application module path will be resolved.
|
||||
if (appModulePath != null && addAllApplicationModules) {
|
||||
ModuleFinder f = finder; // observable modules
|
||||
appModulePath.findAll()
|
||||
.stream()
|
||||
.map(ModuleReference::descriptor)
|
||||
.map(ModuleDescriptor::name)
|
||||
.filter(mn -> f.find(mn).isPresent()) // observable
|
||||
.forEach(mn -> roots.add(mn));
|
||||
}
|
||||
|
||||
PerfCounters.optionsAndRootsTime.addElapsedTimeFrom(t3);
|
||||
|
||||
Counters.add("jdk.module.boot.3.optionsAndRootsTime", t3);
|
||||
|
||||
// Step 4: Resolve the root modules, with service binding, to create
|
||||
// the configuration for the boot layer.
|
||||
// the configuration for the boot layer. If resolution is not needed
|
||||
// then create the configuration for the boot layer from the
|
||||
// readability graph created at link time.
|
||||
|
||||
long t4 = System.nanoTime();
|
||||
|
||||
// determine if post resolution checks are needed
|
||||
boolean needPostResolutionChecks = true;
|
||||
if (baseUri.getScheme().equals("jrt") // toLowerCase not needed here
|
||||
&& (upgradeModulePath == null)
|
||||
&& (appModulePath == null)
|
||||
&& (patcher.isEmpty())) {
|
||||
needPostResolutionChecks = false;
|
||||
Configuration cf;
|
||||
if (needResolution) {
|
||||
cf = JLMA.resolveAndBind(finder, roots, traceOutput);
|
||||
} else {
|
||||
Map<String, Set<String>> map = systemModules.moduleReads();
|
||||
cf = JLMA.newConfiguration(systemModuleFinder, map);
|
||||
}
|
||||
|
||||
PrintStream traceOutput = null;
|
||||
propValue = getAndRemoveProperty("jdk.module.showModuleResolution");
|
||||
if (propValue != null && Boolean.parseBoolean(propValue))
|
||||
traceOutput = System.out;
|
||||
// check that modules specified to --patch-module are resolved
|
||||
if (isPatched) {
|
||||
patcher.patchedModules()
|
||||
.stream()
|
||||
.filter(mn -> !cf.findModule(mn).isPresent())
|
||||
.forEach(mn -> warnUnknownModule(PATCH_MODULE, mn));
|
||||
}
|
||||
|
||||
// run the resolver to create the configuration
|
||||
Configuration cf = SharedSecrets.getJavaLangModuleAccess()
|
||||
.resolveAndBind(finder,
|
||||
roots,
|
||||
needPostResolutionChecks,
|
||||
traceOutput);
|
||||
|
||||
PerfCounters.resolveTime.addElapsedTimeFrom(t4);
|
||||
Counters.add("jdk.module.boot.4.resolveTime", t4);
|
||||
|
||||
|
||||
// Step 5: Map the modules in the configuration to class loaders.
|
||||
@ -326,7 +359,7 @@ public final class ModuleBootstrap {
|
||||
|
||||
// check that all modules to be mapped to the boot loader will be
|
||||
// loaded from the runtime image
|
||||
if (needPostResolutionChecks) {
|
||||
if (haveModulePath) {
|
||||
for (ResolvedModule resolvedModule : cf.modules()) {
|
||||
ModuleReference mref = resolvedModule.reference();
|
||||
String name = mref.descriptor().name();
|
||||
@ -335,51 +368,54 @@ public final class ModuleBootstrap {
|
||||
if (upgradeModulePath != null
|
||||
&& upgradeModulePath.find(name).isPresent())
|
||||
fail(name + ": cannot be loaded from upgrade module path");
|
||||
if (!systemModules.find(name).isPresent())
|
||||
if (!systemModuleFinder.find(name).isPresent())
|
||||
fail(name + ": cannot be loaded from application module path");
|
||||
}
|
||||
}
|
||||
|
||||
// check if module specified in --patch-module is present
|
||||
for (String mn: patcher.patchedModules()) {
|
||||
if (!cf.findModule(mn).isPresent()) {
|
||||
warnUnknownModule(PATCH_MODULE, mn);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// check for split packages in the modules mapped to the built-in loaders
|
||||
if (SystemModules.hasSplitPackages() || needPostResolutionChecks) {
|
||||
if (systemModules.hasSplitPackages() || isPatched || haveModulePath) {
|
||||
checkSplitPackages(cf, clf);
|
||||
}
|
||||
|
||||
// load/register the modules with the built-in class loaders
|
||||
loadModules(cf, clf);
|
||||
|
||||
PerfCounters.loadModulesTime.addElapsedTimeFrom(t5);
|
||||
Counters.add("jdk.module.boot.5.loadModulesTime", t5);
|
||||
|
||||
|
||||
// Step 6: Define all modules to the VM
|
||||
|
||||
long t6 = System.nanoTime();
|
||||
ModuleLayer bootLayer = ModuleLayer.empty().defineModules(cf, clf);
|
||||
PerfCounters.layerCreateTime.addElapsedTimeFrom(t6);
|
||||
Counters.add("jdk.module.boot.6.layerCreateTime", t6);
|
||||
|
||||
|
||||
// Step 7: Miscellaneous
|
||||
|
||||
// check incubating status
|
||||
checkIncubatingStatus(cf);
|
||||
if (systemModules.hasIncubatorModules() || haveModulePath) {
|
||||
checkIncubatingStatus(cf);
|
||||
}
|
||||
|
||||
// --add-reads, --add-exports/--add-opens, and -illegal-access
|
||||
// --add-reads, --add-exports/--add-opens, and --illegal-access
|
||||
long t7 = System.nanoTime();
|
||||
addExtraReads(bootLayer);
|
||||
boolean extraExportsOrOpens = addExtraExportsAndOpens(bootLayer);
|
||||
addIllegalAccess(bootLayer, upgradeModulePath, extraExportsOrOpens);
|
||||
PerfCounters.adjustModulesTime.addElapsedTimeFrom(t7);
|
||||
addIllegalAccess(upgradeModulePath, systemModules, bootLayer, extraExportsOrOpens);
|
||||
Counters.add("jdk.module.boot.7.adjustModulesTime", t7);
|
||||
|
||||
// save module finders for later use
|
||||
if (savedModuleFinder != null) {
|
||||
unlimitedFinder = new SafeModuleFinder(savedModuleFinder);
|
||||
if (savedModuleFinder != finder)
|
||||
limitedFinder = new SafeModuleFinder(finder);
|
||||
}
|
||||
|
||||
// total time to initialize
|
||||
PerfCounters.bootstrapTime.addElapsedTimeFrom(t1);
|
||||
Counters.add("jdk.module.boot.totalTime", t0);
|
||||
Counters.publish();
|
||||
|
||||
return bootLayer;
|
||||
}
|
||||
@ -391,7 +427,6 @@ public final class ModuleBootstrap {
|
||||
Configuration cf = SharedSecrets.getJavaLangModuleAccess()
|
||||
.resolveAndBind(ModuleFinder.ofSystem(),
|
||||
Set.of(JAVA_BASE),
|
||||
false,
|
||||
null);
|
||||
|
||||
Function<String, ClassLoader> clf = ModuleLoaderMap.mappingFunction(cf);
|
||||
@ -439,7 +474,6 @@ public final class ModuleBootstrap {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -489,7 +523,7 @@ public final class ModuleBootstrap {
|
||||
* Creates a finder from the module path that is the value of the given
|
||||
* system property and optionally patched by --patch-module
|
||||
*/
|
||||
private static ModuleFinder createModulePathFinder(String prop) {
|
||||
private static ModuleFinder finderFor(String prop) {
|
||||
String s = System.getProperty(prop);
|
||||
if (s == null) {
|
||||
return null;
|
||||
@ -510,35 +544,48 @@ public final class ModuleBootstrap {
|
||||
*/
|
||||
private static ModulePatcher initModulePatcher() {
|
||||
Map<String, List<String>> map = decode("jdk.module.patch.",
|
||||
File.pathSeparator,
|
||||
false);
|
||||
File.pathSeparator,
|
||||
false);
|
||||
return new ModulePatcher(map);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the set of module names specified via --add-modules options
|
||||
* on the command line
|
||||
* Returns the set of module names specified by --add-module options.
|
||||
*/
|
||||
private static Set<String> getExtraAddModules() {
|
||||
private static Set<String> addModules() {
|
||||
String prefix = "jdk.module.addmods.";
|
||||
int index = 0;
|
||||
|
||||
// the system property is removed after decoding
|
||||
String value = getAndRemoveProperty(prefix + index);
|
||||
if (value == null) {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
Set<String> modules = new HashSet<>();
|
||||
while (value != null) {
|
||||
for (String s : value.split(",")) {
|
||||
if (s.length() > 0) modules.add(s);
|
||||
} else {
|
||||
Set<String> modules = new HashSet<>();
|
||||
while (value != null) {
|
||||
for (String s : value.split(",")) {
|
||||
if (s.length() > 0) modules.add(s);
|
||||
}
|
||||
index++;
|
||||
value = getAndRemoveProperty(prefix + index);
|
||||
}
|
||||
index++;
|
||||
value = getAndRemoveProperty(prefix + index);
|
||||
return modules;
|
||||
}
|
||||
}
|
||||
|
||||
return modules;
|
||||
/**
|
||||
* Returns the set of module names specified by --limit-modules.
|
||||
*/
|
||||
private static Set<String> limitModules() {
|
||||
String value = getAndRemoveProperty("jdk.module.limitmods");
|
||||
if (value == null) {
|
||||
return Collections.emptySet();
|
||||
} else {
|
||||
Set<String> names = new HashSet<>();
|
||||
for (String name : value.split(",")) {
|
||||
if (name.length() > 0) names.add(name);
|
||||
}
|
||||
return names;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -676,8 +723,9 @@ public final class ModuleBootstrap {
|
||||
* Process the --illegal-access option (and its default) to open packages
|
||||
* of system modules in the boot layer to code in unnamed modules.
|
||||
*/
|
||||
private static void addIllegalAccess(ModuleLayer bootLayer,
|
||||
ModuleFinder upgradeModulePath,
|
||||
private static void addIllegalAccess(ModuleFinder upgradeModulePath,
|
||||
SystemModules systemModules,
|
||||
ModuleLayer bootLayer,
|
||||
boolean extraExportsOrOpens) {
|
||||
String value = getAndRemoveProperty("jdk.module.illegalAccess");
|
||||
IllegalAccessLogger.Mode mode = IllegalAccessLogger.Mode.ONESHOT;
|
||||
@ -702,10 +750,10 @@ public final class ModuleBootstrap {
|
||||
IllegalAccessLogger.Builder builder
|
||||
= new IllegalAccessLogger.Builder(mode, System.err);
|
||||
|
||||
Map<String, Set<String>> map1 = SystemModules.concealedPackagesToOpen();
|
||||
Map<String, Set<String>> map2 = SystemModules.exportedPackagesToOpen();
|
||||
Map<String, Set<String>> map1 = systemModules.concealedPackagesToOpen();
|
||||
Map<String, Set<String>> map2 = systemModules.exportedPackagesToOpen();
|
||||
if (map1.isEmpty() && map2.isEmpty()) {
|
||||
// need to generate maps when on exploded build
|
||||
// need to generate (exploded build)
|
||||
IllegalAccessMaps maps = IllegalAccessMaps.generate(limitedFinder());
|
||||
map1 = maps.concealedPackagesToOpen();
|
||||
map2 = maps.exportedPackagesToOpen();
|
||||
@ -906,6 +954,10 @@ public final class ModuleBootstrap {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an iterator that yields all elements of the first iterator
|
||||
* followed by all the elements of the second iterator.
|
||||
*/
|
||||
static <T> Iterator<T> concat(Iterator<T> iterator1, Iterator<T> iterator2) {
|
||||
return new Iterator<T>() {
|
||||
@Override
|
||||
@ -921,23 +973,76 @@ public final class ModuleBootstrap {
|
||||
};
|
||||
}
|
||||
|
||||
static class PerfCounters {
|
||||
/**
|
||||
* Wraps a (potentially not thread safe) ModuleFinder created during startup
|
||||
* for use after startup.
|
||||
*/
|
||||
static class SafeModuleFinder implements ModuleFinder {
|
||||
private final Set<ModuleReference> mrefs;
|
||||
private volatile Map<String, ModuleReference> nameToModule;
|
||||
|
||||
static PerfCounter systemModulesTime
|
||||
= PerfCounter.newPerfCounter("jdk.module.bootstrap.systemModulesTime");
|
||||
static PerfCounter defineBaseTime
|
||||
= PerfCounter.newPerfCounter("jdk.module.bootstrap.defineBaseTime");
|
||||
static PerfCounter optionsAndRootsTime
|
||||
= PerfCounter.newPerfCounter("jdk.module.bootstrap.optionsAndRootsTime");
|
||||
static PerfCounter resolveTime
|
||||
= PerfCounter.newPerfCounter("jdk.module.bootstrap.resolveTime");
|
||||
static PerfCounter layerCreateTime
|
||||
= PerfCounter.newPerfCounter("jdk.module.bootstrap.layerCreateTime");
|
||||
static PerfCounter loadModulesTime
|
||||
= PerfCounter.newPerfCounter("jdk.module.bootstrap.loadModulesTime");
|
||||
static PerfCounter adjustModulesTime
|
||||
= PerfCounter.newPerfCounter("jdk.module.bootstrap.adjustModulesTime");
|
||||
static PerfCounter bootstrapTime
|
||||
= PerfCounter.newPerfCounter("jdk.module.bootstrap.totalTime");
|
||||
SafeModuleFinder(ModuleFinder finder) {
|
||||
this.mrefs = Collections.unmodifiableSet(finder.findAll());
|
||||
}
|
||||
@Override
|
||||
public Optional<ModuleReference> find(String name) {
|
||||
Objects.requireNonNull(name);
|
||||
Map<String, ModuleReference> nameToModule = this.nameToModule;
|
||||
if (nameToModule == null) {
|
||||
this.nameToModule = nameToModule = mrefs.stream()
|
||||
.collect(Collectors.toMap(m -> m.descriptor().name(),
|
||||
Function.identity()));
|
||||
}
|
||||
return Optional.ofNullable(nameToModule.get(name));
|
||||
}
|
||||
@Override
|
||||
public Set<ModuleReference> findAll() {
|
||||
return mrefs;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Counters for startup performance analysis.
|
||||
*/
|
||||
static class Counters {
|
||||
private static final boolean PUBLISH_COUNTERS;
|
||||
private static final boolean PRINT_COUNTERS;
|
||||
private static Map<String, Long> counters;
|
||||
static {
|
||||
String s = System.getProperty("jdk.module.boot.usePerfData");
|
||||
if (s == null) {
|
||||
PUBLISH_COUNTERS = false;
|
||||
PRINT_COUNTERS = false;
|
||||
} else {
|
||||
PUBLISH_COUNTERS = true;
|
||||
PRINT_COUNTERS = s.equals("debug");
|
||||
counters = new LinkedHashMap<>(); // preserve insert order
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a counter
|
||||
*/
|
||||
static void add(String name, long start) {
|
||||
if (PUBLISH_COUNTERS || PRINT_COUNTERS) {
|
||||
counters.put(name, (System.nanoTime() - start));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Publish the counters to the instrumentation buffer or stdout.
|
||||
*/
|
||||
static void publish() {
|
||||
if (PUBLISH_COUNTERS || PRINT_COUNTERS) {
|
||||
for (Map.Entry<String, Long> e : counters.entrySet()) {
|
||||
String name = e.getKey();
|
||||
long value = e.getValue();
|
||||
if (PUBLISH_COUNTERS)
|
||||
PerfCounter.newPerfCounter(name).set(value);
|
||||
if (PRINT_COUNTERS)
|
||||
System.out.println(name + " = " + value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -200,10 +200,10 @@ public final class ModulePatcher {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true is this module patcher has no patches.
|
||||
* Returns true is this module patcher has patches.
|
||||
*/
|
||||
public boolean isEmpty() {
|
||||
return map.isEmpty();
|
||||
public boolean hasPatches() {
|
||||
return !map.isEmpty();
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -68,14 +68,14 @@ public class ModuleReferenceImpl extends ModuleReference {
|
||||
/**
|
||||
* Constructs a new instance of this class.
|
||||
*/
|
||||
ModuleReferenceImpl(ModuleDescriptor descriptor,
|
||||
URI location,
|
||||
Supplier<ModuleReader> readerSupplier,
|
||||
ModulePatcher patcher,
|
||||
ModuleTarget target,
|
||||
ModuleHashes recordedHashes,
|
||||
ModuleHashes.HashSupplier hasher,
|
||||
ModuleResolution moduleResolution)
|
||||
public ModuleReferenceImpl(ModuleDescriptor descriptor,
|
||||
URI location,
|
||||
Supplier<ModuleReader> readerSupplier,
|
||||
ModulePatcher patcher,
|
||||
ModuleTarget target,
|
||||
ModuleHashes recordedHashes,
|
||||
ModuleHashes.HashSupplier hasher,
|
||||
ModuleResolution moduleResolution)
|
||||
{
|
||||
super(descriptor, Objects.requireNonNull(location));
|
||||
this.location = location;
|
||||
|
@ -1,469 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.internal.module;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.UncheckedIOException;
|
||||
import java.lang.module.ModuleDescriptor;
|
||||
import java.lang.module.ModuleFinder;
|
||||
import java.lang.module.ModuleReader;
|
||||
import java.lang.module.ModuleReference;
|
||||
import java.net.URI;
|
||||
import java.net.URLConnection;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.Collections;
|
||||
import java.util.Deque;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.Spliterator;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Stream;
|
||||
import java.util.stream.StreamSupport;
|
||||
|
||||
import jdk.internal.jimage.ImageLocation;
|
||||
import jdk.internal.jimage.ImageReader;
|
||||
import jdk.internal.jimage.ImageReaderFactory;
|
||||
import jdk.internal.misc.JavaNetUriAccess;
|
||||
import jdk.internal.misc.SharedSecrets;
|
||||
import jdk.internal.module.ModuleHashes.HashSupplier;
|
||||
import jdk.internal.perf.PerfCounter;
|
||||
|
||||
/**
|
||||
* A {@code ModuleFinder} that finds modules that are linked into the
|
||||
* run-time image.
|
||||
*
|
||||
* The modules linked into the run-time image are assumed to have the
|
||||
* Packages attribute.
|
||||
*/
|
||||
|
||||
public class SystemModuleFinder implements ModuleFinder {
|
||||
|
||||
private static final JavaNetUriAccess JNUA = SharedSecrets.getJavaNetUriAccess();
|
||||
|
||||
private static final PerfCounter initTime
|
||||
= PerfCounter.newPerfCounter("jdk.module.finder.jimage.initTime");
|
||||
private static final PerfCounter moduleCount
|
||||
= PerfCounter.newPerfCounter("jdk.module.finder.jimage.modules");
|
||||
private static final PerfCounter packageCount
|
||||
= PerfCounter.newPerfCounter("jdk.module.finder.jimage.packages");
|
||||
private static final PerfCounter exportsCount
|
||||
= PerfCounter.newPerfCounter("jdk.module.finder.jimage.exports");
|
||||
|
||||
// singleton finder to find modules in the run-time images
|
||||
private static final SystemModuleFinder INSTANCE;
|
||||
|
||||
public static SystemModuleFinder getInstance() {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
/**
|
||||
* For now, the module references are created eagerly on the assumption
|
||||
* that service binding will require all modules to be located.
|
||||
*/
|
||||
static {
|
||||
long t0 = System.nanoTime();
|
||||
|
||||
INSTANCE = new SystemModuleFinder();
|
||||
|
||||
initTime.addElapsedTimeFrom(t0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Holder class for the ImageReader
|
||||
*/
|
||||
private static class SystemImage {
|
||||
static final ImageReader READER;
|
||||
static {
|
||||
long t0 = System.nanoTime();
|
||||
READER = ImageReaderFactory.getImageReader();
|
||||
initTime.addElapsedTimeFrom(t0);
|
||||
}
|
||||
|
||||
static ImageReader reader() {
|
||||
return READER;
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isFastPathSupported() {
|
||||
return SystemModules.MODULE_NAMES.length > 0;
|
||||
}
|
||||
|
||||
private static String[] moduleNames() {
|
||||
if (isFastPathSupported())
|
||||
// module names recorded at link time
|
||||
return SystemModules.MODULE_NAMES;
|
||||
|
||||
// this happens when java.base is patched with java.base
|
||||
// from an exploded image
|
||||
return SystemImage.reader().getModuleNames();
|
||||
}
|
||||
|
||||
// the set of modules in the run-time image
|
||||
private final Set<ModuleReference> modules;
|
||||
|
||||
// maps module name to module reference
|
||||
private final Map<String, ModuleReference> nameToModule;
|
||||
|
||||
// module name to hashes
|
||||
private final Map<String, byte[]> hashes;
|
||||
|
||||
private SystemModuleFinder() {
|
||||
String[] names = moduleNames();
|
||||
int n = names.length;
|
||||
moduleCount.add(n);
|
||||
|
||||
// fastpath is enabled by default.
|
||||
// It can be disabled for troubleshooting purpose.
|
||||
boolean disabled =
|
||||
System.getProperty("jdk.system.module.finder.disabledFastPath") != null;
|
||||
|
||||
ModuleDescriptor[] descriptors;
|
||||
ModuleTarget[] targets;
|
||||
ModuleHashes[] recordedHashes;
|
||||
ModuleResolution[] moduleResolutions;
|
||||
|
||||
// fast loading of ModuleDescriptor of system modules
|
||||
if (isFastPathSupported() && !disabled) {
|
||||
descriptors = SystemModules.descriptors();
|
||||
targets = SystemModules.targets();
|
||||
recordedHashes = SystemModules.hashes();
|
||||
moduleResolutions = SystemModules.moduleResolutions();
|
||||
} else {
|
||||
// if fast loading of ModuleDescriptors is disabled
|
||||
// fallback to read module-info.class
|
||||
descriptors = new ModuleDescriptor[n];
|
||||
targets = new ModuleTarget[n];
|
||||
recordedHashes = new ModuleHashes[n];
|
||||
moduleResolutions = new ModuleResolution[n];
|
||||
ImageReader imageReader = SystemImage.reader();
|
||||
for (int i = 0; i < names.length; i++) {
|
||||
String mn = names[i];
|
||||
ImageLocation loc = imageReader.findLocation(mn, "module-info.class");
|
||||
ModuleInfo.Attributes attrs =
|
||||
ModuleInfo.read(imageReader.getResourceBuffer(loc), null);
|
||||
descriptors[i] = attrs.descriptor();
|
||||
targets[i] = attrs.target();
|
||||
recordedHashes[i] = attrs.recordedHashes();
|
||||
moduleResolutions[i] = attrs.moduleResolution();
|
||||
}
|
||||
}
|
||||
|
||||
Map<String, byte[]> hashes = null;
|
||||
boolean secondSeen = false;
|
||||
// record the hashes to build HashSupplier
|
||||
for (ModuleHashes mh : recordedHashes) {
|
||||
if (mh != null) {
|
||||
// if only one module contain ModuleHashes, use it
|
||||
if (hashes == null) {
|
||||
hashes = mh.hashes();
|
||||
} else {
|
||||
if (!secondSeen) {
|
||||
hashes = new HashMap<>(hashes);
|
||||
secondSeen = true;
|
||||
}
|
||||
hashes.putAll(mh.hashes());
|
||||
}
|
||||
}
|
||||
}
|
||||
this.hashes = (hashes == null) ? Map.of() : hashes;
|
||||
|
||||
ModuleReference[] mods = new ModuleReference[n];
|
||||
|
||||
@SuppressWarnings(value = {"rawtypes", "unchecked"})
|
||||
Entry<String, ModuleReference>[] map
|
||||
= (Entry<String, ModuleReference>[])new Entry[n];
|
||||
|
||||
for (int i = 0; i < n; i++) {
|
||||
ModuleDescriptor md = descriptors[i];
|
||||
|
||||
// create the ModuleReference
|
||||
ModuleReference mref = toModuleReference(md,
|
||||
targets[i],
|
||||
recordedHashes[i],
|
||||
hashSupplier(names[i]),
|
||||
moduleResolutions[i]);
|
||||
mods[i] = mref;
|
||||
map[i] = Map.entry(names[i], mref);
|
||||
|
||||
// counters
|
||||
packageCount.add(md.packages().size());
|
||||
exportsCount.add(md.exports().size());
|
||||
}
|
||||
|
||||
modules = Set.of(mods);
|
||||
nameToModule = Map.ofEntries(map);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<ModuleReference> find(String name) {
|
||||
Objects.requireNonNull(name);
|
||||
return Optional.ofNullable(nameToModule.get(name));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<ModuleReference> findAll() {
|
||||
return modules;
|
||||
}
|
||||
|
||||
private ModuleReference toModuleReference(ModuleDescriptor md,
|
||||
ModuleTarget target,
|
||||
ModuleHashes recordedHashes,
|
||||
HashSupplier hasher,
|
||||
ModuleResolution mres) {
|
||||
String mn = md.name();
|
||||
URI uri = JNUA.create("jrt", "/".concat(mn));
|
||||
|
||||
Supplier<ModuleReader> readerSupplier = new Supplier<>() {
|
||||
@Override
|
||||
public ModuleReader get() {
|
||||
return new ImageModuleReader(mn, uri);
|
||||
}
|
||||
};
|
||||
|
||||
ModuleReference mref = new ModuleReferenceImpl(md,
|
||||
uri,
|
||||
readerSupplier,
|
||||
null,
|
||||
target,
|
||||
recordedHashes,
|
||||
hasher,
|
||||
mres);
|
||||
|
||||
// may need a reference to a patched module if --patch-module specified
|
||||
mref = ModuleBootstrap.patcher().patchIfNeeded(mref);
|
||||
|
||||
return mref;
|
||||
}
|
||||
|
||||
private HashSupplier hashSupplier(String name) {
|
||||
if (!hashes.containsKey(name))
|
||||
return null;
|
||||
|
||||
return new HashSupplier() {
|
||||
@Override
|
||||
public byte[] generate(String algorithm) {
|
||||
return hashes.get(name);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* A ModuleReader for reading resources from a module linked into the
|
||||
* run-time image.
|
||||
*/
|
||||
static class ImageModuleReader implements ModuleReader {
|
||||
private final String module;
|
||||
private volatile boolean closed;
|
||||
|
||||
/**
|
||||
* If there is a security manager set then check permission to
|
||||
* connect to the run-time image.
|
||||
*/
|
||||
private static void checkPermissionToConnect(URI uri) {
|
||||
SecurityManager sm = System.getSecurityManager();
|
||||
if (sm != null) {
|
||||
try {
|
||||
URLConnection uc = uri.toURL().openConnection();
|
||||
sm.checkPermission(uc.getPermission());
|
||||
} catch (IOException ioe) {
|
||||
throw new UncheckedIOException(ioe);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ImageModuleReader(String module, URI uri) {
|
||||
checkPermissionToConnect(uri);
|
||||
this.module = module;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the ImageLocation for the given resource, {@code null}
|
||||
* if not found.
|
||||
*/
|
||||
private ImageLocation findImageLocation(String name) throws IOException {
|
||||
Objects.requireNonNull(name);
|
||||
if (closed)
|
||||
throw new IOException("ModuleReader is closed");
|
||||
ImageReader imageReader = SystemImage.reader();
|
||||
if (imageReader != null) {
|
||||
return imageReader.findLocation(module, name);
|
||||
} else {
|
||||
// not an images build
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<URI> find(String name) throws IOException {
|
||||
ImageLocation location = findImageLocation(name);
|
||||
if (location != null) {
|
||||
URI u = URI.create("jrt:/" + module + "/" + name);
|
||||
return Optional.of(u);
|
||||
} else {
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<InputStream> open(String name) throws IOException {
|
||||
return read(name).map(this::toInputStream);
|
||||
}
|
||||
|
||||
private InputStream toInputStream(ByteBuffer bb) { // ## -> ByteBuffer?
|
||||
try {
|
||||
int rem = bb.remaining();
|
||||
byte[] bytes = new byte[rem];
|
||||
bb.get(bytes);
|
||||
return new ByteArrayInputStream(bytes);
|
||||
} finally {
|
||||
release(bb);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<ByteBuffer> read(String name) throws IOException {
|
||||
ImageLocation location = findImageLocation(name);
|
||||
if (location != null) {
|
||||
return Optional.of(SystemImage.reader().getResourceBuffer(location));
|
||||
} else {
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void release(ByteBuffer bb) {
|
||||
Objects.requireNonNull(bb);
|
||||
ImageReader.releaseByteBuffer(bb);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Stream<String> list() throws IOException {
|
||||
if (closed)
|
||||
throw new IOException("ModuleReader is closed");
|
||||
|
||||
Spliterator<String> s = new ModuleContentSpliterator(module);
|
||||
return StreamSupport.stream(s, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
// nothing else to do
|
||||
closed = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A Spliterator for traversing the resources of a module linked into the
|
||||
* run-time image.
|
||||
*/
|
||||
static class ModuleContentSpliterator implements Spliterator<String> {
|
||||
final String moduleRoot;
|
||||
final Deque<ImageReader.Node> stack;
|
||||
Iterator<ImageReader.Node> iterator;
|
||||
|
||||
ModuleContentSpliterator(String module) throws IOException {
|
||||
moduleRoot = "/modules/" + module;
|
||||
stack = new ArrayDeque<>();
|
||||
|
||||
// push the root node to the stack to get started
|
||||
ImageReader.Node dir = SystemImage.reader().findNode(moduleRoot);
|
||||
if (dir == null || !dir.isDirectory())
|
||||
throw new IOException(moduleRoot + " not a directory");
|
||||
stack.push(dir);
|
||||
iterator = Collections.emptyIterator();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the next non-directory node or {@code null} if
|
||||
* there are no remaining nodes to visit.
|
||||
*/
|
||||
private String next() throws IOException {
|
||||
for (;;) {
|
||||
while (iterator.hasNext()) {
|
||||
ImageReader.Node node = iterator.next();
|
||||
String name = node.getName();
|
||||
if (node.isDirectory()) {
|
||||
// build node
|
||||
ImageReader.Node dir = SystemImage.reader().findNode(name);
|
||||
assert dir.isDirectory();
|
||||
stack.push(dir);
|
||||
} else {
|
||||
// strip /modules/$MODULE/ prefix
|
||||
return name.substring(moduleRoot.length() + 1);
|
||||
}
|
||||
}
|
||||
|
||||
if (stack.isEmpty()) {
|
||||
return null;
|
||||
} else {
|
||||
ImageReader.Node dir = stack.poll();
|
||||
assert dir.isDirectory();
|
||||
iterator = dir.getChildren().iterator();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean tryAdvance(Consumer<? super String> action) {
|
||||
String next;
|
||||
try {
|
||||
next = next();
|
||||
} catch (IOException ioe) {
|
||||
throw new UncheckedIOException(ioe);
|
||||
}
|
||||
if (next != null) {
|
||||
action.accept(next);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Spliterator<String> trySplit() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int characteristics() {
|
||||
return Spliterator.DISTINCT + Spliterator.NONNULL + Spliterator.IMMUTABLE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long estimateSize() {
|
||||
return Long.MAX_VALUE;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,576 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package jdk.internal.module;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.UncheckedIOException;
|
||||
import java.lang.module.ModuleDescriptor;
|
||||
import java.lang.module.ModuleFinder;
|
||||
import java.lang.module.ModuleReader;
|
||||
import java.lang.module.ModuleReference;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.net.URI;
|
||||
import java.net.URLConnection;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.Collections;
|
||||
import java.util.Deque;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.Spliterator;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Stream;
|
||||
import java.util.stream.StreamSupport;
|
||||
|
||||
import jdk.internal.jimage.ImageLocation;
|
||||
import jdk.internal.jimage.ImageReader;
|
||||
import jdk.internal.jimage.ImageReaderFactory;
|
||||
import jdk.internal.misc.JavaNetUriAccess;
|
||||
import jdk.internal.misc.SharedSecrets;
|
||||
import jdk.internal.module.ModuleHashes.HashSupplier;
|
||||
|
||||
/**
|
||||
* The factory for SystemModules objects and for creating ModuleFinder objects
|
||||
* that find modules in the runtime image.
|
||||
*
|
||||
* This class supports initializing the module system when the runtime is an
|
||||
* images build, an exploded build, or an images build with java.base patched
|
||||
* by an exploded java.base. It also supports a testing mode that re-parses
|
||||
* the module-info.class resources in the run-time image.
|
||||
*/
|
||||
|
||||
public final class SystemModuleFinders {
|
||||
private static final JavaNetUriAccess JNUA = SharedSecrets.getJavaNetUriAccess();
|
||||
|
||||
private static final boolean USE_FAST_PATH;
|
||||
static {
|
||||
String value = System.getProperty("jdk.system.module.finder.disableFastPath");
|
||||
if (value == null) {
|
||||
USE_FAST_PATH = true;
|
||||
} else {
|
||||
USE_FAST_PATH = (value.length() > 0) && !Boolean.parseBoolean(value);
|
||||
}
|
||||
}
|
||||
|
||||
// cached ModuleFinder returned from ofSystem
|
||||
private static volatile ModuleFinder cachedSystemModuleFinder;
|
||||
|
||||
private SystemModuleFinders() { }
|
||||
|
||||
/**
|
||||
* Returns the SystemModules object to reconstitute all modules. Returns
|
||||
* null if this is an exploded build or java.base is patched by an exploded
|
||||
* build.
|
||||
*/
|
||||
static SystemModules allSystemModules() {
|
||||
if (USE_FAST_PATH) {
|
||||
return SystemModulesMap.allSystemModules();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a SystemModules object to reconstitute the modules for the
|
||||
* given initial module. If the initial module is null then return the
|
||||
* SystemModules object to reconstitute the default modules.
|
||||
*
|
||||
* Return null if there is no SystemModules class for the initial module,
|
||||
* this is an exploded build, or java.base is patched by an exploded build.
|
||||
*/
|
||||
static SystemModules systemModules(String initialModule) {
|
||||
if (USE_FAST_PATH) {
|
||||
if (initialModule == null) {
|
||||
return SystemModulesMap.defaultSystemModules();
|
||||
}
|
||||
|
||||
String[] initialModules = SystemModulesMap.moduleNames();
|
||||
for (int i = 0; i < initialModules.length; i++) {
|
||||
String moduleName = initialModules[i];
|
||||
if (initialModule.equals(moduleName)) {
|
||||
String cn = SystemModulesMap.classNames()[i];
|
||||
try {
|
||||
// one-arg Class.forName as java.base may not be defined
|
||||
Constructor<?> ctor = Class.forName(cn).getConstructor();
|
||||
return (SystemModules) ctor.newInstance();
|
||||
} catch (Exception e) {
|
||||
throw new InternalError(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a ModuleFinder that is backed by the given SystemModules object.
|
||||
*
|
||||
* @apiNote The returned ModuleFinder is thread safe.
|
||||
*/
|
||||
static ModuleFinder of(SystemModules systemModules) {
|
||||
ModuleDescriptor[] descriptors = systemModules.moduleDescriptors();
|
||||
ModuleTarget[] targets = systemModules.moduleTargets();
|
||||
ModuleHashes[] recordedHashes = systemModules.moduleHashes();
|
||||
ModuleResolution[] moduleResolutions = systemModules.moduleResolutions();
|
||||
|
||||
int moduleCount = descriptors.length;
|
||||
ModuleReference[] mrefs = new ModuleReference[moduleCount];
|
||||
@SuppressWarnings(value = {"rawtypes", "unchecked"})
|
||||
Map.Entry<String, ModuleReference>[] map
|
||||
= (Map.Entry<String, ModuleReference>[])new Map.Entry[moduleCount];
|
||||
|
||||
Map<String, byte[]> nameToHash = generateNameToHash(recordedHashes);
|
||||
|
||||
for (int i = 0; i < moduleCount; i++) {
|
||||
String name = descriptors[i].name();
|
||||
HashSupplier hashSupplier = hashSupplier(nameToHash, name);
|
||||
ModuleReference mref = toModuleReference(descriptors[i],
|
||||
targets[i],
|
||||
recordedHashes[i],
|
||||
hashSupplier,
|
||||
moduleResolutions[i]);
|
||||
mrefs[i] = mref;
|
||||
map[i] = Map.entry(name, mref);
|
||||
}
|
||||
|
||||
return new SystemModuleFinder(mrefs, map);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the ModuleFinder to find all system modules. Supports both
|
||||
* images and exploded builds.
|
||||
*
|
||||
* @apiNote Used by ModuleFinder.ofSystem()
|
||||
*/
|
||||
public static ModuleFinder ofSystem() {
|
||||
ModuleFinder finder = cachedSystemModuleFinder;
|
||||
if (finder != null) {
|
||||
return finder;
|
||||
}
|
||||
|
||||
// probe to see if this is an images build
|
||||
String home = System.getProperty("java.home");
|
||||
Path modules = Paths.get(home, "lib", "modules");
|
||||
if (Files.isRegularFile(modules)) {
|
||||
if (USE_FAST_PATH) {
|
||||
SystemModules systemModules = allSystemModules();
|
||||
if (systemModules != null) {
|
||||
finder = of(systemModules);
|
||||
}
|
||||
}
|
||||
|
||||
// fall back to parsing the module-info.class files in image
|
||||
if (finder == null) {
|
||||
finder = ofModuleInfos();
|
||||
}
|
||||
|
||||
cachedSystemModuleFinder = finder;
|
||||
return finder;
|
||||
|
||||
}
|
||||
|
||||
// exploded build (do not cache module finder)
|
||||
Path dir = Paths.get(home, "modules");
|
||||
if (!Files.isDirectory(dir))
|
||||
throw new InternalError("Unable to detect the run-time image");
|
||||
ModuleFinder f = ModulePath.of(ModuleBootstrap.patcher(), dir);
|
||||
return new ModuleFinder() {
|
||||
@Override
|
||||
public Optional<ModuleReference> find(String name) {
|
||||
PrivilegedAction<Optional<ModuleReference>> pa = () -> f.find(name);
|
||||
return AccessController.doPrivileged(pa);
|
||||
}
|
||||
@Override
|
||||
public Set<ModuleReference> findAll() {
|
||||
PrivilegedAction<Set<ModuleReference>> pa = f::findAll;
|
||||
return AccessController.doPrivileged(pa);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the module-info.class of all module in the runtime image and
|
||||
* returns a ModuleFinder to find the modules.
|
||||
*
|
||||
* @apiNote The returned ModuleFinder is thread safe.
|
||||
*/
|
||||
private static ModuleFinder ofModuleInfos() {
|
||||
// parse the module-info.class in every module
|
||||
Map<String, ModuleInfo.Attributes> nameToAttributes = new HashMap<>();
|
||||
Map<String, byte[]> nameToHash = new HashMap<>();
|
||||
ImageReader reader = SystemImage.reader();
|
||||
for (String mn : reader.getModuleNames()) {
|
||||
ImageLocation loc = reader.findLocation(mn, "module-info.class");
|
||||
ModuleInfo.Attributes attrs
|
||||
= ModuleInfo.read(reader.getResourceBuffer(loc), null);
|
||||
|
||||
nameToAttributes.put(mn, attrs);
|
||||
ModuleHashes hashes = attrs.recordedHashes();
|
||||
if (hashes != null) {
|
||||
for (String name : hashes.names()) {
|
||||
nameToHash.computeIfAbsent(name, k -> hashes.hashFor(name));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// create a ModuleReference for each module
|
||||
Set<ModuleReference> mrefs = new HashSet<>();
|
||||
Map<String, ModuleReference> nameToModule = new HashMap<>();
|
||||
for (Map.Entry<String, ModuleInfo.Attributes> e : nameToAttributes.entrySet()) {
|
||||
String mn = e.getKey();
|
||||
ModuleInfo.Attributes attrs = e.getValue();
|
||||
HashSupplier hashSupplier = hashSupplier(nameToHash, mn);
|
||||
ModuleReference mref = toModuleReference(attrs.descriptor(),
|
||||
attrs.target(),
|
||||
attrs.recordedHashes(),
|
||||
hashSupplier,
|
||||
attrs.moduleResolution());
|
||||
mrefs.add(mref);
|
||||
nameToModule.put(mn, mref);
|
||||
}
|
||||
|
||||
return new SystemModuleFinder(mrefs, nameToModule);
|
||||
}
|
||||
|
||||
/**
|
||||
* A ModuleFinder that finds module in an array or set of modules.
|
||||
*/
|
||||
private static class SystemModuleFinder implements ModuleFinder {
|
||||
final Set<ModuleReference> mrefs;
|
||||
final Map<String, ModuleReference> nameToModule;
|
||||
|
||||
SystemModuleFinder(ModuleReference[] array,
|
||||
Map.Entry<String, ModuleReference>[] map) {
|
||||
this.mrefs = Set.of(array);
|
||||
this.nameToModule = Map.ofEntries(map);
|
||||
}
|
||||
|
||||
SystemModuleFinder(Set<ModuleReference> mrefs,
|
||||
Map<String, ModuleReference> nameToModule) {
|
||||
this.mrefs = Collections.unmodifiableSet(mrefs);
|
||||
this.nameToModule = Collections.unmodifiableMap(nameToModule);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<ModuleReference> find(String name) {
|
||||
Objects.requireNonNull(name);
|
||||
return Optional.ofNullable(nameToModule.get(name));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<ModuleReference> findAll() {
|
||||
return mrefs;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a ModuleReference to the system module.
|
||||
*/
|
||||
static ModuleReference toModuleReference(ModuleDescriptor descriptor,
|
||||
ModuleTarget target,
|
||||
ModuleHashes recordedHashes,
|
||||
HashSupplier hasher,
|
||||
ModuleResolution mres) {
|
||||
String mn = descriptor.name();
|
||||
URI uri = JNUA.create("jrt", "/".concat(mn));
|
||||
|
||||
Supplier<ModuleReader> readerSupplier = new Supplier<>() {
|
||||
@Override
|
||||
public ModuleReader get() {
|
||||
return new SystemModuleReader(mn, uri);
|
||||
}
|
||||
};
|
||||
|
||||
ModuleReference mref = new ModuleReferenceImpl(descriptor,
|
||||
uri,
|
||||
readerSupplier,
|
||||
null,
|
||||
target,
|
||||
recordedHashes,
|
||||
hasher,
|
||||
mres);
|
||||
|
||||
// may need a reference to a patched module if --patch-module specified
|
||||
mref = ModuleBootstrap.patcher().patchIfNeeded(mref);
|
||||
|
||||
return mref;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a map of module name to hash value.
|
||||
*/
|
||||
static Map<String, byte[]> generateNameToHash(ModuleHashes[] recordedHashes) {
|
||||
Map<String, byte[]> nameToHash = null;
|
||||
|
||||
boolean secondSeen = false;
|
||||
// record the hashes to build HashSupplier
|
||||
for (ModuleHashes mh : recordedHashes) {
|
||||
if (mh != null) {
|
||||
// if only one module contain ModuleHashes, use it
|
||||
if (nameToHash == null) {
|
||||
nameToHash = mh.hashes();
|
||||
} else {
|
||||
if (!secondSeen) {
|
||||
nameToHash = new HashMap<>(nameToHash);
|
||||
secondSeen = true;
|
||||
}
|
||||
nameToHash.putAll(mh.hashes());
|
||||
}
|
||||
}
|
||||
}
|
||||
return (nameToHash != null) ? nameToHash : Collections.emptyMap();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a HashSupplier that returns the hash of the given module.
|
||||
*/
|
||||
static HashSupplier hashSupplier(Map<String, byte[]> nameToHash, String name) {
|
||||
byte[] hash = nameToHash.get(name);
|
||||
if (hash != null) {
|
||||
// avoid lambda here
|
||||
return new HashSupplier() {
|
||||
@Override
|
||||
public byte[] generate(String algorithm) {
|
||||
return hash;
|
||||
}
|
||||
};
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Holder class for the ImageReader
|
||||
*
|
||||
* @apiNote This class must be loaded before a security manager is set.
|
||||
*/
|
||||
private static class SystemImage {
|
||||
static final ImageReader READER = ImageReaderFactory.getImageReader();
|
||||
static ImageReader reader() {
|
||||
return READER;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A ModuleReader for reading resources from a module linked into the
|
||||
* run-time image.
|
||||
*/
|
||||
private static class SystemModuleReader implements ModuleReader {
|
||||
private final String module;
|
||||
private volatile boolean closed;
|
||||
|
||||
/**
|
||||
* If there is a security manager set then check permission to
|
||||
* connect to the run-time image.
|
||||
*/
|
||||
private static void checkPermissionToConnect(URI uri) {
|
||||
SecurityManager sm = System.getSecurityManager();
|
||||
if (sm != null) {
|
||||
try {
|
||||
URLConnection uc = uri.toURL().openConnection();
|
||||
sm.checkPermission(uc.getPermission());
|
||||
} catch (IOException ioe) {
|
||||
throw new UncheckedIOException(ioe);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SystemModuleReader(String module, URI uri) {
|
||||
checkPermissionToConnect(uri);
|
||||
this.module = module;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the ImageLocation for the given resource, {@code null}
|
||||
* if not found.
|
||||
*/
|
||||
private ImageLocation findImageLocation(String name) throws IOException {
|
||||
Objects.requireNonNull(name);
|
||||
if (closed)
|
||||
throw new IOException("ModuleReader is closed");
|
||||
ImageReader imageReader = SystemImage.reader();
|
||||
if (imageReader != null) {
|
||||
return imageReader.findLocation(module, name);
|
||||
} else {
|
||||
// not an images build
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<URI> find(String name) throws IOException {
|
||||
ImageLocation location = findImageLocation(name);
|
||||
if (location != null) {
|
||||
URI u = URI.create("jrt:/" + module + "/" + name);
|
||||
return Optional.of(u);
|
||||
} else {
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<InputStream> open(String name) throws IOException {
|
||||
return read(name).map(this::toInputStream);
|
||||
}
|
||||
|
||||
private InputStream toInputStream(ByteBuffer bb) { // ## -> ByteBuffer?
|
||||
try {
|
||||
int rem = bb.remaining();
|
||||
byte[] bytes = new byte[rem];
|
||||
bb.get(bytes);
|
||||
return new ByteArrayInputStream(bytes);
|
||||
} finally {
|
||||
release(bb);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<ByteBuffer> read(String name) throws IOException {
|
||||
ImageLocation location = findImageLocation(name);
|
||||
if (location != null) {
|
||||
return Optional.of(SystemImage.reader().getResourceBuffer(location));
|
||||
} else {
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void release(ByteBuffer bb) {
|
||||
Objects.requireNonNull(bb);
|
||||
ImageReader.releaseByteBuffer(bb);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Stream<String> list() throws IOException {
|
||||
if (closed)
|
||||
throw new IOException("ModuleReader is closed");
|
||||
|
||||
Spliterator<String> s = new ModuleContentSpliterator(module);
|
||||
return StreamSupport.stream(s, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
// nothing else to do
|
||||
closed = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A Spliterator for traversing the resources of a module linked into the
|
||||
* run-time image.
|
||||
*/
|
||||
private static class ModuleContentSpliterator implements Spliterator<String> {
|
||||
final String moduleRoot;
|
||||
final Deque<ImageReader.Node> stack;
|
||||
Iterator<ImageReader.Node> iterator;
|
||||
|
||||
ModuleContentSpliterator(String module) throws IOException {
|
||||
moduleRoot = "/modules/" + module;
|
||||
stack = new ArrayDeque<>();
|
||||
|
||||
// push the root node to the stack to get started
|
||||
ImageReader.Node dir = SystemImage.reader().findNode(moduleRoot);
|
||||
if (dir == null || !dir.isDirectory())
|
||||
throw new IOException(moduleRoot + " not a directory");
|
||||
stack.push(dir);
|
||||
iterator = Collections.emptyIterator();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the next non-directory node or {@code null} if
|
||||
* there are no remaining nodes to visit.
|
||||
*/
|
||||
private String next() throws IOException {
|
||||
for (;;) {
|
||||
while (iterator.hasNext()) {
|
||||
ImageReader.Node node = iterator.next();
|
||||
String name = node.getName();
|
||||
if (node.isDirectory()) {
|
||||
// build node
|
||||
ImageReader.Node dir = SystemImage.reader().findNode(name);
|
||||
assert dir.isDirectory();
|
||||
stack.push(dir);
|
||||
} else {
|
||||
// strip /modules/$MODULE/ prefix
|
||||
return name.substring(moduleRoot.length() + 1);
|
||||
}
|
||||
}
|
||||
|
||||
if (stack.isEmpty()) {
|
||||
return null;
|
||||
} else {
|
||||
ImageReader.Node dir = stack.poll();
|
||||
assert dir.isDirectory();
|
||||
iterator = dir.getChildren().iterator();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean tryAdvance(Consumer<? super String> action) {
|
||||
String next;
|
||||
try {
|
||||
next = next();
|
||||
} catch (IOException ioe) {
|
||||
throw new UncheckedIOException(ioe);
|
||||
}
|
||||
if (next != null) {
|
||||
action.accept(next);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Spliterator<String> trySplit() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int characteristics() {
|
||||
return Spliterator.DISTINCT + Spliterator.NONNULL + Spliterator.IMMUTABLE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long estimateSize() {
|
||||
return Long.MAX_VALUE;
|
||||
}
|
||||
}
|
||||
}
|
@ -26,94 +26,73 @@
|
||||
package jdk.internal.module;
|
||||
|
||||
import java.lang.module.ModuleDescriptor;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* SystemModules class will be generated at link time to create
|
||||
* ModuleDescriptor for the system modules directly to improve
|
||||
* the module descriptor reconstitution time.
|
||||
*
|
||||
* This will skip parsing of module-info.class file and validating
|
||||
* names such as module name, package name, service and provider type names.
|
||||
* It also avoids taking a defensive copy of any collection.
|
||||
* A SystemModules object reconstitutes module descriptors and other modules
|
||||
* attributes in an efficient way to avoid parsing module-info.class files at
|
||||
* startup. Implementations of this class are generated by the "system modules"
|
||||
* jlink plugin.
|
||||
*
|
||||
* @see SystemModuleFinders
|
||||
* @see jdk.tools.jlink.internal.plugins.SystemModulesPlugin
|
||||
*/
|
||||
public final class SystemModules {
|
||||
/**
|
||||
* Name of the system modules.
|
||||
*
|
||||
* This array provides a way for SystemModuleFinder to fallback
|
||||
* and read module-info.class from the run-time image instead of
|
||||
* the fastpath.
|
||||
*/
|
||||
public static final String[] MODULE_NAMES = new String[0];
|
||||
|
||||
interface SystemModules {
|
||||
|
||||
/**
|
||||
* Number of packages in the boot layer from the installed modules.
|
||||
*
|
||||
* Don't make it final to avoid inlining during compile time as
|
||||
* the value will be changed at jlink time.
|
||||
* Returns false if the module reconstituted by this SystemModules object
|
||||
* have no overlapping packages. Returns true if there are overlapping
|
||||
* packages or unknown.
|
||||
*/
|
||||
public static int PACKAGES_IN_BOOT_LAYER = 1024;
|
||||
boolean hasSplitPackages();
|
||||
|
||||
/**
|
||||
* Return true if there are no split packages in the run-time image.
|
||||
* Return false if the modules reconstituted by this SystemModules object
|
||||
* do not include any incubator modules. Returns true if there are
|
||||
* incubating modules or unknown.
|
||||
*/
|
||||
public static boolean hasSplitPackages() {
|
||||
return true;
|
||||
}
|
||||
boolean hasIncubatorModules();
|
||||
|
||||
/**
|
||||
* Returns a non-empty array of ModuleDescriptor objects in the run-time image.
|
||||
*
|
||||
* When running an exploded image it returns an empty array.
|
||||
* Returns the non-empty array of ModuleDescriptor objects.
|
||||
*/
|
||||
public static ModuleDescriptor[] descriptors() {
|
||||
throw new InternalError("expected to be overridden at link time");
|
||||
}
|
||||
ModuleDescriptor[] moduleDescriptors();
|
||||
|
||||
/**
|
||||
* Returns a non-empty array of ModuleTarget objects in the run-time image.
|
||||
*
|
||||
* When running an exploded image it returns an empty array.
|
||||
* Returns the array of ModuleTarget objects. The array elements correspond
|
||||
* to the array of ModuleDescriptor objects.
|
||||
*/
|
||||
public static ModuleTarget[] targets() {
|
||||
throw new InternalError("expected to be overridden at link time");
|
||||
}
|
||||
ModuleTarget[] moduleTargets();
|
||||
|
||||
/**
|
||||
* Returns a non-empty array of ModuleHashes recorded in each module
|
||||
* in the run-time image.
|
||||
*
|
||||
* When running an exploded image it returns an empty array.
|
||||
* Returns the array of ModuleHashes objects. The array elements correspond
|
||||
* to the array of ModuleDescriptor objects.
|
||||
*/
|
||||
public static ModuleHashes[] hashes() {
|
||||
throw new InternalError("expected to be overridden at link time");
|
||||
}
|
||||
ModuleHashes[] moduleHashes();
|
||||
|
||||
/**
|
||||
* Returns a non-empty array of ModuleResolutions in the run-time image.
|
||||
* Returns the array of ModuleResolution objects. The array elements correspond
|
||||
* to the array of ModuleDescriptor objects.
|
||||
*/
|
||||
public static ModuleResolution[] moduleResolutions() {
|
||||
throw new InternalError("expected to be overridden at link time");
|
||||
}
|
||||
ModuleResolution[] moduleResolutions();
|
||||
|
||||
/**
|
||||
* Returns the map representing readability graph for the modules reconstituted
|
||||
* by this SystemModules object.
|
||||
*/
|
||||
Map<String, Set<String>> moduleReads();
|
||||
|
||||
/**
|
||||
* Returns the map of module concealed packages to open. The map key is the
|
||||
* module name, the value is the set of concealed packages to open.
|
||||
*/
|
||||
public static Map<String, Set<String>> concealedPackagesToOpen() {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
Map<String, Set<String>> concealedPackagesToOpen();
|
||||
|
||||
/**
|
||||
* Returns the map of module exported packages to open. The map key is the
|
||||
* module name, the value is the set of exported packages to open.
|
||||
*/
|
||||
public static Map<String, Set<String>> exportedPackagesToOpen() {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
Map<String, Set<String>> exportedPackagesToOpen();
|
||||
}
|
||||
|
@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.internal.module;
|
||||
|
||||
/**
|
||||
* This class is generated/overridden at link time to return the names of the
|
||||
* SystemModules classes generated at link time.
|
||||
*
|
||||
* @see SystemModuleFinders
|
||||
* @see jdk.tools.jlink.internal.plugins.SystemModulesPlugin
|
||||
*/
|
||||
|
||||
class SystemModulesMap {
|
||||
|
||||
/**
|
||||
* Returns the SystemModules object to reconstitute all modules or null
|
||||
* if this is an exploded build.
|
||||
*/
|
||||
static SystemModules allSystemModules() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the SystemModules object to reconstitute default modules or null
|
||||
* if this is an exploded build.
|
||||
*/
|
||||
static SystemModules defaultSystemModules() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the array of initial module names identified at link time.
|
||||
*/
|
||||
static String[] moduleNames() {
|
||||
return new String[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the array of of SystemModules class names. The elements
|
||||
* correspond to the elements in the array returned by moduleNames().
|
||||
*/
|
||||
static String[] classNames() {
|
||||
return new String[0];
|
||||
}
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -26,10 +26,18 @@
|
||||
package sun.nio.ch;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.channels.*;
|
||||
import java.nio.channels.spi.*;
|
||||
import java.net.SocketException;
|
||||
import java.util.*;
|
||||
import java.nio.channels.ClosedSelectorException;
|
||||
import java.nio.channels.IllegalSelectorException;
|
||||
import java.nio.channels.SelectionKey;
|
||||
import java.nio.channels.Selector;
|
||||
import java.nio.channels.spi.AbstractSelectableChannel;
|
||||
import java.nio.channels.spi.AbstractSelector;
|
||||
import java.nio.channels.spi.SelectorProvider;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.Set;
|
||||
|
||||
|
||||
/**
|
||||
@ -54,23 +62,18 @@ public abstract class SelectorImpl
|
||||
super(sp);
|
||||
keys = new HashSet<>();
|
||||
selectedKeys = new HashSet<>();
|
||||
if (Util.atBugLevel("1.4")) {
|
||||
publicKeys = keys;
|
||||
publicSelectedKeys = selectedKeys;
|
||||
} else {
|
||||
publicKeys = Collections.unmodifiableSet(keys);
|
||||
publicSelectedKeys = Util.ungrowableSet(selectedKeys);
|
||||
}
|
||||
publicKeys = Collections.unmodifiableSet(keys);
|
||||
publicSelectedKeys = Util.ungrowableSet(selectedKeys);
|
||||
}
|
||||
|
||||
public Set<SelectionKey> keys() {
|
||||
if (!isOpen() && !Util.atBugLevel("1.4"))
|
||||
if (!isOpen())
|
||||
throw new ClosedSelectorException();
|
||||
return publicKeys;
|
||||
}
|
||||
|
||||
public Set<SelectionKey> selectedKeys() {
|
||||
if (!isOpen() && !Util.atBugLevel("1.4"))
|
||||
if (!isOpen())
|
||||
throw new ClosedSelectorException();
|
||||
return publicSelectedKeys;
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -25,13 +25,16 @@
|
||||
|
||||
package sun.nio.ch;
|
||||
|
||||
import java.lang.reflect.*;
|
||||
import java.io.FileDescriptor;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.MappedByteBuffer;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.util.*;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.Set;
|
||||
import jdk.internal.misc.Unsafe;
|
||||
import sun.security.action.GetPropertyAction;
|
||||
|
||||
@ -456,21 +459,4 @@ public class Util {
|
||||
}
|
||||
return dbb;
|
||||
}
|
||||
|
||||
|
||||
// -- Bug compatibility --
|
||||
|
||||
private static volatile String bugLevel;
|
||||
|
||||
static boolean atBugLevel(String bl) { // package-private
|
||||
if (bugLevel == null) {
|
||||
if (!jdk.internal.misc.VM.isBooted())
|
||||
return false;
|
||||
String value = GetPropertyAction
|
||||
.privilegedGetProperty("sun.nio.ch.bugLevel");
|
||||
bugLevel = (value != null) ? value : "";
|
||||
}
|
||||
return bugLevel.equals(bl);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -35,6 +35,7 @@ import java.security.SecureRandom;
|
||||
import java.security.UnrecoverableKeyException;
|
||||
import java.util.*;
|
||||
|
||||
import jdk.internal.ref.CleanerFactory;
|
||||
import sun.security.pkcs.PKCS8Key;
|
||||
import sun.security.pkcs.EncryptedPrivateKeyInfo;
|
||||
import sun.security.x509.AlgorithmId;
|
||||
@ -141,18 +142,10 @@ final class KeyProtector {
|
||||
passwdBytes[j++] = (byte)(password[i] >> 8);
|
||||
passwdBytes[j++] = (byte)password[i];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures that the password bytes of this key protector are
|
||||
* set to zero when there are no more references to it.
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
protected void finalize() {
|
||||
if (passwdBytes != null) {
|
||||
Arrays.fill(passwdBytes, (byte)0x00);
|
||||
passwdBytes = null;
|
||||
}
|
||||
// Use the cleaner to zero the password when no longer referenced
|
||||
final byte[] k = this.passwdBytes;
|
||||
CleanerFactory.cleaner().register(this,
|
||||
() -> java.util.Arrays.fill(k, (byte)0x00));
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -275,6 +275,12 @@ public class SocketTransportService extends TransportService {
|
||||
sa = new InetSocketAddress(localaddress, port);
|
||||
}
|
||||
ServerSocket ss = new ServerSocket();
|
||||
if (port == 0) {
|
||||
// Only need SO_REUSEADDR if we're using a fixed port. If we
|
||||
// start seeing EADDRINUSE due to collisions in free ports
|
||||
// then we should retry the bind() a few times.
|
||||
ss.setReuseAddress(false);
|
||||
}
|
||||
ss.bind(sa);
|
||||
return new SocketListenKey(ss);
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1998, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -119,8 +119,26 @@ getLastError() {
|
||||
return (char *)dbgsysTlsGet(tlsIndex);
|
||||
}
|
||||
|
||||
/* Set options common to client and server sides */
|
||||
static jdwpTransportError
|
||||
setOptions(int fd)
|
||||
setOptionsCommon(int fd)
|
||||
{
|
||||
jvalue dontcare;
|
||||
int err;
|
||||
|
||||
dontcare.i = 0; /* keep compiler happy */
|
||||
|
||||
err = dbgsysSetSocketOption(fd, TCP_NODELAY, JNI_TRUE, dontcare);
|
||||
if (err < 0) {
|
||||
RETURN_IO_ERROR("setsockopt TCPNODELAY failed");
|
||||
}
|
||||
|
||||
return JDWPTRANSPORT_ERROR_NONE;
|
||||
}
|
||||
|
||||
/* Set the SO_REUSEADDR option */
|
||||
static jdwpTransportError
|
||||
setReuseAddrOption(int fd)
|
||||
{
|
||||
jvalue dontcare;
|
||||
int err;
|
||||
@ -132,11 +150,6 @@ setOptions(int fd)
|
||||
RETURN_IO_ERROR("setsockopt SO_REUSEADDR failed");
|
||||
}
|
||||
|
||||
err = dbgsysSetSocketOption(fd, TCP_NODELAY, JNI_TRUE, dontcare);
|
||||
if (err < 0) {
|
||||
RETURN_IO_ERROR("setsockopt TCPNODELAY failed");
|
||||
}
|
||||
|
||||
return JDWPTRANSPORT_ERROR_NONE;
|
||||
}
|
||||
|
||||
@ -350,10 +363,21 @@ socketTransport_startListening(jdwpTransportEnv* env, const char* address,
|
||||
RETURN_IO_ERROR("socket creation failed");
|
||||
}
|
||||
|
||||
err = setOptions(serverSocketFD);
|
||||
err = setOptionsCommon(serverSocketFD);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
if (sa.sin_port != 0) {
|
||||
/*
|
||||
* Only need SO_REUSEADDR if we're using a fixed port. If we
|
||||
* start seeing EADDRINUSE due to collisions in free ports
|
||||
* then we should retry the dbgsysBind() a few times.
|
||||
*/
|
||||
err = setReuseAddrOption(serverSocketFD);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
err = dbgsysBind(serverSocketFD, (struct sockaddr *)&sa, sizeof(sa));
|
||||
if (err < 0) {
|
||||
@ -510,11 +534,17 @@ socketTransport_attach(jdwpTransportEnv* env, const char* addressString, jlong a
|
||||
RETURN_IO_ERROR("unable to create socket");
|
||||
}
|
||||
|
||||
err = setOptions(socketFD);
|
||||
err = setOptionsCommon(socketFD);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* We don't call setReuseAddrOption() for the non-server socket
|
||||
* case. If we start seeing EADDRINUSE due to collisions in free
|
||||
* ports then we should retry the dbgsysConnect() a few times.
|
||||
*/
|
||||
|
||||
/*
|
||||
* To do a timed connect we make the socket non-blocking
|
||||
* and poll with a timeout;
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @modules java.base/com.sun.crypto.provider:+open
|
||||
* @run main/othervm DESKeyCleanupTest
|
||||
* @summary Verify that key storage is cleared
|
||||
*/
|
||||
|
||||
import java.lang.ref.PhantomReference;
|
||||
import java.lang.ref.Reference;
|
||||
import java.lang.ref.ReferenceQueue;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Arrays;
|
||||
|
||||
import javax.crypto.KeyGenerator;
|
||||
import javax.crypto.SecretKey;
|
||||
|
||||
/**
|
||||
* Test that the array holding the key bytes is cleared when it is
|
||||
* no longer referenced by the key.
|
||||
*/
|
||||
|
||||
public class DESKeyCleanupTest {
|
||||
|
||||
private final static String SunJCEProvider = "SunJCE";
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
testCleanupSecret("DES");
|
||||
testCleanupSecret("DESede");
|
||||
}
|
||||
|
||||
static void testCleanupSecret(String algorithm) throws Exception {
|
||||
KeyGenerator desGen = KeyGenerator.getInstance(algorithm, SunJCEProvider);
|
||||
SecretKey key = desGen.generateKey();
|
||||
|
||||
// Break into the implementation to observe the key byte array.
|
||||
Class<?> keyClass = key.getClass();
|
||||
Field keyField = keyClass.getDeclaredField("key");
|
||||
keyField.setAccessible(true);
|
||||
byte[] array = (byte[])keyField.get(key);
|
||||
|
||||
byte[] zeros = new byte[array.length];
|
||||
do {
|
||||
// Wait for array to be cleared; if not cleared test will timeout
|
||||
System.out.printf("%s array: %s%n", algorithm, Arrays.toString(array));
|
||||
key = null;
|
||||
System.gc(); // attempt to reclaim the key
|
||||
} while (Arrays.compare(zeros, array) != 0);
|
||||
System.out.printf("%s array: %s%n", algorithm, Arrays.toString(array));
|
||||
|
||||
Reference.reachabilityFence(key); // Keep key alive
|
||||
Reference.reachabilityFence(array); // Keep array alive
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,103 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @modules java.base/com.sun.crypto.provider:+open
|
||||
* @run main/othervm PBEKeyCleanupTest
|
||||
* @summary Verify that key storage is cleared
|
||||
*/
|
||||
|
||||
import java.lang.ref.PhantomReference;
|
||||
import java.lang.ref.Reference;
|
||||
import java.lang.ref.ReferenceQueue;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Arrays;
|
||||
import java.util.Random;
|
||||
|
||||
import javax.crypto.SecretKey;
|
||||
import javax.crypto.SecretKeyFactory;
|
||||
import javax.crypto.spec.PBEKeySpec;
|
||||
|
||||
/**
|
||||
* Test that the array holding the key bytes is cleared when it is
|
||||
* no longer referenced by the key.
|
||||
*/
|
||||
public class PBEKeyCleanupTest {
|
||||
|
||||
private final static String SunJCEProvider = "SunJCE";
|
||||
|
||||
private static final String PASS_PHRASE = "some hidden string";
|
||||
private static final int ITERATION_COUNT = 1000;
|
||||
private static final int KEY_SIZE = 128;
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
testPBESecret("PBEWithMD5AndDES");
|
||||
testPBKSecret("PBKDF2WithHmacSHA1");
|
||||
}
|
||||
|
||||
private static void testPBESecret(String algorithm) throws Exception {
|
||||
char[] password = new char[] {'f', 'o', 'o'};
|
||||
PBEKeySpec pbeKeySpec = new PBEKeySpec(password);
|
||||
SecretKeyFactory keyFac =
|
||||
SecretKeyFactory.getInstance(algorithm, SunJCEProvider);
|
||||
|
||||
testCleanupSecret(algorithm, keyFac.generateSecret(pbeKeySpec));
|
||||
}
|
||||
|
||||
private static void testPBKSecret(String algorithm) throws Exception {
|
||||
byte[] salt = new byte[8];
|
||||
new Random().nextBytes(salt);
|
||||
char[] password = new char[] {'f', 'o', 'o'};
|
||||
PBEKeySpec pbeKeySpec = new PBEKeySpec(PASS_PHRASE.toCharArray(), salt,
|
||||
ITERATION_COUNT, KEY_SIZE);
|
||||
SecretKeyFactory keyFac =
|
||||
SecretKeyFactory.getInstance(algorithm, SunJCEProvider);
|
||||
|
||||
testCleanupSecret(algorithm, keyFac.generateSecret(pbeKeySpec));
|
||||
}
|
||||
|
||||
static void testCleanupSecret(String algorithm, SecretKey key) throws Exception {
|
||||
|
||||
// Break into the implementation to observe the key byte array.
|
||||
Class<?> keyClass = key.getClass();
|
||||
Field keyField = keyClass.getDeclaredField("key");
|
||||
keyField.setAccessible(true);
|
||||
byte[] array = (byte[])keyField.get(key);
|
||||
|
||||
byte[] zeros = new byte[array.length];
|
||||
do {
|
||||
// Wait for array to be cleared; if not cleared test will timeout
|
||||
System.out.printf("%s array: %s%n", algorithm, Arrays.toString(array));
|
||||
key = null;
|
||||
System.gc(); // attempt to reclaim the key
|
||||
} while (Arrays.compare(zeros, array) != 0);
|
||||
System.out.printf("%s array: %s%n", algorithm, Arrays.toString(array));
|
||||
|
||||
Reference.reachabilityFence(key); // Keep key alive
|
||||
Reference.reachabilityFence(array); // Keep array alive
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -125,10 +125,9 @@ public class GetResource {
|
||||
return new Object[][] {
|
||||
new Object[] { List.of("-Xbootclasspath/a:."), "a"},
|
||||
|
||||
// "b" is the expected result when JDK-8185540 is resolved
|
||||
new Object[] { List.of("-Xbootclasspath/a:" + dirB), "a"},
|
||||
new Object[] { List.of("-Xbootclasspath/a:" + dirB), "b"},
|
||||
// empty path in first element
|
||||
new Object[] { List.of("-Xbootclasspath/a:" + File.pathSeparator + dirB), "a"},
|
||||
new Object[] { List.of("-Xbootclasspath/a:" + File.pathSeparator + dirB), "b"},
|
||||
|
||||
new Object[] { List.of("-cp", File.pathSeparator), "a"},
|
||||
new Object[] { List.of("-cp", dirB), "b"},
|
||||
|
@ -23,6 +23,7 @@ grant codebase "file:${test.classes}/proxydir/-" {
|
||||
|
||||
grant codeBase "jrt:/jdk.incubator.httpclient" {
|
||||
permission java.lang.RuntimePermission "accessClassInPackage.sun.net";
|
||||
permission java.lang.RuntimePermission "accessClassInPackage.sun.net.util";
|
||||
permission java.lang.RuntimePermission "accessClassInPackage.sun.net.www";
|
||||
permission java.lang.RuntimePermission "accessClassInPackage.jdk.internal.misc";
|
||||
|
||||
|
@ -23,6 +23,7 @@ grant codebase "file:${test.classes}/proxydir/-" {
|
||||
|
||||
grant codeBase "jrt:/jdk.incubator.httpclient" {
|
||||
permission java.lang.RuntimePermission "accessClassInPackage.sun.net";
|
||||
permission java.lang.RuntimePermission "accessClassInPackage.sun.net.util";
|
||||
permission java.lang.RuntimePermission "accessClassInPackage.sun.net.www";
|
||||
permission java.lang.RuntimePermission "accessClassInPackage.jdk.internal.misc";
|
||||
|
||||
|
@ -22,6 +22,7 @@ grant codebase "file:${test.classes}/proxydir/-" {
|
||||
|
||||
grant codeBase "jrt:/jdk.incubator.httpclient" {
|
||||
permission java.lang.RuntimePermission "accessClassInPackage.sun.net";
|
||||
permission java.lang.RuntimePermission "accessClassInPackage.sun.net.util";
|
||||
permission java.lang.RuntimePermission "accessClassInPackage.sun.net.www";
|
||||
permission java.lang.RuntimePermission "accessClassInPackage.jdk.internal.misc";
|
||||
|
||||
|
@ -24,6 +24,7 @@ grant codebase "file:${test.classes}/proxydir/-" {
|
||||
|
||||
grant codeBase "jrt:/jdk.incubator.httpclient" {
|
||||
permission java.lang.RuntimePermission "accessClassInPackage.sun.net";
|
||||
permission java.lang.RuntimePermission "accessClassInPackage.sun.net.util";
|
||||
permission java.lang.RuntimePermission "accessClassInPackage.sun.net.www";
|
||||
permission java.lang.RuntimePermission "accessClassInPackage.jdk.internal.misc";
|
||||
|
||||
|
@ -24,6 +24,7 @@ grant codebase "file:${test.classes}/proxydir/-" {
|
||||
|
||||
grant codeBase "jrt:/jdk.incubator.httpclient" {
|
||||
permission java.lang.RuntimePermission "accessClassInPackage.sun.net";
|
||||
permission java.lang.RuntimePermission "accessClassInPackage.sun.net.util";
|
||||
permission java.lang.RuntimePermission "accessClassInPackage.sun.net.www";
|
||||
permission java.lang.RuntimePermission "accessClassInPackage.jdk.internal.misc";
|
||||
|
||||
|
@ -23,6 +23,7 @@ grant codebase "file:${test.classes}/proxydir/-" {
|
||||
|
||||
grant codeBase "jrt:/jdk.incubator.httpclient" {
|
||||
permission java.lang.RuntimePermission "accessClassInPackage.sun.net";
|
||||
permission java.lang.RuntimePermission "accessClassInPackage.sun.net.util";
|
||||
permission java.lang.RuntimePermission "accessClassInPackage.sun.net.www";
|
||||
permission java.lang.RuntimePermission "accessClassInPackage.jdk.internal.misc";
|
||||
|
||||
|
@ -26,6 +26,7 @@ grant codebase "file:${test.classes}/proxydir/-" {
|
||||
|
||||
grant codeBase "jrt:/jdk.incubator.httpclient" {
|
||||
permission java.lang.RuntimePermission "accessClassInPackage.sun.net";
|
||||
permission java.lang.RuntimePermission "accessClassInPackage.sun.net.util";
|
||||
permission java.lang.RuntimePermission "accessClassInPackage.sun.net.www";
|
||||
permission java.lang.RuntimePermission "accessClassInPackage.jdk.internal.misc";
|
||||
|
||||
|
@ -23,6 +23,7 @@ grant codebase "file:${test.classes}/proxydir/-" {
|
||||
|
||||
grant codeBase "jrt:/jdk.incubator.httpclient" {
|
||||
permission java.lang.RuntimePermission "accessClassInPackage.sun.net";
|
||||
permission java.lang.RuntimePermission "accessClassInPackage.sun.net.util";
|
||||
permission java.lang.RuntimePermission "accessClassInPackage.sun.net.www";
|
||||
permission java.lang.RuntimePermission "accessClassInPackage.jdk.internal.misc";
|
||||
|
||||
|
@ -23,6 +23,7 @@ grant codebase "file:${test.classes}/proxydir/-" {
|
||||
|
||||
grant codeBase "jrt:/jdk.incubator.httpclient" {
|
||||
permission java.lang.RuntimePermission "accessClassInPackage.sun.net";
|
||||
permission java.lang.RuntimePermission "accessClassInPackage.sun.net.util";
|
||||
permission java.lang.RuntimePermission "accessClassInPackage.sun.net.www";
|
||||
permission java.lang.RuntimePermission "accessClassInPackage.jdk.internal.misc";
|
||||
|
||||
|
@ -24,6 +24,7 @@ grant codebase "file:${test.classes}/proxydir/-" {
|
||||
|
||||
grant codeBase "jrt:/jdk.incubator.httpclient" {
|
||||
permission java.lang.RuntimePermission "accessClassInPackage.sun.net";
|
||||
permission java.lang.RuntimePermission "accessClassInPackage.sun.net.util";
|
||||
permission java.lang.RuntimePermission "accessClassInPackage.sun.net.www";
|
||||
permission java.lang.RuntimePermission "accessClassInPackage.jdk.internal.misc";
|
||||
|
||||
|
@ -23,6 +23,7 @@ grant codebase "file:${test.classes}/proxydir/-" {
|
||||
|
||||
grant codeBase "jrt:/jdk.incubator.httpclient" {
|
||||
permission java.lang.RuntimePermission "accessClassInPackage.sun.net";
|
||||
permission java.lang.RuntimePermission "accessClassInPackage.sun.net.util";
|
||||
permission java.lang.RuntimePermission "accessClassInPackage.sun.net.www";
|
||||
permission java.lang.RuntimePermission "accessClassInPackage.jdk.internal.misc";
|
||||
|
||||
|
@ -23,6 +23,7 @@ grant codebase "file:${test.classes}/proxydir/-" {
|
||||
|
||||
grant codeBase "jrt:/jdk.incubator.httpclient" {
|
||||
permission java.lang.RuntimePermission "accessClassInPackage.sun.net";
|
||||
permission java.lang.RuntimePermission "accessClassInPackage.sun.net.util";
|
||||
permission java.lang.RuntimePermission "accessClassInPackage.sun.net.www";
|
||||
permission java.lang.RuntimePermission "accessClassInPackage.jdk.internal.misc";
|
||||
|
||||
|
@ -23,6 +23,7 @@ grant codebase "file:${test.classes}/proxydir/-" {
|
||||
|
||||
grant codeBase "jrt:/jdk.incubator.httpclient" {
|
||||
permission java.lang.RuntimePermission "accessClassInPackage.sun.net";
|
||||
permission java.lang.RuntimePermission "accessClassInPackage.sun.net.util";
|
||||
permission java.lang.RuntimePermission "accessClassInPackage.sun.net.www";
|
||||
permission java.lang.RuntimePermission "accessClassInPackage.jdk.internal.misc";
|
||||
|
||||
|
@ -23,6 +23,7 @@ grant codebase "file:${test.classes}/proxydir/-" {
|
||||
|
||||
grant codeBase "jrt:/jdk.incubator.httpclient" {
|
||||
permission java.lang.RuntimePermission "accessClassInPackage.sun.net";
|
||||
permission java.lang.RuntimePermission "accessClassInPackage.sun.net.util";
|
||||
permission java.lang.RuntimePermission "accessClassInPackage.sun.net.www";
|
||||
permission java.lang.RuntimePermission "accessClassInPackage.jdk.internal.misc";
|
||||
|
||||
|
@ -23,6 +23,7 @@ grant codebase "file:${test.classes}/proxydir/-" {
|
||||
|
||||
grant codeBase "jrt:/jdk.incubator.httpclient" {
|
||||
permission java.lang.RuntimePermission "accessClassInPackage.sun.net";
|
||||
permission java.lang.RuntimePermission "accessClassInPackage.sun.net.util";
|
||||
permission java.lang.RuntimePermission "accessClassInPackage.sun.net.www";
|
||||
permission java.lang.RuntimePermission "accessClassInPackage.jdk.internal.misc";
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -34,7 +34,7 @@
|
||||
* @compile ../ProxyServer.java
|
||||
* @build Security
|
||||
*
|
||||
* @run driver/timeout=60 Driver
|
||||
* @run driver/timeout=90 Driver
|
||||
*/
|
||||
|
||||
/**
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -26,34 +26,25 @@
|
||||
* @summary Check various properties of key and selected-key sets
|
||||
*
|
||||
* @run main KeySets
|
||||
* @run main/othervm -Dsun.nio.ch.bugLevel=1.4 KeySets
|
||||
*/
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.channels.*;
|
||||
import java.util.*;
|
||||
|
||||
|
||||
public class KeySets {
|
||||
|
||||
static boolean compat;
|
||||
|
||||
static abstract class Catch {
|
||||
abstract void go() throws Exception;
|
||||
Catch(Class xc) throws Exception {
|
||||
try {
|
||||
go();
|
||||
} catch (Exception x) {
|
||||
if (compat)
|
||||
throw new Exception("Exception thrown", x);
|
||||
if (xc.isInstance(x))
|
||||
return;
|
||||
throw new Exception("Wrong exception", x);
|
||||
}
|
||||
if (compat)
|
||||
return;
|
||||
throw new Exception("Not thrown as expected: "
|
||||
+ xc.getName());
|
||||
throw new Exception("Not thrown as expected: " + xc.getName());
|
||||
}
|
||||
}
|
||||
|
||||
@ -74,7 +65,6 @@ public class KeySets {
|
||||
void go() throws Exception {
|
||||
sel.selectedKeys();
|
||||
}};
|
||||
|
||||
}
|
||||
|
||||
static void testNoAddition(final Set s) throws Exception {
|
||||
@ -174,14 +164,10 @@ public class KeySets {
|
||||
sel.selectedKeys().clear();
|
||||
if (!sel.selectedKeys().isEmpty())
|
||||
throw new Exception("clear failed");
|
||||
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
String bl = System.getProperty("sun.nio.ch.bugLevel");
|
||||
compat = (bl != null) && bl.equals("1.4");
|
||||
testClose();
|
||||
testMutability();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -111,16 +111,10 @@ public class SystemModulesTest {
|
||||
|
||||
private void checkAttributes(ModuleReference modRef) {
|
||||
try {
|
||||
if (modRef.descriptor().name().equals("java.base")) {
|
||||
ModuleTargetHelper.ModuleTarget mt = ModuleTargetHelper.read(modRef);
|
||||
String[] values = mt.targetPlatform().split("-");
|
||||
assertTrue(checkOSName(values[0]));
|
||||
assertTrue(checkOSArch(values[1]));
|
||||
} else {
|
||||
// target platform attribute is dropped by jlink plugin for other modules
|
||||
ModuleTargetHelper.ModuleTarget mt = ModuleTargetHelper.read(modRef);
|
||||
assertTrue(mt == null || mt.targetPlatform() == null);
|
||||
}
|
||||
ModuleTargetHelper.ModuleTarget mt = ModuleTargetHelper.read(modRef);
|
||||
String[] values = mt.targetPlatform().split("-");
|
||||
assertTrue(checkOSName(values[0]));
|
||||
assertTrue(checkOSArch(values[1]));
|
||||
} catch (IOException exp) {
|
||||
throw new UncheckedIOException(exp);
|
||||
}
|
||||
|
@ -284,7 +284,6 @@ public class UserModuleTest {
|
||||
Set<String> modules = Set.of("m1", "m4");
|
||||
assertTrue(JLINK_TOOL.run(System.out, System.out,
|
||||
"--output", dir.toString(),
|
||||
"--system-modules", "retainModuleTarget",
|
||||
"--exclude-resources", "m4/p4/dummy/*",
|
||||
"--add-modules", modules.stream().collect(Collectors.joining(",")),
|
||||
"--module-path", mp) == 0);
|
||||
|
@ -32,7 +32,7 @@ import java.nio.file.FileSystem;
|
||||
import java.nio.file.FileSystems;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import jdk.internal.module.ClassFileAttributes;
|
||||
@ -67,8 +67,7 @@ public class Main {
|
||||
}
|
||||
|
||||
private static boolean hasModuleTarget(String modName) throws IOException {
|
||||
FileSystem fs = FileSystems.newFileSystem(URI.create("jrt:/"),
|
||||
Collections.emptyMap());
|
||||
FileSystem fs = FileSystems.newFileSystem(URI.create("jrt:/"), Map.of());
|
||||
Path path = fs.getPath("/", "modules", modName, "module-info.class");
|
||||
try (InputStream in = Files.newInputStream(path)) {
|
||||
return hasModuleTarget(in);
|
||||
@ -86,8 +85,8 @@ public class Main {
|
||||
expectModuleTarget = true;
|
||||
}
|
||||
|
||||
// java.base is packaged with osName/osArch/osVersion
|
||||
if (! hasModuleTarget("java.base")) {
|
||||
// java.base is packaged with ModuleTarget
|
||||
if (!hasModuleTarget("java.base")) {
|
||||
throw new RuntimeException("ModuleTarget absent for java.base");
|
||||
}
|
||||
|
||||
@ -109,8 +108,7 @@ public class Main {
|
||||
}
|
||||
|
||||
// verify ModuleDescriptor from module-info.class read from jimage
|
||||
FileSystem fs = FileSystems.newFileSystem(URI.create("jrt:/"),
|
||||
Collections.emptyMap());
|
||||
FileSystem fs = FileSystems.newFileSystem(URI.create("jrt:/"), Map.of());
|
||||
Path path = fs.getPath("/", "modules", mn, "module-info.class");
|
||||
checkModuleDescriptor(ModuleDescriptor.read(Files.newInputStream(path)), packages);
|
||||
}
|
||||
@ -121,16 +119,9 @@ public class Main {
|
||||
throw new RuntimeException(md.mainClass().toString());
|
||||
}
|
||||
|
||||
if (expectModuleTarget) {
|
||||
// ModuleTarget attribute is retained
|
||||
if (! hasModuleTarget(md.name())) {
|
||||
throw new RuntimeException("ModuleTarget missing for " + md.name());
|
||||
}
|
||||
} else {
|
||||
// by default ModuleTarget attribute is dropped
|
||||
if (hasModuleTarget(md.name())) {
|
||||
throw new RuntimeException("ModuleTarget present for " + md.name());
|
||||
}
|
||||
// ModuleTarget attribute should be present
|
||||
if (!hasModuleTarget(md.name())) {
|
||||
throw new RuntimeException("ModuleTarget missing for " + md.name());
|
||||
}
|
||||
|
||||
Set<String> pkgs = md.packages();
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -31,20 +31,17 @@ import java.util.Set;
|
||||
* Test --patch-module java.base=jdk/modules/java.base to override
|
||||
* java.base with an exploded image
|
||||
*/
|
||||
public final class SystemModules {
|
||||
public static final String[] MODULE_NAMES = new String[0];
|
||||
|
||||
public static int PACKAGES_IN_BOOT_LAYER = 1024;
|
||||
|
||||
public static boolean hasSplitPackages() {
|
||||
return true;
|
||||
class SystemModulesMap {
|
||||
static SystemModules allSystemModules() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static Map<String, Set<String>> concealedPackagesToOpen() {
|
||||
return Collections.emptyMap();
|
||||
static SystemModules defaultSystemModules() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static Map<String, Set<String>> exportedPackagesToOpen() {
|
||||
return Collections.emptyMap();
|
||||
static String[] moduleNames() {
|
||||
return new String[0];
|
||||
}
|
||||
static String[] classNames() {
|
||||
return new String[0];
|
||||
}
|
||||
}
|
@ -101,9 +101,9 @@ JAVADOC_TAGS := \
|
||||
JAVADOC_DISABLED_DOCLINT := accessibility html missing syntax reference
|
||||
|
||||
# The initial set of options for javadoc
|
||||
JAVADOC_OPTIONS := -XDignore.symbol.file=true -use -keywords -notimestamp \
|
||||
-serialwarn -encoding ISO-8859-1 -breakiterator -splitIndex --system none \
|
||||
-html5 -javafx --expand-requires transitive
|
||||
JAVADOC_OPTIONS := -use -keywords -notimestamp \
|
||||
-serialwarn -encoding ISO-8859-1 -docencoding UTF-8 -breakiterator \
|
||||
-splitIndex --system none -html5 -javafx --expand-requires transitive
|
||||
|
||||
# Should we add DRAFT stamps to the generated javadoc?
|
||||
ifeq ($(VERSION_IS_GA), true)
|
||||
|
Loading…
Reference in New Issue
Block a user