8178380
: Module system implementation refresh (5/2017)
Co-authored-by: Mandy Chung <mandy.chung@oracle.com> Co-authored-by: Chris Hegarty <chris.hegarty@oracle.com> Reviewed-by: mchung, alanb, sspitsyn
This commit is contained in:
parent
ffed03c6d9
commit
4c0e26e374
@ -39,6 +39,7 @@ SUNWprivate_1.1 {
|
|||||||
Java_sun_instrument_InstrumentationImpl_getObjectSize0;
|
Java_sun_instrument_InstrumentationImpl_getObjectSize0;
|
||||||
Java_sun_instrument_InstrumentationImpl_appendToClassLoaderSearch0;
|
Java_sun_instrument_InstrumentationImpl_appendToClassLoaderSearch0;
|
||||||
Java_sun_instrument_InstrumentationImpl_setNativeMethodPrefixes;
|
Java_sun_instrument_InstrumentationImpl_setNativeMethodPrefixes;
|
||||||
|
Java_sun_instrument_InstrumentationImpl_loadAgent0;
|
||||||
local:
|
local:
|
||||||
*;
|
*;
|
||||||
};
|
};
|
||||||
|
@ -119,18 +119,24 @@ import sun.security.util.SecurityConstants;
|
|||||||
* The Java run-time has the following built-in class loaders:
|
* The Java run-time has the following built-in class loaders:
|
||||||
*
|
*
|
||||||
* <ul>
|
* <ul>
|
||||||
* <li>Bootstrap class loader.
|
* <li><p>Bootstrap class loader.
|
||||||
* It is the virtual machine's built-in class loader, typically represented
|
* It is the virtual machine's built-in class loader, typically represented
|
||||||
* as {@code null}, and does not have a parent.</li>
|
* as {@code null}, and does not have a parent.</li>
|
||||||
* <li>{@linkplain #getPlatformClassLoader() Platform class loader}.
|
* <li><p>{@linkplain #getPlatformClassLoader() Platform class loader}.
|
||||||
* All <em>platform classes</em> are visible to the platform class loader
|
* All <em>platform classes</em> are visible to the platform class loader
|
||||||
* that can be used as the parent of a {@code ClassLoader} instance.
|
* that can be used as the parent of a {@code ClassLoader} instance.
|
||||||
* Platform classes include Java SE platform APIs, their implementation
|
* Platform classes include Java SE platform APIs, their implementation
|
||||||
* classes and JDK-specific run-time classes that are defined by the
|
* classes and JDK-specific run-time classes that are defined by the
|
||||||
* platform class loader or its ancestors.</li>
|
* platform class loader or its ancestors.
|
||||||
* <li>{@linkplain #getSystemClassLoader() System class loader}.
|
* <p> To allow for upgrading/overriding of modules defined to the platform
|
||||||
* It is also known as <em>application class
|
* class loader, and where classes in the upgraded version link to
|
||||||
* loader</em> and is distinct from the platform class loader.
|
* classes in modules defined to the application class loader, the
|
||||||
|
* platform class loader may delegate to the application class loader.
|
||||||
|
* In other words, classes in named modules defined to the application
|
||||||
|
* class loader may be visible to the platform class loader. </li>
|
||||||
|
* <li><p>{@linkplain #getSystemClassLoader() System class loader}.
|
||||||
|
* It is also known as <em>application class loader</em> and is distinct
|
||||||
|
* from the platform class loader.
|
||||||
* The system class loader is typically used to define classes on the
|
* The system class loader is typically used to define classes on the
|
||||||
* application class path, module path, and JDK-specific tools.
|
* application class path, module path, and JDK-specific tools.
|
||||||
* The platform class loader is a parent or an ancestor of the system class
|
* The platform class loader is a parent or an ancestor of the system class
|
||||||
@ -368,6 +374,10 @@ public abstract class ClassLoader {
|
|||||||
* Creates a new class loader of the specified name and using the
|
* Creates a new class loader of the specified name and using the
|
||||||
* specified parent class loader for delegation.
|
* specified parent class loader for delegation.
|
||||||
*
|
*
|
||||||
|
* @apiNote If the parent is specified as {@code null} (for the
|
||||||
|
* bootstrap class loader) then there is no guarantee that all platform
|
||||||
|
* classes are visible.
|
||||||
|
*
|
||||||
* @param name class loader name; or {@code null} if not named
|
* @param name class loader name; or {@code null} if not named
|
||||||
* @param parent the parent class loader
|
* @param parent the parent class loader
|
||||||
*
|
*
|
||||||
@ -390,9 +400,12 @@ public abstract class ClassLoader {
|
|||||||
* delegation.
|
* delegation.
|
||||||
*
|
*
|
||||||
* <p> If there is a security manager, its {@link
|
* <p> If there is a security manager, its {@link
|
||||||
* SecurityManager#checkCreateClassLoader()
|
* SecurityManager#checkCreateClassLoader() checkCreateClassLoader} method
|
||||||
* checkCreateClassLoader} method is invoked. This may result in
|
* is invoked. This may result in a security exception. </p>
|
||||||
* a security exception. </p>
|
*
|
||||||
|
* @apiNote If the parent is specified as {@code null} (for the
|
||||||
|
* bootstrap class loader) then there is no guarantee that all platform
|
||||||
|
* classes are visible.
|
||||||
*
|
*
|
||||||
* @param parent
|
* @param parent
|
||||||
* The parent class loader
|
* The parent class loader
|
||||||
@ -2206,6 +2219,12 @@ public abstract class ClassLoader {
|
|||||||
* this class loader are searched recursively (parent by parent)
|
* this class loader are searched recursively (parent by parent)
|
||||||
* for a {@code Package} of the given name.
|
* for a {@code Package} of the given name.
|
||||||
*
|
*
|
||||||
|
* @apiNote The {@link #getPlatformClassLoader() platform class loader}
|
||||||
|
* may delegate to the application class loader but the application class
|
||||||
|
* loader is not its ancestor. When invoked on the platform class loader,
|
||||||
|
* this method will not find packages defined to the application
|
||||||
|
* class loader.
|
||||||
|
*
|
||||||
* @param name
|
* @param name
|
||||||
* The <a href="#name">package name</a>
|
* The <a href="#name">package name</a>
|
||||||
*
|
*
|
||||||
@ -2251,6 +2270,14 @@ public abstract class ClassLoader {
|
|||||||
* {@code Package} object of the same package name, each defined by
|
* {@code Package} object of the same package name, each defined by
|
||||||
* a different class loader in the class loader hierarchy.
|
* a different class loader in the class loader hierarchy.
|
||||||
*
|
*
|
||||||
|
* @apiNote The {@link #getPlatformClassLoader() platform class loader}
|
||||||
|
* may delegate to the application class loader. In other words,
|
||||||
|
* packages in modules defined to the application class loader may be
|
||||||
|
* visible to the platform class loader. On the other hand,
|
||||||
|
* the application class loader is not its ancestor and hence
|
||||||
|
* when invoked on the platform class loader, this method will not
|
||||||
|
* return any packages defined to the application class loader.
|
||||||
|
*
|
||||||
* @return The array of {@code Package} objects defined by this
|
* @return The array of {@code Package} objects defined by this
|
||||||
* class loader and its ancestors
|
* class loader and its ancestors
|
||||||
*
|
*
|
||||||
|
@ -57,6 +57,7 @@ import jdk.internal.loader.BuiltinClassLoader;
|
|||||||
import jdk.internal.loader.BootLoader;
|
import jdk.internal.loader.BootLoader;
|
||||||
import jdk.internal.misc.JavaLangAccess;
|
import jdk.internal.misc.JavaLangAccess;
|
||||||
import jdk.internal.misc.SharedSecrets;
|
import jdk.internal.misc.SharedSecrets;
|
||||||
|
import jdk.internal.module.ModuleLoaderMap;
|
||||||
import jdk.internal.module.ServicesCatalog;
|
import jdk.internal.module.ServicesCatalog;
|
||||||
import jdk.internal.module.Resources;
|
import jdk.internal.module.Resources;
|
||||||
import jdk.internal.org.objectweb.asm.AnnotationVisitor;
|
import jdk.internal.org.objectweb.asm.AnnotationVisitor;
|
||||||
@ -215,8 +216,8 @@ public final class Module implements AnnotatedElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the layer that contains this module or {@code null} if this
|
* Returns the module layer that contains this module or {@code null} if
|
||||||
* module is not in a layer.
|
* this module is not in a module layer.
|
||||||
*
|
*
|
||||||
* A module layer contains named modules and therefore this method always
|
* A module layer contains named modules and therefore this method always
|
||||||
* returns {@code null} when invoked on an unnamed module.
|
* returns {@code null} when invoked on an unnamed module.
|
||||||
@ -691,6 +692,13 @@ public final class Module implements AnnotatedElement {
|
|||||||
* <p> This method has no effect if the package is already <em>open</em>
|
* <p> This method has no effect if the package is already <em>open</em>
|
||||||
* to the given module. </p>
|
* to the given module. </p>
|
||||||
*
|
*
|
||||||
|
* @apiNote This method can be used for cases where a <em>consumer
|
||||||
|
* module</em> uses a qualified opens to open a package to an <em>API
|
||||||
|
* module</em> but where the reflective access to the members of classes in
|
||||||
|
* the consumer module is delegated to code in another module. Code in the
|
||||||
|
* API module can use this method to open the package in the consumer module
|
||||||
|
* to the other module.
|
||||||
|
*
|
||||||
* @param pn
|
* @param pn
|
||||||
* The package name
|
* The package name
|
||||||
* @param other
|
* @param other
|
||||||
@ -1077,7 +1085,7 @@ public final class Module implements AnnotatedElement {
|
|||||||
if (loader != null) {
|
if (loader != null) {
|
||||||
moduleToLoader.put(name, loader);
|
moduleToLoader.put(name, loader);
|
||||||
loaders.add(loader);
|
loaders.add(loader);
|
||||||
} else if (!isBootLayer) {
|
} else if (!(clf instanceof ModuleLoaderMap.Mapper)) {
|
||||||
throw new IllegalArgumentException("loader can't be 'null'");
|
throw new IllegalArgumentException("loader can't be 'null'");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1458,11 +1466,11 @@ public final class Module implements AnnotatedElement {
|
|||||||
* encapsulated. </li>
|
* encapsulated. </li>
|
||||||
*
|
*
|
||||||
* <li> A <em>package name</em> is derived from the resource name. If
|
* <li> A <em>package name</em> is derived from the resource name. If
|
||||||
* the package name is a {@link #getPackages() package} in the module
|
* the package name is a {@linkplain #getPackages() package} in the
|
||||||
* then the resource can only be located by the caller of this method
|
* module then the resource can only be located by the caller of this
|
||||||
* when the package is {@link #isOpen(String,Module) open} to at least
|
* method when the package is {@linkplain #isOpen(String,Module) open}
|
||||||
* the caller's module. If the resource is not in a package in the module
|
* to at least the caller's module. If the resource is not in a
|
||||||
* then the resource is not encapsulated. </li>
|
* package in the module then the resource is not encapsulated. </li>
|
||||||
* </ul>
|
* </ul>
|
||||||
*
|
*
|
||||||
* <p> In the above, the <em>package name</em> for a resource is derived
|
* <p> In the above, the <em>package name</em> for a resource is derived
|
||||||
@ -1521,8 +1529,7 @@ public final class Module implements AnnotatedElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// locate resource in module
|
// locate resource in module
|
||||||
JavaLangAccess jla = SharedSecrets.getJavaLangAccess();
|
URL url = loader.findResource(mn, name);
|
||||||
URL url = jla.findResource(loader, mn, name);
|
|
||||||
if (url != null) {
|
if (url != null) {
|
||||||
try {
|
try {
|
||||||
return url.openStream();
|
return url.openStream();
|
||||||
|
@ -25,10 +25,10 @@
|
|||||||
|
|
||||||
package java.lang;
|
package java.lang;
|
||||||
|
|
||||||
import java.lang.RuntimePermission;
|
|
||||||
import java.lang.module.ModuleDescriptor;
|
import java.lang.module.ModuleDescriptor;
|
||||||
import java.lang.module.ModuleDescriptor.Exports;
|
import java.lang.module.ModuleDescriptor.Exports;
|
||||||
import java.lang.module.ModuleDescriptor.Opens;
|
import java.lang.module.ModuleDescriptor.Opens;
|
||||||
|
import java.lang.module.ModuleReference;
|
||||||
import java.lang.reflect.Member;
|
import java.lang.reflect.Member;
|
||||||
import java.io.FileDescriptor;
|
import java.io.FileDescriptor;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
@ -42,12 +42,15 @@ import java.security.PrivilegedAction;
|
|||||||
import java.security.Security;
|
import java.security.Security;
|
||||||
import java.security.SecurityPermission;
|
import java.security.SecurityPermission;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.PropertyPermission;
|
import java.util.PropertyPermission;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import java.util.stream.Stream;
|
|
||||||
|
|
||||||
|
import jdk.internal.module.ModuleBootstrap;
|
||||||
|
import jdk.internal.module.ModuleLoaderMap;
|
||||||
import jdk.internal.reflect.CallerSensitive;
|
import jdk.internal.reflect.CallerSensitive;
|
||||||
import sun.security.util.SecurityConstants;
|
import sun.security.util.SecurityConstants;
|
||||||
|
|
||||||
@ -1431,30 +1434,30 @@ class SecurityManager {
|
|||||||
return packages;
|
return packages;
|
||||||
}
|
}
|
||||||
|
|
||||||
// The non-exported packages of the modules in the boot layer that are
|
// The non-exported packages in modules defined to the boot or platform
|
||||||
// loaded by the platform class loader or its ancestors. A non-exported
|
// class loaders. A non-exported package is a package that is not exported
|
||||||
// package is a package that either is not exported at all by its containing
|
// or is only exported to specific modules.
|
||||||
// module or is exported in a qualified fashion by its containing module.
|
private static final Map<String, Boolean> nonExportedPkgs = new ConcurrentHashMap<>();
|
||||||
private static final Set<String> nonExportedPkgs;
|
|
||||||
|
|
||||||
static {
|
static {
|
||||||
// Get the modules in the boot layer
|
addNonExportedPackages(ModuleLayer.boot());
|
||||||
Stream<Module> bootLayerModules = ModuleLayer.boot().modules().stream();
|
|
||||||
|
|
||||||
// Filter out the modules loaded by the boot or platform loader
|
|
||||||
PrivilegedAction<Set<Module>> pa = () ->
|
|
||||||
bootLayerModules.filter(SecurityManager::isBootOrPlatformModule)
|
|
||||||
.collect(Collectors.toSet());
|
|
||||||
Set<Module> modules = AccessController.doPrivileged(pa);
|
|
||||||
|
|
||||||
// Filter out the non-exported packages
|
|
||||||
nonExportedPkgs = modules.stream()
|
|
||||||
.map(Module::getDescriptor)
|
|
||||||
.map(SecurityManager::nonExportedPkgs)
|
|
||||||
.flatMap(Set::stream)
|
|
||||||
.collect(Collectors.toSet());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Record the non-exported packages of the modules in the given layer
|
||||||
|
*/
|
||||||
|
static void addNonExportedPackages(ModuleLayer layer) {
|
||||||
|
Set<String> bootModules = ModuleLoaderMap.bootModules();
|
||||||
|
Set<String> platformModules = ModuleLoaderMap.platformModules();
|
||||||
|
layer.modules().stream()
|
||||||
|
.map(Module::getDescriptor)
|
||||||
|
.filter(md -> bootModules.contains(md.name())
|
||||||
|
|| platformModules.contains(md.name()))
|
||||||
|
.map(SecurityManager::nonExportedPkgs)
|
||||||
|
.flatMap(Set::stream)
|
||||||
|
.forEach(pn -> nonExportedPkgs.put(pn, Boolean.TRUE));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called by java.security.Security
|
* Called by java.security.Security
|
||||||
*/
|
*/
|
||||||
@ -1467,14 +1470,6 @@ class SecurityManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns true if the module's loader is the boot or platform loader.
|
|
||||||
*/
|
|
||||||
private static boolean isBootOrPlatformModule(Module m) {
|
|
||||||
return m.getClassLoader() == null ||
|
|
||||||
m.getClassLoader() == ClassLoader.getPlatformClassLoader();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the non-exported packages of the specified module.
|
* Returns the non-exported packages of the specified module.
|
||||||
*/
|
*/
|
||||||
@ -1535,7 +1530,7 @@ class SecurityManager {
|
|||||||
Objects.requireNonNull(pkg, "package name can't be null");
|
Objects.requireNonNull(pkg, "package name can't be null");
|
||||||
|
|
||||||
// check if pkg is not exported to all modules
|
// check if pkg is not exported to all modules
|
||||||
if (nonExportedPkgs.contains(pkg)) {
|
if (nonExportedPkgs.containsKey(pkg)) {
|
||||||
checkPermission(
|
checkPermission(
|
||||||
new RuntimePermission("accessClassInPackage." + pkg));
|
new RuntimePermission("accessClassInPackage." + pkg));
|
||||||
return;
|
return;
|
||||||
@ -1634,7 +1629,7 @@ class SecurityManager {
|
|||||||
Objects.requireNonNull(pkg, "package name can't be null");
|
Objects.requireNonNull(pkg, "package name can't be null");
|
||||||
|
|
||||||
// check if pkg is not exported to all modules
|
// check if pkg is not exported to all modules
|
||||||
if (nonExportedPkgs.contains(pkg)) {
|
if (nonExportedPkgs.containsKey(pkg)) {
|
||||||
checkPermission(
|
checkPermission(
|
||||||
new RuntimePermission("defineClassInPackage." + pkg));
|
new RuntimePermission("defineClassInPackage." + pkg));
|
||||||
return;
|
return;
|
||||||
|
@ -41,7 +41,6 @@ import java.lang.reflect.Executable;
|
|||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.lang.reflect.Modifier;
|
import java.lang.reflect.Modifier;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.net.URL;
|
|
||||||
import java.security.AccessControlContext;
|
import java.security.AccessControlContext;
|
||||||
import java.security.ProtectionDomain;
|
import java.security.ProtectionDomain;
|
||||||
import java.security.AccessController;
|
import java.security.AccessController;
|
||||||
@ -2111,9 +2110,6 @@ public final class System {
|
|||||||
public Class<?> findBootstrapClassOrNull(ClassLoader cl, String name) {
|
public Class<?> findBootstrapClassOrNull(ClassLoader cl, String name) {
|
||||||
return cl.findBootstrapClassOrNull(name);
|
return cl.findBootstrapClassOrNull(name);
|
||||||
}
|
}
|
||||||
public URL findResource(ClassLoader cl, String mn, String name) throws IOException {
|
|
||||||
return cl.findResource(mn, name);
|
|
||||||
}
|
|
||||||
public Stream<Package> packages(ClassLoader cl) {
|
public Stream<Package> packages(ClassLoader cl) {
|
||||||
return cl.packages();
|
return cl.packages();
|
||||||
}
|
}
|
||||||
@ -2123,6 +2119,9 @@ public final class System {
|
|||||||
public String fastUUID(long lsb, long msb) {
|
public String fastUUID(long lsb, long msb) {
|
||||||
return Long.fastUUID(lsb, msb);
|
return Long.fastUUID(lsb, msb);
|
||||||
}
|
}
|
||||||
|
public void addNonExportedPackages(ModuleLayer layer) {
|
||||||
|
SecurityManager.addNonExportedPackages(layer);
|
||||||
|
}
|
||||||
public void invalidatePackageAccessCache() {
|
public void invalidatePackageAccessCache() {
|
||||||
SecurityManager.invalidatePackageAccessCache();
|
SecurityManager.invalidatePackageAccessCache();
|
||||||
}
|
}
|
||||||
|
@ -876,9 +876,7 @@ public class MethodHandles {
|
|||||||
* accessible to the class. The {@code PACKAGE} lookup mode serves to authenticate
|
* accessible to the class. The {@code PACKAGE} lookup mode serves to authenticate
|
||||||
* that the lookup object was created by a caller in the runtime package (or derived
|
* that the lookup object was created by a caller in the runtime package (or derived
|
||||||
* from a lookup originally created by suitably privileged code to a target class in
|
* from a lookup originally created by suitably privileged code to a target class in
|
||||||
* the runtime package). The lookup modes cannot include {@link #PRIVATE PRIVATE}
|
* the runtime package). </p>
|
||||||
* access. A lookup with {@code PRIVATE} access can be downgraded to drop this lookup
|
|
||||||
* mode with the {@linkplain #dropLookupMode(int) dropLookupMode} method. </p>
|
|
||||||
*
|
*
|
||||||
* <p> The {@code bytes} parameter is the class bytes of a valid class file (as defined
|
* <p> The {@code bytes} parameter is the class bytes of a valid class file (as defined
|
||||||
* by the <em>The Java Virtual Machine Specification</em>) with a class name in the
|
* by the <em>The Java Virtual Machine Specification</em>) with a class name in the
|
||||||
@ -896,7 +894,6 @@ public class MethodHandles {
|
|||||||
* @throws IllegalArgumentException the bytes are for a class in a different package
|
* @throws IllegalArgumentException the bytes are for a class in a different package
|
||||||
* to the lookup class
|
* to the lookup class
|
||||||
* @throws IllegalAccessException if this lookup does not have {@code PACKAGE} access
|
* @throws IllegalAccessException if this lookup does not have {@code PACKAGE} access
|
||||||
* @throws UnsupportedOperationException if the lookup class has {@code PRIVATE} access
|
|
||||||
* @throws LinkageError if the class is malformed ({@code ClassFormatError}), cannot be
|
* @throws LinkageError if the class is malformed ({@code ClassFormatError}), cannot be
|
||||||
* verified ({@code VerifyError}), is already defined, or another linkage error occurs
|
* verified ({@code VerifyError}), is already defined, or another linkage error occurs
|
||||||
* @throws SecurityException if denied by the security manager
|
* @throws SecurityException if denied by the security manager
|
||||||
@ -911,8 +908,6 @@ public class MethodHandles {
|
|||||||
SecurityManager sm = System.getSecurityManager();
|
SecurityManager sm = System.getSecurityManager();
|
||||||
if (sm != null)
|
if (sm != null)
|
||||||
sm.checkPermission(new RuntimePermission("defineClass"));
|
sm.checkPermission(new RuntimePermission("defineClass"));
|
||||||
if (hasPrivateAccess())
|
|
||||||
throw new UnsupportedOperationException("PRIVATE access not supported");
|
|
||||||
if ((lookupModes() & PACKAGE) == 0)
|
if ((lookupModes() & PACKAGE) == 0)
|
||||||
throw new IllegalAccessException("Lookup does not have PACKAGE access");
|
throw new IllegalAccessException("Lookup does not have PACKAGE access");
|
||||||
assert (lookupModes() & (MODULE|PUBLIC)) != 0;
|
assert (lookupModes() & (MODULE|PUBLIC)) != 0;
|
||||||
|
@ -109,20 +109,17 @@ public final class Configuration {
|
|||||||
private final Set<ResolvedModule> modules;
|
private final Set<ResolvedModule> modules;
|
||||||
private final Map<String, ResolvedModule> nameToModule;
|
private final Map<String, ResolvedModule> nameToModule;
|
||||||
|
|
||||||
// module constraints on target
|
// constraint on target platform
|
||||||
private final String osName;
|
private final String targetPlatform;
|
||||||
private final String osArch;
|
|
||||||
|
|
||||||
String osName() { return osName; }
|
String targetPlatform() { return targetPlatform; }
|
||||||
String osArch() { return osArch; }
|
|
||||||
|
|
||||||
private Configuration() {
|
private Configuration() {
|
||||||
this.parents = Collections.emptyList();
|
this.parents = Collections.emptyList();
|
||||||
this.graph = Collections.emptyMap();
|
this.graph = Collections.emptyMap();
|
||||||
this.modules = Collections.emptySet();
|
this.modules = Collections.emptySet();
|
||||||
this.nameToModule = Collections.emptyMap();
|
this.nameToModule = Collections.emptyMap();
|
||||||
this.osName = null;
|
this.targetPlatform = null;
|
||||||
this.osArch = null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private Configuration(List<Configuration> parents,
|
private Configuration(List<Configuration> parents,
|
||||||
@ -147,8 +144,7 @@ public final class Configuration {
|
|||||||
this.modules = Set.of(moduleArray);
|
this.modules = Set.of(moduleArray);
|
||||||
this.nameToModule = Map.ofEntries(nameEntries);
|
this.nameToModule = Map.ofEntries(nameEntries);
|
||||||
|
|
||||||
this.osName = resolver.osName();
|
this.targetPlatform = resolver.targetPlatform();
|
||||||
this.osArch = resolver.osArch();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -99,6 +99,7 @@ public class ModuleDescriptor
|
|||||||
*
|
*
|
||||||
* @see ModuleDescriptor#modifiers()
|
* @see ModuleDescriptor#modifiers()
|
||||||
* @since 9
|
* @since 9
|
||||||
|
* @spec JPMS
|
||||||
*/
|
*/
|
||||||
public static enum Modifier {
|
public static enum Modifier {
|
||||||
/**
|
/**
|
||||||
|
@ -286,8 +286,9 @@ public interface ModuleFinder {
|
|||||||
* class names of provider classes. </p></li>
|
* class names of provider classes. </p></li>
|
||||||
*
|
*
|
||||||
* <li><p> If the JAR file has a {@code Main-Class} attribute in its
|
* <li><p> If the JAR file has a {@code Main-Class} attribute in its
|
||||||
* main manifest then its value is the module {@link
|
* main manifest, its value is a legal class name, and its package is
|
||||||
* ModuleDescriptor#mainClass() main class}. </p></li>
|
* in the set of packages derived for the module, then the value is the
|
||||||
|
* module {@linkplain ModuleDescriptor#mainClass() main class}. </p></li>
|
||||||
*
|
*
|
||||||
* </ul>
|
* </ul>
|
||||||
*
|
*
|
||||||
@ -298,8 +299,7 @@ public interface ModuleFinder {
|
|||||||
* file, where the JAR file contains a {@code .class} in the top-level
|
* file, where the JAR file contains a {@code .class} in the top-level
|
||||||
* directory of the JAR file, where an entry in a service configuration
|
* directory of the JAR file, where an entry in a service configuration
|
||||||
* file is not a legal class name or its package name is not in the set of
|
* file is not a legal class name or its package name is not in the set of
|
||||||
* packages derived for the module, or where the module main class is not
|
* packages derived for the module. </p>
|
||||||
* a legal class name or its package is not in the module. </p>
|
|
||||||
*
|
*
|
||||||
* <p> In addition to JAR files, an implementation may also support modules
|
* <p> In addition to JAR files, an implementation may also support modules
|
||||||
* that are packaged in other implementation specific module formats. If
|
* that are packaged in other implementation specific module formats. If
|
||||||
|
@ -28,6 +28,7 @@ package java.lang.module;
|
|||||||
import java.io.PrintStream;
|
import java.io.PrintStream;
|
||||||
import java.lang.module.ModuleDescriptor.Provides;
|
import java.lang.module.ModuleDescriptor.Provides;
|
||||||
import java.lang.module.ModuleDescriptor.Requires.Modifier;
|
import java.lang.module.ModuleDescriptor.Requires.Modifier;
|
||||||
|
import java.net.URI;
|
||||||
import java.util.ArrayDeque;
|
import java.util.ArrayDeque;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
@ -38,10 +39,8 @@ import java.util.HashSet;
|
|||||||
import java.util.LinkedHashSet;
|
import java.util.LinkedHashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.StringJoiner;
|
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import jdk.internal.module.ModuleHashes;
|
import jdk.internal.module.ModuleHashes;
|
||||||
@ -69,12 +68,10 @@ final class Resolver {
|
|||||||
// true if all automatic modules have been found
|
// true if all automatic modules have been found
|
||||||
private boolean haveAllAutomaticModules;
|
private boolean haveAllAutomaticModules;
|
||||||
|
|
||||||
// module constraints on target platform
|
// constraint on target platform
|
||||||
private String osName;
|
private String targetPlatform;
|
||||||
private String osArch;
|
|
||||||
|
|
||||||
String osName() { return osName; }
|
String targetPlatform() { return targetPlatform; }
|
||||||
String osArch() { return osArch; }
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @throws IllegalArgumentException if there are more than one parent and
|
* @throws IllegalArgumentException if there are more than one parent and
|
||||||
@ -89,37 +86,23 @@ final class Resolver {
|
|||||||
this.afterFinder = afterFinder;
|
this.afterFinder = afterFinder;
|
||||||
this.traceOutput = traceOutput;
|
this.traceOutput = traceOutput;
|
||||||
|
|
||||||
// record constraints on target platform, checking that they don't conflict
|
// record constraint on target platform, checking for conflicts
|
||||||
for (Configuration parent : parents) {
|
for (Configuration parent : parents) {
|
||||||
String value = parent.osName();
|
String value = parent.targetPlatform();
|
||||||
if (value != null) {
|
if (value != null) {
|
||||||
if (osName == null) {
|
if (targetPlatform == null) {
|
||||||
osName = value;
|
targetPlatform = value;
|
||||||
} else {
|
} else {
|
||||||
if (!value.equals(osName)) {
|
if (!value.equals(targetPlatform)) {
|
||||||
failParentConflict("Operating System", osName, value);
|
String msg = "Parents have conflicting constraints on target" +
|
||||||
}
|
" platform: " + targetPlatform + ", " + value;
|
||||||
}
|
throw new IllegalArgumentException(msg);
|
||||||
}
|
|
||||||
value = parent.osArch();
|
|
||||||
if (value != null) {
|
|
||||||
if (osArch == null) {
|
|
||||||
osArch = value;
|
|
||||||
} else {
|
|
||||||
if (!value.equals(osArch)) {
|
|
||||||
failParentConflict("OS architecture", osArch, value);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void failParentConflict(String constraint, String s1, String s2) {
|
|
||||||
String msg = "Parents have conflicting constraints on target "
|
|
||||||
+ constraint + ": " + s1 + ", " + s2;
|
|
||||||
throw new IllegalArgumentException(msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Resolves the given named modules.
|
* Resolves the given named modules.
|
||||||
*
|
*
|
||||||
@ -147,8 +130,7 @@ final class Resolver {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (isTracing()) {
|
if (isTracing()) {
|
||||||
trace("Root module %s located", root);
|
trace("root %s", nameAndInfo(mref));
|
||||||
mref.location().ifPresent(uri -> trace(" (%s)", uri));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
addFoundModule(mref);
|
addFoundModule(mref);
|
||||||
@ -180,9 +162,7 @@ final class Resolver {
|
|||||||
ModuleDescriptor other = mref.descriptor();
|
ModuleDescriptor other = mref.descriptor();
|
||||||
q.offer(other);
|
q.offer(other);
|
||||||
if (isTracing()) {
|
if (isTracing()) {
|
||||||
trace("Automatic module %s located, required by %s",
|
trace("%s requires %s", descriptor.name(), nameAndInfo(mref));
|
||||||
other.name(), descriptor.name());
|
|
||||||
mref.location().ifPresent(uri -> trace(" (%s)", uri));
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
haveAllAutomaticModules = true;
|
haveAllAutomaticModules = true;
|
||||||
@ -213,21 +193,13 @@ final class Resolver {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isTracing() && !dn.equals("java.base")) {
|
||||||
|
trace("%s requires %s", descriptor.name(), nameAndInfo(mref));
|
||||||
|
}
|
||||||
|
|
||||||
if (!nameToReference.containsKey(dn)) {
|
if (!nameToReference.containsKey(dn)) {
|
||||||
addFoundModule(mref);
|
addFoundModule(mref);
|
||||||
q.offer(mref.descriptor());
|
q.offer(mref.descriptor());
|
||||||
|
|
||||||
if (isTracing()) {
|
|
||||||
String prefix;
|
|
||||||
if (mref.descriptor().isAutomatic()) {
|
|
||||||
prefix = "Automatic module";
|
|
||||||
} else {
|
|
||||||
prefix = "Module";
|
|
||||||
}
|
|
||||||
trace(prefix + " %s located, required by %s",
|
|
||||||
dn, descriptor.name());
|
|
||||||
mref.location().ifPresent(uri -> trace(" (%s)", uri));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -291,6 +263,13 @@ final class Resolver {
|
|||||||
do {
|
do {
|
||||||
for (ModuleDescriptor descriptor : candidateConsumers) {
|
for (ModuleDescriptor descriptor : candidateConsumers) {
|
||||||
if (!descriptor.uses().isEmpty()) {
|
if (!descriptor.uses().isEmpty()) {
|
||||||
|
|
||||||
|
// the modules that provide at least one service
|
||||||
|
Set<ModuleDescriptor> modulesToBind = null;
|
||||||
|
if (isTracing()) {
|
||||||
|
modulesToBind = new HashSet<>();
|
||||||
|
}
|
||||||
|
|
||||||
for (String service : descriptor.uses()) {
|
for (String service : descriptor.uses()) {
|
||||||
Set<ModuleReference> mrefs = availableProviders.get(service);
|
Set<ModuleReference> mrefs = availableProviders.get(service);
|
||||||
if (mrefs != null) {
|
if (mrefs != null) {
|
||||||
@ -298,15 +277,13 @@ final class Resolver {
|
|||||||
ModuleDescriptor provider = mref.descriptor();
|
ModuleDescriptor provider = mref.descriptor();
|
||||||
if (!provider.equals(descriptor)) {
|
if (!provider.equals(descriptor)) {
|
||||||
|
|
||||||
trace("Module %s provides %s, used by %s",
|
if (isTracing() && modulesToBind.add(provider)) {
|
||||||
provider.name(), service, descriptor.name());
|
trace("%s binds %s", descriptor.name(),
|
||||||
|
nameAndInfo(mref));
|
||||||
|
}
|
||||||
|
|
||||||
String pn = provider.name();
|
String pn = provider.name();
|
||||||
if (!nameToReference.containsKey(pn)) {
|
if (!nameToReference.containsKey(pn)) {
|
||||||
if (isTracing()) {
|
|
||||||
mref.location()
|
|
||||||
.ifPresent(uri -> trace(" (%s)", uri));
|
|
||||||
}
|
|
||||||
addFoundModule(mref);
|
addFoundModule(mref);
|
||||||
q.push(provider);
|
q.push(provider);
|
||||||
}
|
}
|
||||||
@ -349,59 +326,31 @@ final class Resolver {
|
|||||||
if (mref instanceof ModuleReferenceImpl) {
|
if (mref instanceof ModuleReferenceImpl) {
|
||||||
ModuleTarget target = ((ModuleReferenceImpl)mref).moduleTarget();
|
ModuleTarget target = ((ModuleReferenceImpl)mref).moduleTarget();
|
||||||
if (target != null)
|
if (target != null)
|
||||||
checkTargetConstraints(mn, target);
|
checkTargetPlatform(mn, target);
|
||||||
}
|
}
|
||||||
|
|
||||||
nameToReference.put(mn, mref);
|
nameToReference.put(mn, mref);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check that the module's constraints on the target platform do not
|
* Check that the module's constraints on the target platform does
|
||||||
* conflict with the constraints of other modules resolved so far or
|
* conflict with the constraint of other modules resolved so far.
|
||||||
* modules in parent configurations.
|
|
||||||
*/
|
*/
|
||||||
private void checkTargetConstraints(String mn, ModuleTarget target) {
|
private void checkTargetPlatform(String mn, ModuleTarget target) {
|
||||||
String value = target.osName();
|
String value = target.targetPlatform();
|
||||||
if (value != null) {
|
if (value != null) {
|
||||||
if (osName == null) {
|
if (targetPlatform == null) {
|
||||||
osName = value;
|
targetPlatform = value;
|
||||||
} else {
|
} else {
|
||||||
if (!value.equals(osName)) {
|
if (!value.equals(targetPlatform)) {
|
||||||
failTargetConstraint(mn, target);
|
findFail("Module %s has constraints on target platform (%s)"
|
||||||
}
|
+ " that conflict with other modules: %s", mn,
|
||||||
}
|
value, targetPlatform);
|
||||||
}
|
|
||||||
value = target.osArch();
|
|
||||||
if (value != null) {
|
|
||||||
if (osArch == null) {
|
|
||||||
osArch = value;
|
|
||||||
} else {
|
|
||||||
if (!value.equals(osArch)) {
|
|
||||||
failTargetConstraint(mn, target);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void failTargetConstraint(String mn, ModuleTarget target) {
|
|
||||||
String s1 = targetAsString(osName, osArch);
|
|
||||||
String s2 = targetAsString(target.osName(), target.osArch());
|
|
||||||
findFail("Module %s has constraints on target platform (%s) that"
|
|
||||||
+ " conflict with other modules: %s", mn, s1, s2);
|
|
||||||
}
|
|
||||||
|
|
||||||
private String targetAsString(ModuleTarget target) {
|
|
||||||
return targetAsString(target.osName(), target.osArch());
|
|
||||||
}
|
|
||||||
|
|
||||||
private String targetAsString(String osName, String osArch) {
|
|
||||||
return new StringJoiner("-")
|
|
||||||
.add(Objects.toString(osName, "*"))
|
|
||||||
.add(Objects.toString(osArch, "*"))
|
|
||||||
.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Execute post-resolution checks and returns the module graph of resolved
|
* Execute post-resolution checks and returns the module graph of resolved
|
||||||
* modules as {@code Map}. The resolved modules will be in the given
|
* modules as {@code Map}. The resolved modules will be in the given
|
||||||
@ -412,12 +361,6 @@ final class Resolver {
|
|||||||
Map<ResolvedModule, Set<ResolvedModule>> finish(Configuration cf,
|
Map<ResolvedModule, Set<ResolvedModule>> finish(Configuration cf,
|
||||||
boolean check)
|
boolean check)
|
||||||
{
|
{
|
||||||
if (isTracing()) {
|
|
||||||
trace("Result:");
|
|
||||||
Set<String> names = nameToReference.keySet();
|
|
||||||
names.stream().sorted().forEach(name -> trace(" %s", name));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (check) {
|
if (check) {
|
||||||
detectCycles();
|
detectCycles();
|
||||||
checkHashes();
|
checkHashes();
|
||||||
@ -520,9 +463,8 @@ final class Resolver {
|
|||||||
findFail("Unable to compute the hash of module %s", dn);
|
findFail("Unable to compute the hash of module %s", dn);
|
||||||
}
|
}
|
||||||
|
|
||||||
// skip checking the hash if the module has been patched
|
|
||||||
ModuleReferenceImpl other = (ModuleReferenceImpl)mref2;
|
ModuleReferenceImpl other = (ModuleReferenceImpl)mref2;
|
||||||
if (other != null && !other.isPatched()) {
|
if (other != null) {
|
||||||
byte[] recordedHash = hashes.hashFor(dn);
|
byte[] recordedHash = hashes.hashFor(dn);
|
||||||
byte[] actualHash = other.computeHash(algorithm);
|
byte[] actualHash = other.computeHash(algorithm);
|
||||||
if (actualHash == null)
|
if (actualHash == null)
|
||||||
@ -965,9 +907,17 @@ final class Resolver {
|
|||||||
|
|
||||||
private void trace(String fmt, Object ... args) {
|
private void trace(String fmt, Object ... args) {
|
||||||
if (traceOutput != null) {
|
if (traceOutput != null) {
|
||||||
traceOutput.format("[Resolver] " + fmt, args);
|
traceOutput.format(fmt, args);
|
||||||
traceOutput.println();
|
traceOutput.println();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String nameAndInfo(ModuleReference mref) {
|
||||||
|
ModuleDescriptor descriptor = mref.descriptor();
|
||||||
|
StringBuilder sb = new StringBuilder(descriptor.name());
|
||||||
|
mref.location().ifPresent(uri -> sb.append(" " + uri));
|
||||||
|
if (descriptor.isAutomatic())
|
||||||
|
sb.append(" automatic");
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2007, 2015, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2007, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -36,6 +36,8 @@ import java.util.Map;
|
|||||||
import java.util.ServiceConfigurationError;
|
import java.util.ServiceConfigurationError;
|
||||||
import java.util.ServiceLoader;
|
import java.util.ServiceLoader;
|
||||||
|
|
||||||
|
import jdk.internal.misc.VM;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Factory methods for file systems. This class defines the {@link #getDefault
|
* Factory methods for file systems. This class defines the {@link #getDefault
|
||||||
* getDefault} method to get the default file system and factory methods to
|
* getDefault} method to get the default file system and factory methods to
|
||||||
@ -120,8 +122,8 @@ public final class FileSystems {
|
|||||||
|
|
||||||
// if the property java.nio.file.spi.DefaultFileSystemProvider is
|
// if the property java.nio.file.spi.DefaultFileSystemProvider is
|
||||||
// set then its value is the name of the default provider (or a list)
|
// set then its value is the name of the default provider (or a list)
|
||||||
String propValue = System
|
String prop = "java.nio.file.spi.DefaultFileSystemProvider";
|
||||||
.getProperty("java.nio.file.spi.DefaultFileSystemProvider");
|
String propValue = System.getProperty(prop);
|
||||||
if (propValue != null) {
|
if (propValue != null) {
|
||||||
for (String cn: propValue.split(",")) {
|
for (String cn: propValue.split(",")) {
|
||||||
try {
|
try {
|
||||||
@ -184,7 +186,7 @@ public final class FileSystems {
|
|||||||
* @return the default file system
|
* @return the default file system
|
||||||
*/
|
*/
|
||||||
public static FileSystem getDefault() {
|
public static FileSystem getDefault() {
|
||||||
if (jdk.internal.misc.VM.isBooted()) {
|
if (VM.isModuleSystemInited()) {
|
||||||
return DefaultFileSystemHolder.defaultFileSystem;
|
return DefaultFileSystemHolder.defaultFileSystem;
|
||||||
} else {
|
} else {
|
||||||
return BuiltinFileSystemHolder.builtinFileSystem;
|
return BuiltinFileSystemHolder.builtinFileSystem;
|
||||||
|
@ -172,12 +172,10 @@ public class BuiltinClassLoader
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Register a module this this class loader. This has the effect of making
|
* Register a module this class loader. This has the effect of making the
|
||||||
* the types in the module visible.
|
* types in the module visible.
|
||||||
*/
|
*/
|
||||||
public void loadModule(ModuleReference mref) {
|
public void loadModule(ModuleReference mref) {
|
||||||
assert !VM.isModuleSystemInited();
|
|
||||||
|
|
||||||
String mn = mref.descriptor().name();
|
String mn = mref.descriptor().name();
|
||||||
if (nameToModule.putIfAbsent(mn, mref) != null) {
|
if (nameToModule.putIfAbsent(mn, mref) != null) {
|
||||||
throw new InternalError(mn + " already defined to this loader");
|
throw new InternalError(mn + " already defined to this loader");
|
||||||
@ -191,6 +189,11 @@ public class BuiltinClassLoader
|
|||||||
+ other.mref().descriptor().name());
|
+ other.mref().descriptor().name());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// clear resources cache if VM is already initialized
|
||||||
|
if (VM.isModuleSystemInited() && resourceCache != null) {
|
||||||
|
resourceCache = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -355,7 +358,10 @@ public class BuiltinClassLoader
|
|||||||
private List<URL> findMiscResource(String name) throws IOException {
|
private List<URL> findMiscResource(String name) throws IOException {
|
||||||
SoftReference<Map<String, List<URL>>> ref = this.resourceCache;
|
SoftReference<Map<String, List<URL>>> ref = this.resourceCache;
|
||||||
Map<String, List<URL>> map = (ref != null) ? ref.get() : null;
|
Map<String, List<URL>> map = (ref != null) ? ref.get() : null;
|
||||||
if (map != null) {
|
if (map == null) {
|
||||||
|
map = new ConcurrentHashMap<>();
|
||||||
|
this.resourceCache = new SoftReference<>(map);
|
||||||
|
} else {
|
||||||
List<URL> urls = map.get(name);
|
List<URL> urls = map.get(name);
|
||||||
if (urls != null)
|
if (urls != null)
|
||||||
return urls;
|
return urls;
|
||||||
@ -381,23 +387,18 @@ public class BuiltinClassLoader
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result;
|
return (result != null) ? result : Collections.emptyList();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} catch (PrivilegedActionException pae) {
|
} catch (PrivilegedActionException pae) {
|
||||||
throw (IOException) pae.getCause();
|
throw (IOException) pae.getCause();
|
||||||
}
|
}
|
||||||
|
|
||||||
// only cache resources after all modules have been defined
|
// only cache resources after VM is fully initialized
|
||||||
if (VM.isModuleSystemInited()) {
|
if (VM.isModuleSystemInited()) {
|
||||||
if (map == null) {
|
|
||||||
map = new ConcurrentHashMap<>();
|
|
||||||
this.resourceCache = new SoftReference<>(map);
|
|
||||||
}
|
|
||||||
if (urls == null)
|
|
||||||
urls = Collections.emptyList();
|
|
||||||
map.putIfAbsent(name, urls);
|
map.putIfAbsent(name, urls);
|
||||||
}
|
}
|
||||||
|
|
||||||
return urls;
|
return urls;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,13 +25,11 @@
|
|||||||
|
|
||||||
package jdk.internal.misc;
|
package jdk.internal.misc;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.lang.annotation.Annotation;
|
import java.lang.annotation.Annotation;
|
||||||
import java.lang.module.ModuleDescriptor;
|
import java.lang.module.ModuleDescriptor;
|
||||||
import java.lang.reflect.Executable;
|
import java.lang.reflect.Executable;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.net.URL;
|
|
||||||
import java.security.AccessControlContext;
|
import java.security.AccessControlContext;
|
||||||
import java.security.ProtectionDomain;
|
import java.security.ProtectionDomain;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@ -156,12 +154,6 @@ public interface JavaLangAccess {
|
|||||||
*/
|
*/
|
||||||
Class<?> findBootstrapClassOrNull(ClassLoader cl, String name);
|
Class<?> findBootstrapClassOrNull(ClassLoader cl, String name);
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a URL to a resource with the given name in a module that is
|
|
||||||
* defined to the given class loader.
|
|
||||||
*/
|
|
||||||
URL findResource(ClassLoader cl, String moduleName, String name) throws IOException;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the Packages for the given class loader.
|
* Returns the Packages for the given class loader.
|
||||||
*/
|
*/
|
||||||
@ -177,6 +169,11 @@ public interface JavaLangAccess {
|
|||||||
*/
|
*/
|
||||||
String fastUUID(long lsb, long msb);
|
String fastUUID(long lsb, long msb);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Record the non-exported packages of the modules in the given layer
|
||||||
|
*/
|
||||||
|
void addNonExportedPackages(ModuleLayer layer);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Invalidate package access cache
|
* Invalidate package access cache
|
||||||
*/
|
*/
|
||||||
|
@ -25,6 +25,8 @@
|
|||||||
|
|
||||||
package jdk.internal.module;
|
package jdk.internal.module;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Utility class for checking module, package, and class names.
|
* Utility class for checking module, package, and class names.
|
||||||
*/
|
*/
|
||||||
@ -45,18 +47,17 @@ public final class Checks {
|
|||||||
int next;
|
int next;
|
||||||
int off = 0;
|
int off = 0;
|
||||||
while ((next = name.indexOf('.', off)) != -1) {
|
while ((next = name.indexOf('.', off)) != -1) {
|
||||||
if (isJavaIdentifier(name, off, (next - off)) == -1) {
|
String id = name.substring(off, next);
|
||||||
String id = name.substring(off, next);
|
if (!isJavaIdentifier(id)) {
|
||||||
throw new IllegalArgumentException(name + ": Invalid module name"
|
throw new IllegalArgumentException(name + ": Invalid module name"
|
||||||
+ ": '" + id + "' is not a Java identifier");
|
+ ": '" + id + "' is not a Java identifier");
|
||||||
}
|
}
|
||||||
off = next+1;
|
off = next+1;
|
||||||
}
|
}
|
||||||
int last = isJavaIdentifier(name, off, name.length() - off);
|
String last = name.substring(off);
|
||||||
if (last == -1) {
|
if (!isJavaIdentifier(last)) {
|
||||||
String id = name.substring(off);
|
|
||||||
throw new IllegalArgumentException(name + ": Invalid module name"
|
throw new IllegalArgumentException(name + ": Invalid module name"
|
||||||
+ ": '" + id + "' is not a Java identifier");
|
+ ": '" + last + "' is not a Java identifier");
|
||||||
}
|
}
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
@ -68,14 +69,13 @@ public final class Checks {
|
|||||||
int next;
|
int next;
|
||||||
int off = 0;
|
int off = 0;
|
||||||
while ((next = name.indexOf('.', off)) != -1) {
|
while ((next = name.indexOf('.', off)) != -1) {
|
||||||
if (isJavaIdentifier(name, off, (next - off)) == -1)
|
String id = name.substring(off, next);
|
||||||
|
if (!isJavaIdentifier(id))
|
||||||
return false;
|
return false;
|
||||||
off = next+1;
|
off = next+1;
|
||||||
}
|
}
|
||||||
int last = isJavaIdentifier(name, off, name.length() - off);
|
String last = name.substring(off);
|
||||||
if (last == -1)
|
return isJavaIdentifier(last);
|
||||||
return false;
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -144,12 +144,13 @@ public final class Checks {
|
|||||||
int next;
|
int next;
|
||||||
int off = 0;
|
int off = 0;
|
||||||
while ((next = name.indexOf('.', off)) != -1) {
|
while ((next = name.indexOf('.', off)) != -1) {
|
||||||
if (isJavaIdentifier(name, off, (next - off)) == -1)
|
String id = name.substring(off, next);
|
||||||
|
if (!isJavaIdentifier(id))
|
||||||
return false;
|
return false;
|
||||||
off = next+1;
|
off = next+1;
|
||||||
}
|
}
|
||||||
int count = name.length() - off;
|
String last = name.substring(off);
|
||||||
return (isJavaIdentifier(name, off, count) != -1);
|
return isJavaIdentifier(last);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -164,76 +165,99 @@ public final class Checks {
|
|||||||
int next;
|
int next;
|
||||||
int off = 0;
|
int off = 0;
|
||||||
while ((next = name.indexOf('.', off)) != -1) {
|
while ((next = name.indexOf('.', off)) != -1) {
|
||||||
if (isJavaIdentifier(name, off, (next - off)) == -1) {
|
String id = name.substring(off, next);
|
||||||
String id = name.substring(off, next);
|
if (!isJavaIdentifier(id)) {
|
||||||
throw new IllegalArgumentException(name + ": Invalid " + what
|
throw new IllegalArgumentException(name + ": Invalid " + what
|
||||||
+ ": '" + id + "' is not a Java identifier");
|
+ ": '" + id + "' is not a Java identifier");
|
||||||
}
|
}
|
||||||
off = next + 1;
|
off = next + 1;
|
||||||
}
|
}
|
||||||
if (isJavaIdentifier(name, off, name.length() - off) == -1) {
|
String last = name.substring(off);
|
||||||
String id = name.substring(off, name.length());
|
if (!isJavaIdentifier(last)) {
|
||||||
throw new IllegalArgumentException(name + ": Invalid " + what
|
throw new IllegalArgumentException(name + ": Invalid " + what
|
||||||
+ ": '" + id + "' is not a Java identifier");
|
+ ": '" + last + "' is not a Java identifier");
|
||||||
}
|
}
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns {@code true} if a given legal module name contains an identifier
|
* Returns true if the given char sequence is a legal Java identifier,
|
||||||
* that doesn't end with a Java letter.
|
* otherwise false.
|
||||||
*/
|
*/
|
||||||
public static boolean hasJavaIdentifierWithTrailingDigit(String name) {
|
private static boolean isJavaIdentifier(CharSequence cs) {
|
||||||
// quick scan to allow names that are just ASCII without digits
|
if (cs.length() == 0 || RESERVED.contains(cs))
|
||||||
boolean needToParse = false;
|
|
||||||
int i = 0;
|
|
||||||
while (i < name.length()) {
|
|
||||||
int c = name.charAt(i);
|
|
||||||
if (c > 0x7F || (c >= '0' && c <= '9')) {
|
|
||||||
needToParse = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
if (!needToParse)
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// slow path
|
int first = Character.codePointAt(cs, 0);
|
||||||
int next;
|
|
||||||
int off = 0;
|
|
||||||
while ((next = name.indexOf('.', off)) != -1) {
|
|
||||||
int last = isJavaIdentifier(name, off, (next - off));
|
|
||||||
if (!Character.isJavaIdentifierStart(last))
|
|
||||||
return true;
|
|
||||||
off = next+1;
|
|
||||||
}
|
|
||||||
int last = isJavaIdentifier(name, off, name.length() - off);
|
|
||||||
if (!Character.isJavaIdentifierStart(last))
|
|
||||||
return true;
|
|
||||||
return false;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if a char sequence is a legal Java identifier, returning the code
|
|
||||||
* point of the last character if legal or {@code -1} if not legal.
|
|
||||||
*/
|
|
||||||
private static int isJavaIdentifier(CharSequence cs, int offset, int count) {
|
|
||||||
if (count == 0)
|
|
||||||
return -1;
|
|
||||||
int first = Character.codePointAt(cs, offset);
|
|
||||||
if (!Character.isJavaIdentifierStart(first))
|
if (!Character.isJavaIdentifierStart(first))
|
||||||
return -1;
|
return false;
|
||||||
|
|
||||||
int cp = first;
|
|
||||||
int i = Character.charCount(first);
|
int i = Character.charCount(first);
|
||||||
while (i < count) {
|
while (i < cs.length()) {
|
||||||
cp = Character.codePointAt(cs, offset+i);
|
int cp = Character.codePointAt(cs, i);
|
||||||
if (!Character.isJavaIdentifierPart(cp))
|
if (!Character.isJavaIdentifierPart(cp))
|
||||||
return -1;
|
return false;
|
||||||
i += Character.charCount(cp);
|
i += Character.charCount(cp);
|
||||||
}
|
}
|
||||||
|
|
||||||
return cp;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// keywords, boolean and null literals, not allowed in identifiers
|
||||||
|
private static final Set<String> RESERVED = Set.of(
|
||||||
|
"abstract",
|
||||||
|
"assert",
|
||||||
|
"boolean",
|
||||||
|
"break",
|
||||||
|
"byte",
|
||||||
|
"case",
|
||||||
|
"catch",
|
||||||
|
"char",
|
||||||
|
"class",
|
||||||
|
"const",
|
||||||
|
"continue",
|
||||||
|
"default",
|
||||||
|
"do",
|
||||||
|
"double",
|
||||||
|
"else",
|
||||||
|
"enum",
|
||||||
|
"extends",
|
||||||
|
"final",
|
||||||
|
"finally",
|
||||||
|
"float",
|
||||||
|
"for",
|
||||||
|
"goto",
|
||||||
|
"if",
|
||||||
|
"implements",
|
||||||
|
"import",
|
||||||
|
"instanceof",
|
||||||
|
"int",
|
||||||
|
"interface",
|
||||||
|
"long",
|
||||||
|
"native",
|
||||||
|
"new",
|
||||||
|
"package",
|
||||||
|
"private",
|
||||||
|
"protected",
|
||||||
|
"public",
|
||||||
|
"return",
|
||||||
|
"short",
|
||||||
|
"static",
|
||||||
|
"strictfp",
|
||||||
|
"super",
|
||||||
|
"switch",
|
||||||
|
"synchronized",
|
||||||
|
"this",
|
||||||
|
"throw",
|
||||||
|
"throws",
|
||||||
|
"transient",
|
||||||
|
"try",
|
||||||
|
"void",
|
||||||
|
"volatile",
|
||||||
|
"while",
|
||||||
|
"true",
|
||||||
|
"false",
|
||||||
|
"null",
|
||||||
|
"_"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
@ -549,34 +549,26 @@ public final class ClassFileAttributes {
|
|||||||
* u2 attribute_name_index;
|
* u2 attribute_name_index;
|
||||||
* u4 attribute_length;
|
* u4 attribute_length;
|
||||||
*
|
*
|
||||||
* // index to CONSTANT_utf8_info structure with the OS name
|
* // index to CONSTANT_utf8_info structure with the target platform
|
||||||
* u2 os_name_index;
|
* u2 target_platform_index;
|
||||||
* // index to CONSTANT_utf8_info structure with the OS arch
|
|
||||||
* u2 os_arch_index
|
|
||||||
* }
|
* }
|
||||||
*
|
*
|
||||||
* } </pre>
|
* } </pre>
|
||||||
*/
|
*/
|
||||||
public static class ModuleTargetAttribute extends Attribute {
|
public static class ModuleTargetAttribute extends Attribute {
|
||||||
private final String osName;
|
private final String targetPlatform;
|
||||||
private final String osArch;
|
|
||||||
|
|
||||||
public ModuleTargetAttribute(String osName, String osArch) {
|
public ModuleTargetAttribute(String targetPlatform) {
|
||||||
super(MODULE_TARGET);
|
super(MODULE_TARGET);
|
||||||
this.osName = osName;
|
this.targetPlatform = targetPlatform;
|
||||||
this.osArch = osArch;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public ModuleTargetAttribute() {
|
public ModuleTargetAttribute() {
|
||||||
this(null, null);
|
this(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String osName() {
|
public String targetPlatform() {
|
||||||
return osName;
|
return targetPlatform;
|
||||||
}
|
|
||||||
|
|
||||||
public String osArch() {
|
|
||||||
return osArch;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -588,20 +580,14 @@ public final class ClassFileAttributes {
|
|||||||
Label[] labels)
|
Label[] labels)
|
||||||
{
|
{
|
||||||
|
|
||||||
String osName = null;
|
String targetPlatform = null;
|
||||||
String osArch = null;
|
|
||||||
|
|
||||||
int name_index = cr.readUnsignedShort(off);
|
int target_platform_index = cr.readUnsignedShort(off);
|
||||||
if (name_index != 0)
|
if (target_platform_index != 0)
|
||||||
osName = cr.readUTF8(off, buf);
|
targetPlatform = cr.readUTF8(off, buf);
|
||||||
off += 2;
|
off += 2;
|
||||||
|
|
||||||
int arch_index = cr.readUnsignedShort(off);
|
return new ModuleTargetAttribute(targetPlatform);
|
||||||
if (arch_index != 0)
|
|
||||||
osArch = cr.readUTF8(off, buf);
|
|
||||||
off += 2;
|
|
||||||
|
|
||||||
return new ModuleTargetAttribute(osName, osArch);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -613,15 +599,10 @@ public final class ClassFileAttributes {
|
|||||||
{
|
{
|
||||||
ByteVector attr = new ByteVector();
|
ByteVector attr = new ByteVector();
|
||||||
|
|
||||||
int name_index = 0;
|
int target_platform_index = 0;
|
||||||
if (osName != null && osName.length() > 0)
|
if (targetPlatform != null && targetPlatform.length() > 0)
|
||||||
name_index = cw.newUTF8(osName);
|
target_platform_index = cw.newUTF8(targetPlatform);
|
||||||
attr.putShort(name_index);
|
attr.putShort(target_platform_index);
|
||||||
|
|
||||||
int arch_index = 0;
|
|
||||||
if (osArch != null && osArch.length() > 0)
|
|
||||||
arch_index = cw.newUTF8(osArch);
|
|
||||||
attr.putShort(arch_index);
|
|
||||||
|
|
||||||
return attr;
|
return attr;
|
||||||
}
|
}
|
||||||
|
@ -84,8 +84,9 @@ public final class ModuleBootstrap {
|
|||||||
// The ModulePatcher for the initial configuration
|
// The ModulePatcher for the initial configuration
|
||||||
private static final ModulePatcher patcher = initModulePatcher();
|
private static final ModulePatcher patcher = initModulePatcher();
|
||||||
|
|
||||||
// ModuleFinder for the initial configuration
|
// ModuleFinders for the initial configuration
|
||||||
private static ModuleFinder initialFinder;
|
private static ModuleFinder unlimitedFinder;
|
||||||
|
private static ModuleFinder limitedFinder;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the ModulePatcher for the initial configuration.
|
* Returns the ModulePatcher for the initial configuration.
|
||||||
@ -95,11 +96,20 @@ public final class ModuleBootstrap {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the ModuleFinder for the initial configuration
|
* Returns the ModuleFinder for the initial configuration before observability
|
||||||
|
* is limited by the --limit-modules command line option.
|
||||||
*/
|
*/
|
||||||
public static ModuleFinder finder() {
|
public static ModuleFinder unlimitedFinder() {
|
||||||
assert initialFinder != null;
|
assert unlimitedFinder != null;
|
||||||
return initialFinder;
|
return unlimitedFinder;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the ModuleFinder for the initial configuration.
|
||||||
|
*/
|
||||||
|
public static ModuleFinder limitedFinder() {
|
||||||
|
assert limitedFinder != null;
|
||||||
|
return limitedFinder;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -134,6 +144,11 @@ public final class ModuleBootstrap {
|
|||||||
|
|
||||||
PerfCounters.defineBaseTime.addElapsedTimeFrom(t1);
|
PerfCounters.defineBaseTime.addElapsedTimeFrom(t1);
|
||||||
|
|
||||||
|
// special mode to boot with only java.base, ignores other options
|
||||||
|
String propValue = getAndRemoveProperty("jdk.module.minimumBoot");
|
||||||
|
if (propValue != null) {
|
||||||
|
return createMinimalBootLayer();
|
||||||
|
}
|
||||||
|
|
||||||
long t2 = System.nanoTime();
|
long t2 = System.nanoTime();
|
||||||
|
|
||||||
@ -180,7 +195,8 @@ public final class ModuleBootstrap {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// --limit-modules
|
// --limit-modules
|
||||||
String propValue = getAndRemoveProperty("jdk.module.limitmods");
|
unlimitedFinder = finder;
|
||||||
|
propValue = getAndRemoveProperty("jdk.module.limitmods");
|
||||||
if (propValue != null) {
|
if (propValue != null) {
|
||||||
Set<String> mods = new HashSet<>();
|
Set<String> mods = new HashSet<>();
|
||||||
for (String mod: propValue.split(",")) {
|
for (String mod: propValue.split(",")) {
|
||||||
@ -188,6 +204,7 @@ public final class ModuleBootstrap {
|
|||||||
}
|
}
|
||||||
finder = limitFinder(finder, mods, roots);
|
finder = limitFinder(finder, mods, roots);
|
||||||
}
|
}
|
||||||
|
limitedFinder = finder;
|
||||||
|
|
||||||
// If there is no initial module specified then assume that the initial
|
// If there is no initial module specified then assume that the initial
|
||||||
// module is the unnamed module of the application class loader. This
|
// module is the unnamed module of the application class loader. This
|
||||||
@ -267,7 +284,8 @@ public final class ModuleBootstrap {
|
|||||||
}
|
}
|
||||||
|
|
||||||
PrintStream traceOutput = null;
|
PrintStream traceOutput = null;
|
||||||
if (Boolean.getBoolean("jdk.launcher.traceResolver"))
|
propValue = getAndRemoveProperty("jdk.module.showModuleResolution");
|
||||||
|
if (propValue != null && Boolean.parseBoolean(propValue))
|
||||||
traceOutput = System.out;
|
traceOutput = System.out;
|
||||||
|
|
||||||
// run the resolver to create the configuration
|
// run the resolver to create the configuration
|
||||||
@ -362,12 +380,23 @@ public final class ModuleBootstrap {
|
|||||||
// total time to initialize
|
// total time to initialize
|
||||||
PerfCounters.bootstrapTime.addElapsedTimeFrom(t0);
|
PerfCounters.bootstrapTime.addElapsedTimeFrom(t0);
|
||||||
|
|
||||||
// remember the ModuleFinder
|
|
||||||
initialFinder = finder;
|
|
||||||
|
|
||||||
return bootLayer;
|
return bootLayer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a "minimal" boot module layer that only contains java.base.
|
||||||
|
*/
|
||||||
|
private static ModuleLayer createMinimalBootLayer() {
|
||||||
|
Configuration cf = SharedSecrets.getJavaLangModuleAccess()
|
||||||
|
.resolveAndBind(ModuleFinder.ofSystem(),
|
||||||
|
Set.of(JAVA_BASE),
|
||||||
|
false,
|
||||||
|
null);
|
||||||
|
|
||||||
|
Function<String, ClassLoader> clf = ModuleLoaderMap.mappingFunction(cf);
|
||||||
|
return ModuleLayer.empty().defineModules(cf, clf);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a ModuleFinder that limits observability to the given root
|
* Returns a ModuleFinder that limits observability to the given root
|
||||||
* modules, their transitive dependences, plus a set of other modules.
|
* modules, their transitive dependences, plus a set of other modules.
|
||||||
|
@ -138,7 +138,7 @@ public class ModuleHashesBuilder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Utilty class
|
* Utility class
|
||||||
*/
|
*/
|
||||||
static class Graph<T> {
|
static class Graph<T> {
|
||||||
private final Set<T> nodes;
|
private final Set<T> nodes;
|
||||||
|
@ -546,21 +546,15 @@ public final class ModuleInfo {
|
|||||||
private ModuleTarget readModuleTargetAttribute(DataInput in, ConstantPool cpool)
|
private ModuleTarget readModuleTargetAttribute(DataInput in, ConstantPool cpool)
|
||||||
throws IOException
|
throws IOException
|
||||||
{
|
{
|
||||||
String osName = null;
|
String targetPlatform = null;
|
||||||
String osArch = null;
|
|
||||||
|
|
||||||
int name_index = in.readUnsignedShort();
|
int index = in.readUnsignedShort();
|
||||||
if (name_index != 0)
|
if (index != 0)
|
||||||
osName = cpool.getUtf8(name_index);
|
targetPlatform = cpool.getUtf8(index);
|
||||||
|
|
||||||
int arch_index = in.readUnsignedShort();
|
return new ModuleTarget(targetPlatform);
|
||||||
if (arch_index != 0)
|
|
||||||
osArch = cpool.getUtf8(arch_index);
|
|
||||||
|
|
||||||
return new ModuleTarget(osName, osArch);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reads the ModuleHashes attribute
|
* Reads the ModuleHashes attribute
|
||||||
*/
|
*/
|
||||||
@ -612,7 +606,6 @@ public final class ModuleInfo {
|
|||||||
return new ModuleResolution(flags);
|
return new ModuleResolution(flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if the given attribute can be present at most once
|
* Returns true if the given attribute can be present at most once
|
||||||
* in the class file. Returns false otherwise.
|
* in the class file. Returns false otherwise.
|
||||||
|
@ -62,9 +62,8 @@ public final class ModuleInfoExtender {
|
|||||||
// the value of the ModuleMainClass attribute
|
// the value of the ModuleMainClass attribute
|
||||||
private String mainClass;
|
private String mainClass;
|
||||||
|
|
||||||
// the values for the ModuleTarget attribute
|
// the value for the ModuleTarget attribute
|
||||||
private String osName;
|
private String targetPlatform;
|
||||||
private String osArch;
|
|
||||||
|
|
||||||
// the hashes for the ModuleHashes attribute
|
// the hashes for the ModuleHashes attribute
|
||||||
private ModuleHashes hashes;
|
private ModuleHashes hashes;
|
||||||
@ -108,11 +107,10 @@ public final class ModuleInfoExtender {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the values for the ModuleTarget attribute.
|
* Sets the value for the ModuleTarget attribute.
|
||||||
*/
|
*/
|
||||||
public ModuleInfoExtender targetPlatform(String osName, String osArch) {
|
public ModuleInfoExtender targetPlatform(String targetPlatform) {
|
||||||
this.osName = osName;
|
this.targetPlatform = targetPlatform;
|
||||||
this.osArch = osArch;
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -199,8 +197,8 @@ public final class ModuleInfoExtender {
|
|||||||
cv.addAttribute(new ModulePackagesAttribute(packages));
|
cv.addAttribute(new ModulePackagesAttribute(packages));
|
||||||
if (mainClass != null)
|
if (mainClass != null)
|
||||||
cv.addAttribute(new ModuleMainClassAttribute(mainClass));
|
cv.addAttribute(new ModuleMainClassAttribute(mainClass));
|
||||||
if (osName != null || osArch != null)
|
if (targetPlatform != null)
|
||||||
cv.addAttribute(new ModuleTargetAttribute(osName, osArch));
|
cv.addAttribute(new ModuleTargetAttribute(targetPlatform));
|
||||||
if (hashes != null)
|
if (hashes != null)
|
||||||
cv.addAttribute(new ModuleHashesAttribute(hashes));
|
cv.addAttribute(new ModuleHashesAttribute(hashes));
|
||||||
if (moduleResolution != null)
|
if (moduleResolution != null)
|
||||||
|
@ -66,10 +66,9 @@ public final class ModuleInfoWriter {
|
|||||||
// write ModuleMainClass if the module has a main class
|
// write ModuleMainClass if the module has a main class
|
||||||
md.mainClass().ifPresent(mc -> cw.visitAttribute(new ModuleMainClassAttribute(mc)));
|
md.mainClass().ifPresent(mc -> cw.visitAttribute(new ModuleMainClassAttribute(mc)));
|
||||||
|
|
||||||
// write ModuleTarget if there is a platform OS/arch
|
// write ModuleTarget if there is a target platform
|
||||||
if (target != null) {
|
if (target != null) {
|
||||||
cw.visitAttribute(new ModuleTargetAttribute(target.osName(),
|
cw.visitAttribute(new ModuleTargetAttribute(target.targetPlatform()));
|
||||||
target.osArch()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cw.visitEnd();
|
cw.visitEnd();
|
||||||
|
@ -37,36 +37,66 @@ import jdk.internal.loader.ClassLoaders;
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The module to class loader map. The list of boot modules and platform modules
|
* Supports the mapping of modules to class loaders. The set of modules mapped
|
||||||
* are generated at build time.
|
* to the boot and platform class loaders is generated at build time from
|
||||||
|
* this source file.
|
||||||
*/
|
*/
|
||||||
final class ModuleLoaderMap {
|
public final class ModuleLoaderMap {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Maps the system modules to the built-in class loaders.
|
||||||
|
*/
|
||||||
|
public static final class Mapper implements Function<String, ClassLoader> {
|
||||||
|
private final Map<String, ClassLoader> map;
|
||||||
|
|
||||||
|
Mapper(Map<String, ClassLoader> map) {
|
||||||
|
this.map = map; // defensive copy not needed
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ClassLoader apply(String name) {
|
||||||
|
return map.get(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the names of the modules defined to the boot loader.
|
||||||
|
*/
|
||||||
|
public static Set<String> bootModules() {
|
||||||
|
// The list of boot modules generated at build time.
|
||||||
|
String[] BOOT_MODULES = new String[] { "@@BOOT_MODULE_NAMES@@" };
|
||||||
|
Set<String> bootModules = new HashSet<>(BOOT_MODULES.length);
|
||||||
|
for (String mn : BOOT_MODULES) {
|
||||||
|
bootModules.add(mn);
|
||||||
|
}
|
||||||
|
return bootModules;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the names of the modules defined to the platform loader.
|
||||||
|
*/
|
||||||
|
public static Set<String> platformModules() {
|
||||||
|
// The list of platform modules generated at build time.
|
||||||
|
String[] PLATFORM_MODULES = new String[] { "@@PLATFORM_MODULE_NAMES@@" };
|
||||||
|
Set<String> platformModules = new HashSet<>(PLATFORM_MODULES.length);
|
||||||
|
for (String mn : PLATFORM_MODULES) {
|
||||||
|
platformModules.add(mn);
|
||||||
|
}
|
||||||
|
return platformModules;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the function to map modules in the given configuration to the
|
* Returns the function to map modules in the given configuration to the
|
||||||
* built-in class loaders.
|
* built-in class loaders.
|
||||||
*/
|
*/
|
||||||
static Function<String, ClassLoader> mappingFunction(Configuration cf) {
|
static Function<String, ClassLoader> mappingFunction(Configuration cf) {
|
||||||
|
Set<String> bootModules = bootModules();
|
||||||
// The list of boot modules and platform modules are generated at build time.
|
Set<String> platformModules = platformModules();
|
||||||
final String[] BOOT_MODULES = new String[] { "@@BOOT_MODULE_NAMES@@" };
|
|
||||||
final String[] PLATFORM_MODULES = new String[] { "@@PLATFORM_MODULE_NAMES@@" };
|
|
||||||
|
|
||||||
Set<String> bootModules = new HashSet<>(BOOT_MODULES.length);
|
|
||||||
for (String mn : BOOT_MODULES) {
|
|
||||||
bootModules.add(mn);
|
|
||||||
}
|
|
||||||
|
|
||||||
Set<String> platformModules = new HashSet<>(PLATFORM_MODULES.length);
|
|
||||||
for (String mn : PLATFORM_MODULES) {
|
|
||||||
platformModules.add(mn);
|
|
||||||
}
|
|
||||||
|
|
||||||
ClassLoader platformClassLoader = ClassLoaders.platformClassLoader();
|
ClassLoader platformClassLoader = ClassLoaders.platformClassLoader();
|
||||||
ClassLoader appClassLoader = ClassLoaders.appClassLoader();
|
ClassLoader appClassLoader = ClassLoaders.appClassLoader();
|
||||||
|
|
||||||
Map<String, ClassLoader> map = new HashMap<>();
|
Map<String, ClassLoader> map = new HashMap<>();
|
||||||
|
|
||||||
for (ResolvedModule resolvedModule : cf.modules()) {
|
for (ResolvedModule resolvedModule : cf.modules()) {
|
||||||
String mn = resolvedModule.name();
|
String mn = resolvedModule.name();
|
||||||
if (!bootModules.contains(mn)) {
|
if (!bootModules.contains(mn)) {
|
||||||
@ -77,12 +107,6 @@ final class ModuleLoaderMap {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return new Mapper(map);
|
||||||
return new Function<String, ClassLoader> () {
|
|
||||||
@Override
|
|
||||||
public ClassLoader apply(String mn) {
|
|
||||||
return map.get(mn);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -120,7 +120,7 @@ public final class ModulePatcher {
|
|||||||
|
|
||||||
// JAR file - do not open as a multi-release JAR as this
|
// JAR file - do not open as a multi-release JAR as this
|
||||||
// is not supported by the boot class loader
|
// is not supported by the boot class loader
|
||||||
try (JarFile jf = new JarFile(file.toFile())) {
|
try (JarFile jf = new JarFile(file.toString())) {
|
||||||
jf.stream()
|
jf.stream()
|
||||||
.filter(e -> !e.isDirectory()
|
.filter(e -> !e.isDirectory()
|
||||||
&& (!isAutomatic || e.getName().endsWith(".class")))
|
&& (!isAutomatic || e.getName().endsWith(".class")))
|
||||||
@ -431,7 +431,7 @@ public final class ModulePatcher {
|
|||||||
private final URL csURL;
|
private final URL csURL;
|
||||||
|
|
||||||
JarResourceFinder(Path path) throws IOException {
|
JarResourceFinder(Path path) throws IOException {
|
||||||
this.jf = new JarFile(path.toFile());
|
this.jf = new JarFile(path.toString());
|
||||||
this.csURL = path.toUri().toURL();
|
this.csURL = path.toUri().toURL();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -505,7 +505,7 @@ public final class ModulePatcher {
|
|||||||
public Resource find(String name) throws IOException {
|
public Resource find(String name) throws IOException {
|
||||||
Path file = Resources.toFilePath(dir, name);
|
Path file = Resources.toFilePath(dir, name);
|
||||||
if (file != null) {
|
if (file != null) {
|
||||||
return newResource(name, dir, file);
|
return newResource(name, dir, file);
|
||||||
} else {
|
} else {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -59,6 +59,7 @@ import java.util.jar.Manifest;
|
|||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.zip.ZipException;
|
||||||
import java.util.zip.ZipFile;
|
import java.util.zip.ZipFile;
|
||||||
|
|
||||||
import jdk.internal.jmod.JmodFile;
|
import jdk.internal.jmod.JmodFile;
|
||||||
@ -315,26 +316,42 @@ public class ModulePath implements ModuleFinder {
|
|||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
|
|
||||||
|
// exploded module
|
||||||
if (attrs.isDirectory()) {
|
if (attrs.isDirectory()) {
|
||||||
return readExplodedModule(entry); // may return null
|
return readExplodedModule(entry); // may return null
|
||||||
} else {
|
}
|
||||||
|
|
||||||
|
// JAR or JMOD file
|
||||||
|
if (attrs.isRegularFile()) {
|
||||||
String fn = entry.getFileName().toString();
|
String fn = entry.getFileName().toString();
|
||||||
if (attrs.isRegularFile()) {
|
boolean isDefaultFileSystem = isDefaultFileSystem(entry);
|
||||||
if (fn.endsWith(".jar")) {
|
|
||||||
|
// JAR file
|
||||||
|
if (fn.endsWith(".jar")) {
|
||||||
|
if (isDefaultFileSystem) {
|
||||||
return readJar(entry);
|
return readJar(entry);
|
||||||
} else if (isLinkPhase && fn.endsWith(".jmod")) {
|
} else {
|
||||||
return readJMod(entry);
|
// the JAR file is in a custom file system so
|
||||||
|
// need to copy it to the local file system
|
||||||
|
Path tmpdir = Files.createTempDirectory("mlib");
|
||||||
|
Path target = Files.copy(entry, tmpdir.resolve(fn));
|
||||||
|
return readJar(target);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null;
|
|
||||||
|
// JMOD file
|
||||||
|
if (isDefaultFileSystem && isLinkPhase && fn.endsWith(".jmod")) {
|
||||||
|
return readJMod(entry);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
|
||||||
} catch (InvalidModuleDescriptorException e) {
|
} catch (InvalidModuleDescriptorException e) {
|
||||||
throw new FindException("Error reading module: " + entry, e);
|
throw new FindException("Error reading module: " + entry, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a string with the file name of the module if possible.
|
* Returns a string with the file name of the module if possible.
|
||||||
* If the module location is not a file URI then return the URI
|
* If the module location is not a file URI then return the URI
|
||||||
@ -434,7 +451,7 @@ public class ModulePath implements ModuleFinder {
|
|||||||
* 3. The contents of any META-INF/services configuration files are mapped
|
* 3. The contents of any META-INF/services configuration files are mapped
|
||||||
* to "provides" declarations
|
* to "provides" declarations
|
||||||
* 4. The Main-Class attribute in the main attributes of the JAR manifest
|
* 4. The Main-Class attribute in the main attributes of the JAR manifest
|
||||||
* is mapped to the module descriptor mainClass
|
* is mapped to the module descriptor mainClass if possible
|
||||||
*/
|
*/
|
||||||
private ModuleDescriptor deriveModuleDescriptor(JarFile jf)
|
private ModuleDescriptor deriveModuleDescriptor(JarFile jf)
|
||||||
throws IOException
|
throws IOException
|
||||||
@ -530,12 +547,12 @@ public class ModulePath implements ModuleFinder {
|
|||||||
String mainClass = attrs.getValue(Attributes.Name.MAIN_CLASS);
|
String mainClass = attrs.getValue(Attributes.Name.MAIN_CLASS);
|
||||||
if (mainClass != null) {
|
if (mainClass != null) {
|
||||||
mainClass = mainClass.replace("/", ".");
|
mainClass = mainClass.replace("/", ".");
|
||||||
String pn = packageName(mainClass);
|
if (Checks.isClassName(mainClass)) {
|
||||||
if (!packages.contains(pn)) {
|
String pn = packageName(mainClass);
|
||||||
String msg = "Main-Class " + mainClass + " not in module";
|
if (packages.contains(pn)) {
|
||||||
throw new InvalidModuleDescriptorException(msg);
|
builder.mainClass(mainClass);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
builder.mainClass(mainClass);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -617,6 +634,8 @@ public class ModulePath implements ModuleFinder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return ModuleReferences.newJarModule(attrs, patcher, file);
|
return ModuleReferences.newJarModule(attrs, patcher, file);
|
||||||
|
} catch (ZipException e) {
|
||||||
|
throw new FindException("Error reading " + file, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -733,6 +752,16 @@ public class ModulePath implements ModuleFinder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return true if a path locates a path in the default file system
|
||||||
|
*/
|
||||||
|
private boolean isDefaultFileSystem(Path path) {
|
||||||
|
return path.getFileSystem().provider()
|
||||||
|
.getScheme().equalsIgnoreCase("file");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private static final PerfCounter scanTime
|
private static final PerfCounter scanTime
|
||||||
= PerfCounter.newPerfCounter("jdk.module.finder.modulepath.scanTime");
|
= PerfCounter.newPerfCounter("jdk.module.finder.modulepath.scanTime");
|
||||||
private static final PerfCounter moduleCount
|
private static final PerfCounter moduleCount
|
||||||
|
@ -25,6 +25,7 @@
|
|||||||
|
|
||||||
package jdk.internal.module;
|
package jdk.internal.module;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
import java.io.IOError;
|
import java.io.IOError;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
@ -226,8 +227,8 @@ class ModuleReferences {
|
|||||||
|
|
||||||
static JarFile newJarFile(Path path) {
|
static JarFile newJarFile(Path path) {
|
||||||
try {
|
try {
|
||||||
return new JarFile(path.toFile(),
|
return new JarFile(new File(path.toString()),
|
||||||
true, // verify
|
true, // verify
|
||||||
ZipFile.OPEN_READ,
|
ZipFile.OPEN_READ,
|
||||||
JarFile.runtimeVersion());
|
JarFile.runtimeVersion());
|
||||||
} catch (IOException ioe) {
|
} catch (IOException ioe) {
|
||||||
|
@ -39,6 +39,10 @@ public final class ModuleResolution {
|
|||||||
this.value = value;
|
this.value = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int value() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
public static ModuleResolution empty() {
|
public static ModuleResolution empty() {
|
||||||
return new ModuleResolution(0);
|
return new ModuleResolution(0);
|
||||||
}
|
}
|
||||||
@ -74,35 +78,30 @@ public final class ModuleResolution {
|
|||||||
throw new InternalError("cannot add deprecated for removal to " + value);
|
throw new InternalError("cannot add deprecated for removal to " + value);
|
||||||
return new ModuleResolution(value | WARN_DEPRECATED_FOR_REMOVAL);
|
return new ModuleResolution(value | WARN_DEPRECATED_FOR_REMOVAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ModuleResolution withIncubating() {
|
public ModuleResolution withIncubating() {
|
||||||
if ((value & (WARN_DEPRECATED | WARN_DEPRECATED_FOR_REMOVAL)) != 0)
|
if ((value & (WARN_DEPRECATED | WARN_DEPRECATED_FOR_REMOVAL)) != 0)
|
||||||
throw new InternalError("cannot add incubating to " + value);
|
throw new InternalError("cannot add incubating to " + value);
|
||||||
return new ModuleResolution(value | WARN_INCUBATING);
|
return new ModuleResolution(value | WARN_INCUBATING);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int value() {
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean doNotResolveByDefault(ModuleReference mref) {
|
public static boolean doNotResolveByDefault(ModuleReference mref) {
|
||||||
// get the DO_NOT_RESOLVE_BY_DEFAULT flag, if any
|
// get the DO_NOT_RESOLVE_BY_DEFAULT flag, if any
|
||||||
if (!(mref instanceof ModuleReferenceImpl))
|
if (mref instanceof ModuleReferenceImpl) {
|
||||||
return false;
|
ModuleResolution mres = ((ModuleReferenceImpl) mref).moduleResolution();
|
||||||
|
if (mres != null)
|
||||||
ModuleResolution mres = ((ModuleReferenceImpl)mref).moduleResolution();
|
return mres.doNotResolveByDefault();
|
||||||
if (mres != null)
|
}
|
||||||
return mres.doNotResolveByDefault();
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean hasIncubatingWarning(ModuleReference mref) {
|
public static boolean hasIncubatingWarning(ModuleReference mref) {
|
||||||
if (!(mref instanceof ModuleReferenceImpl))
|
if (mref instanceof ModuleReferenceImpl) {
|
||||||
return false;
|
ModuleResolution mres = ((ModuleReferenceImpl) mref).moduleResolution();
|
||||||
|
if (mres != null)
|
||||||
ModuleResolution mres = ((ModuleReferenceImpl)mref).moduleResolution();
|
return mres.hasIncubatingWarning();
|
||||||
if (mres != null)
|
}
|
||||||
return mres.hasIncubatingWarning();
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -25,22 +25,21 @@
|
|||||||
|
|
||||||
package jdk.internal.module;
|
package jdk.internal.module;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents the module target.
|
||||||
|
*
|
||||||
|
* For now, this is a single value for the target platform, e.g. "linux-x64".
|
||||||
|
*/
|
||||||
public final class ModuleTarget {
|
public final class ModuleTarget {
|
||||||
|
|
||||||
private final String osName;
|
private final String targetPlatform;
|
||||||
private final String osArch;
|
|
||||||
|
|
||||||
public ModuleTarget(String osName, String osArch) {
|
public ModuleTarget(String targetPlatform) {
|
||||||
this.osName = osName;
|
this.targetPlatform = targetPlatform;
|
||||||
this.osArch = osArch;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public String osName() {
|
public String targetPlatform() {
|
||||||
return osName;
|
return targetPlatform;
|
||||||
}
|
|
||||||
|
|
||||||
public String osArch() {
|
|
||||||
return osArch;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -25,12 +25,22 @@
|
|||||||
|
|
||||||
package jdk.internal.module;
|
package jdk.internal.module;
|
||||||
|
|
||||||
|
import java.lang.module.Configuration;
|
||||||
import java.lang.module.ModuleDescriptor;
|
import java.lang.module.ModuleDescriptor;
|
||||||
|
import java.lang.module.ModuleFinder;
|
||||||
|
import java.lang.module.ModuleReference;
|
||||||
|
import java.lang.module.ResolvedModule;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.security.AccessController;
|
import java.security.AccessController;
|
||||||
import java.security.PrivilegedAction;
|
import java.security.PrivilegedAction;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.function.Function;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import jdk.internal.loader.BootLoader;
|
import jdk.internal.loader.BootLoader;
|
||||||
|
import jdk.internal.loader.BuiltinClassLoader;
|
||||||
import jdk.internal.loader.ClassLoaders;
|
import jdk.internal.loader.ClassLoaders;
|
||||||
import jdk.internal.misc.JavaLangAccess;
|
import jdk.internal.misc.JavaLangAccess;
|
||||||
import jdk.internal.misc.SharedSecrets;
|
import jdk.internal.misc.SharedSecrets;
|
||||||
@ -38,8 +48,8 @@ import jdk.internal.misc.SharedSecrets;
|
|||||||
/**
|
/**
|
||||||
* A helper class for creating and updating modules. This class is intended to
|
* A helper class for creating and updating modules. This class is intended to
|
||||||
* support command-line options, tests, and the instrumentation API. It is also
|
* support command-line options, tests, and the instrumentation API. It is also
|
||||||
* used by the VM to add read edges when agents are instrumenting code that
|
* used by the VM to load modules or add read edges when agents are instrumenting
|
||||||
* need to link to supporting classes.
|
* code that need to link to supporting classes.
|
||||||
*
|
*
|
||||||
* The parameters that are package names in this API are the fully-qualified
|
* The parameters that are package names in this API are the fully-qualified
|
||||||
* names of the packages as defined in section 6.5.3 of <cite>The Java™
|
* names of the packages as defined in section 6.5.3 of <cite>The Java™
|
||||||
@ -154,4 +164,90 @@ public class Modules {
|
|||||||
addReads(m, BootLoader.getUnnamedModule());
|
addReads(m, BootLoader.getUnnamedModule());
|
||||||
addReads(m, ClassLoaders.appClassLoader().getUnnamedModule());
|
addReads(m, ClassLoaders.appClassLoader().getUnnamedModule());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called by the VM to load a system module, typically "java.instrument" or
|
||||||
|
* "jdk.management.agent". If the module is not loaded then it is resolved
|
||||||
|
* and loaded (along with any dependences that weren't previously loaded)
|
||||||
|
* into a child layer.
|
||||||
|
*/
|
||||||
|
public static synchronized Module loadModule(String name) {
|
||||||
|
ModuleLayer top = topLayer;
|
||||||
|
if (top == null)
|
||||||
|
top = ModuleLayer.boot();
|
||||||
|
|
||||||
|
Module module = top.findModule(name).orElse(null);
|
||||||
|
if (module != null) {
|
||||||
|
// module already loaded
|
||||||
|
return module;
|
||||||
|
}
|
||||||
|
|
||||||
|
// resolve the module with the top-most layer as the parent
|
||||||
|
ModuleFinder empty = ModuleFinder.of();
|
||||||
|
ModuleFinder finder = ModuleBootstrap.unlimitedFinder();
|
||||||
|
Set<String> roots = Set.of(name);
|
||||||
|
Configuration cf = top.configuration().resolveAndBind(empty, finder, roots);
|
||||||
|
|
||||||
|
// create the child layer
|
||||||
|
Function<String, ClassLoader> clf = ModuleLoaderMap.mappingFunction(cf);
|
||||||
|
ModuleLayer newLayer = top.defineModules(cf, clf);
|
||||||
|
|
||||||
|
// add qualified exports/opens to give access to modules in child layer
|
||||||
|
Map<String, Module> map = newLayer.modules().stream()
|
||||||
|
.collect(Collectors.toMap(Module::getName,
|
||||||
|
Function.identity()));
|
||||||
|
ModuleLayer layer = top;
|
||||||
|
while (layer != null) {
|
||||||
|
for (Module m : layer.modules()) {
|
||||||
|
// qualified exports
|
||||||
|
m.getDescriptor().exports().stream()
|
||||||
|
.filter(ModuleDescriptor.Exports::isQualified)
|
||||||
|
.forEach(e -> e.targets().forEach(target -> {
|
||||||
|
Module other = map.get(target);
|
||||||
|
if (other != null) {
|
||||||
|
addExports(m, e.source(), other);
|
||||||
|
}}));
|
||||||
|
|
||||||
|
// qualified opens
|
||||||
|
m.getDescriptor().opens().stream()
|
||||||
|
.filter(ModuleDescriptor.Opens::isQualified)
|
||||||
|
.forEach(o -> o.targets().forEach(target -> {
|
||||||
|
Module other = map.get(target);
|
||||||
|
if (other != null) {
|
||||||
|
addOpens(m, o.source(), other);
|
||||||
|
}}));
|
||||||
|
}
|
||||||
|
|
||||||
|
List<ModuleLayer> parents = layer.parents();
|
||||||
|
assert parents.size() <= 1;
|
||||||
|
layer = parents.isEmpty() ? null : parents.get(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// update security manager before making types visible
|
||||||
|
JLA.addNonExportedPackages(newLayer);
|
||||||
|
|
||||||
|
// update the built-in class loaders to make the types visible
|
||||||
|
for (ResolvedModule resolvedModule : cf.modules()) {
|
||||||
|
ModuleReference mref = resolvedModule.reference();
|
||||||
|
String mn = mref.descriptor().name();
|
||||||
|
ClassLoader cl = clf.apply(mn);
|
||||||
|
if (cl == null) {
|
||||||
|
BootLoader.loadModule(mref);
|
||||||
|
} else {
|
||||||
|
((BuiltinClassLoader) cl).loadModule(mref);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// new top layer
|
||||||
|
topLayer = newLayer;
|
||||||
|
|
||||||
|
// return module
|
||||||
|
return newLayer.findModule(name)
|
||||||
|
.orElseThrow(() -> new InternalError("module not loaded"));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// the top-most system layer
|
||||||
|
private static ModuleLayer topLayer;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -26,10 +26,10 @@ package jdk.internal.module;
|
|||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.nio.file.FileSystem;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.NoSuchFileException;
|
import java.nio.file.NoSuchFileException;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.nio.file.Paths;
|
|
||||||
import java.nio.file.attribute.BasicFileAttributes;
|
import java.nio.file.attribute.BasicFileAttributes;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -94,7 +94,7 @@ public final class Resources {
|
|||||||
if (expectDirectory) {
|
if (expectDirectory) {
|
||||||
name = name.substring(0, name.length() - 1); // drop trailing "/"
|
name = name.substring(0, name.length() - 1); // drop trailing "/"
|
||||||
}
|
}
|
||||||
Path path = toSafeFilePath(name);
|
Path path = toSafeFilePath(dir.getFileSystem(), name);
|
||||||
if (path != null) {
|
if (path != null) {
|
||||||
Path file = dir.resolve(path);
|
Path file = dir.resolve(path);
|
||||||
try {
|
try {
|
||||||
@ -116,7 +116,7 @@ public final class Resources {
|
|||||||
* are rejected, as are resource names that translates to a file path
|
* are rejected, as are resource names that translates to a file path
|
||||||
* with a root component.
|
* with a root component.
|
||||||
*/
|
*/
|
||||||
private static Path toSafeFilePath(String name) {
|
private static Path toSafeFilePath(FileSystem fs, String name) {
|
||||||
// scan elements of resource name
|
// scan elements of resource name
|
||||||
int next;
|
int next;
|
||||||
int off = 0;
|
int off = 0;
|
||||||
@ -135,12 +135,12 @@ public final class Resources {
|
|||||||
// convert to file path
|
// convert to file path
|
||||||
Path path;
|
Path path;
|
||||||
if (File.separatorChar == '/') {
|
if (File.separatorChar == '/') {
|
||||||
path = Paths.get(name);
|
path = fs.getPath(name);
|
||||||
} else {
|
} else {
|
||||||
// not allowed to embed file separators
|
// not allowed to embed file separators
|
||||||
if (name.contains(File.separator))
|
if (name.contains(File.separator))
|
||||||
return null;
|
return null;
|
||||||
path = Paths.get(name.replace('/', File.separatorChar));
|
path = fs.getPath(name.replace('/', File.separatorChar));
|
||||||
}
|
}
|
||||||
|
|
||||||
// file path not allowed to have root component
|
// file path not allowed to have root component
|
||||||
|
@ -161,6 +161,7 @@ module java.base {
|
|||||||
java.security.jgss,
|
java.security.jgss,
|
||||||
java.sql,
|
java.sql,
|
||||||
java.xml,
|
java.xml,
|
||||||
|
jdk.attach,
|
||||||
jdk.charsets,
|
jdk.charsets,
|
||||||
jdk.compiler, // reflective dependency
|
jdk.compiler, // reflective dependency
|
||||||
jdk.incubator.httpclient,
|
jdk.incubator.httpclient,
|
||||||
|
@ -43,13 +43,17 @@ import java.io.File;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.PrintStream;
|
import java.io.PrintStream;
|
||||||
import java.io.UnsupportedEncodingException;
|
import java.io.UnsupportedEncodingException;
|
||||||
import java.lang.module.ModuleFinder;
|
import java.lang.module.Configuration;
|
||||||
import java.lang.module.ModuleReference;
|
import java.lang.module.FindException;
|
||||||
import java.lang.module.ModuleDescriptor;
|
import java.lang.module.ModuleDescriptor;
|
||||||
import java.lang.module.ModuleDescriptor.Requires;
|
import java.lang.module.ModuleDescriptor.Requires;
|
||||||
import java.lang.module.ModuleDescriptor.Exports;
|
import java.lang.module.ModuleDescriptor.Exports;
|
||||||
import java.lang.module.ModuleDescriptor.Opens;
|
import java.lang.module.ModuleDescriptor.Opens;
|
||||||
import java.lang.module.ModuleDescriptor.Provides;
|
import java.lang.module.ModuleDescriptor.Provides;
|
||||||
|
import java.lang.module.ModuleFinder;
|
||||||
|
import java.lang.module.ModuleReference;
|
||||||
|
import java.lang.module.ResolvedModule;
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.lang.reflect.Modifier;
|
import java.lang.reflect.Modifier;
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
@ -58,14 +62,16 @@ import java.net.URI;
|
|||||||
import java.nio.charset.Charset;
|
import java.nio.charset.Charset;
|
||||||
import java.nio.file.DirectoryStream;
|
import java.nio.file.DirectoryStream;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.NoSuchFileException;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.Paths;
|
||||||
|
import java.nio.file.attribute.BasicFileAttributes;
|
||||||
import java.text.Normalizer;
|
import java.text.Normalizer;
|
||||||
import java.text.MessageFormat;
|
import java.text.MessageFormat;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.HashSet;
|
import java.util.HashMap;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
@ -83,6 +89,7 @@ import java.util.stream.Collectors;
|
|||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
import jdk.internal.misc.VM;
|
import jdk.internal.misc.VM;
|
||||||
|
import jdk.internal.module.ModuleBootstrap;
|
||||||
import jdk.internal.module.Modules;
|
import jdk.internal.module.Modules;
|
||||||
|
|
||||||
|
|
||||||
@ -98,6 +105,7 @@ public final class LauncherHelper {
|
|||||||
"javafx.application.Application";
|
"javafx.application.Application";
|
||||||
private static final String JAVAFX_FXHELPER_CLASS_NAME_SUFFIX =
|
private static final String JAVAFX_FXHELPER_CLASS_NAME_SUFFIX =
|
||||||
"sun.launcher.LauncherHelper$FXHelper";
|
"sun.launcher.LauncherHelper$FXHelper";
|
||||||
|
private static final String LAUNCHER_AGENT_CLASS = "Launcher-Agent-Class";
|
||||||
private static final String MAIN_CLASS = "Main-Class";
|
private static final String MAIN_CLASS = "Main-Class";
|
||||||
private static final String ADD_EXPORTS = "Add-Exports";
|
private static final String ADD_EXPORTS = "Add-Exports";
|
||||||
private static final String ADD_OPENS = "Add-Opens";
|
private static final String ADD_OPENS = "Add-Opens";
|
||||||
@ -408,8 +416,12 @@ public final class LauncherHelper {
|
|||||||
ostream = (printToStderr) ? System.err : System.out;
|
ostream = (printToStderr) ? System.err : System.out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void initOutput(PrintStream ps) {
|
||||||
|
ostream = ps;
|
||||||
|
}
|
||||||
|
|
||||||
static String getMainClassFromJar(String jarname) {
|
static String getMainClassFromJar(String jarname) {
|
||||||
String mainValue = null;
|
String mainValue;
|
||||||
try (JarFile jarFile = new JarFile(jarname)) {
|
try (JarFile jarFile = new JarFile(jarname)) {
|
||||||
Manifest manifest = jarFile.getManifest();
|
Manifest manifest = jarFile.getManifest();
|
||||||
if (manifest == null) {
|
if (manifest == null) {
|
||||||
@ -426,6 +438,22 @@ public final class LauncherHelper {
|
|||||||
abort(null, "java.launcher.jar.error3", jarname);
|
abort(null, "java.launcher.jar.error3", jarname);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Launcher-Agent-Class (only check for this when Main-Class present)
|
||||||
|
String agentClass = mainAttrs.getValue(LAUNCHER_AGENT_CLASS);
|
||||||
|
if (agentClass != null) {
|
||||||
|
ModuleLayer.boot().findModule("java.instrument").ifPresent(m -> {
|
||||||
|
try {
|
||||||
|
String cn = "sun.instrument.InstrumentationImpl";
|
||||||
|
Class<?> clazz = Class.forName(cn, false, null);
|
||||||
|
Method loadAgent = clazz.getMethod("loadAgent", String.class);
|
||||||
|
loadAgent.invoke(null, jarname);
|
||||||
|
} catch (Throwable e) {
|
||||||
|
if (e instanceof InvocationTargetException) e = e.getCause();
|
||||||
|
abort(e, "java.launcher.jar.error4", jarname);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// Add-Exports and Add-Opens
|
// Add-Exports and Add-Opens
|
||||||
String exports = mainAttrs.getValue(ADD_EXPORTS);
|
String exports = mainAttrs.getValue(ADD_EXPORTS);
|
||||||
if (exports != null) {
|
if (exports != null) {
|
||||||
@ -913,141 +941,350 @@ public final class LauncherHelper {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void formatCommaList(PrintStream out,
|
|
||||||
String prefix,
|
|
||||||
Collection<?> list)
|
|
||||||
{
|
|
||||||
if (list.isEmpty())
|
|
||||||
return;
|
|
||||||
out.format("%s", prefix);
|
|
||||||
boolean first = true;
|
|
||||||
for (Object ob : list) {
|
|
||||||
if (first) {
|
|
||||||
out.format(" %s", ob);
|
|
||||||
first = false;
|
|
||||||
} else {
|
|
||||||
out.format(", %s", ob);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
out.format("%n");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called by the launcher to list the observable modules.
|
* Called by the launcher to list the observable modules.
|
||||||
* If called without any sub-options then the output is a simple list of
|
|
||||||
* the modules. If called with sub-options then the sub-options are the
|
|
||||||
* names of the modules to list (e.g. --list-modules java.base,java.desktop)
|
|
||||||
*/
|
*/
|
||||||
static void listModules(boolean printToStderr, String optionFlag)
|
static void listModules() {
|
||||||
throws IOException, ClassNotFoundException
|
initOutput(System.out);
|
||||||
{
|
|
||||||
initOutput(printToStderr);
|
|
||||||
|
|
||||||
ModuleFinder finder = jdk.internal.module.ModuleBootstrap.finder();
|
ModuleBootstrap.limitedFinder().findAll().stream()
|
||||||
int colon = optionFlag.indexOf('=');
|
.sorted(new JrtFirstComparator())
|
||||||
if (colon == -1) {
|
.forEach(LauncherHelper::showModule);
|
||||||
finder.findAll().stream()
|
|
||||||
.sorted(Comparator.comparing(ModuleReference::descriptor))
|
|
||||||
.forEach(mref -> describeModule(finder, mref, false));
|
|
||||||
} else {
|
|
||||||
String[] names = optionFlag.substring(colon+1).split(",");
|
|
||||||
for (String name: names) {
|
|
||||||
ModuleReference mref = finder.find(name).orElse(null);
|
|
||||||
if (mref == null) {
|
|
||||||
System.err.format("%s not found%n", name);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
describeModule(finder, mref, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Describes the given module.
|
* Called by the launcher to show the resolved modules
|
||||||
*/
|
*/
|
||||||
static void describeModule(ModuleFinder finder,
|
static void showResolvedModules() {
|
||||||
ModuleReference mref,
|
initOutput(System.out);
|
||||||
boolean verbose)
|
|
||||||
{
|
|
||||||
ModuleDescriptor md = mref.descriptor();
|
|
||||||
ostream.print("module " + midAndLocation(md, mref.location()));
|
|
||||||
if (md.isAutomatic())
|
|
||||||
ostream.print(" automatic");
|
|
||||||
ostream.println();
|
|
||||||
|
|
||||||
if (!verbose)
|
ModuleLayer bootLayer = ModuleLayer.boot();
|
||||||
return;
|
Configuration cf = bootLayer.configuration();
|
||||||
|
|
||||||
|
cf.modules().stream()
|
||||||
|
.map(ResolvedModule::reference)
|
||||||
|
.sorted(new JrtFirstComparator())
|
||||||
|
.forEach(LauncherHelper::showModule);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called by the launcher to describe a module
|
||||||
|
*/
|
||||||
|
static void describeModule(String moduleName) {
|
||||||
|
initOutput(System.out);
|
||||||
|
|
||||||
|
ModuleFinder finder = ModuleBootstrap.limitedFinder();
|
||||||
|
ModuleReference mref = finder.find(moduleName).orElse(null);
|
||||||
|
if (mref == null) {
|
||||||
|
abort(null, "java.launcher.module.error4", moduleName);
|
||||||
|
}
|
||||||
|
ModuleDescriptor md = mref.descriptor();
|
||||||
|
|
||||||
|
// one-line summary
|
||||||
|
showModule(mref);
|
||||||
|
|
||||||
// unqualified exports (sorted by package)
|
// unqualified exports (sorted by package)
|
||||||
Set<Exports> exports = new TreeSet<>(Comparator.comparing(Exports::source));
|
md.exports().stream()
|
||||||
md.exports().stream().filter(e -> !e.isQualified()).forEach(exports::add);
|
.filter(e -> !e.isQualified())
|
||||||
for (Exports e : exports) {
|
.sorted(Comparator.comparing(Exports::source))
|
||||||
String modsAndSource = Stream.concat(toStringStream(e.modifiers()),
|
.map(e -> Stream.concat(Stream.of(e.source()),
|
||||||
Stream.of(e.source()))
|
toStringStream(e.modifiers()))
|
||||||
|
.collect(Collectors.joining(" ")))
|
||||||
|
.forEach(sourceAndMods -> ostream.format("exports %s%n", sourceAndMods));
|
||||||
|
|
||||||
|
// dependences
|
||||||
|
for (Requires r : md.requires()) {
|
||||||
|
String nameAndMods = Stream.concat(Stream.of(r.name()),
|
||||||
|
toStringStream(r.modifiers()))
|
||||||
.collect(Collectors.joining(" "));
|
.collect(Collectors.joining(" "));
|
||||||
ostream.format(" exports %s%n", modsAndSource);
|
ostream.format("requires %s", nameAndMods);
|
||||||
|
finder.find(r.name())
|
||||||
|
.map(ModuleReference::descriptor)
|
||||||
|
.filter(ModuleDescriptor::isAutomatic)
|
||||||
|
.ifPresent(any -> ostream.print(" automatic"));
|
||||||
|
ostream.println();
|
||||||
}
|
}
|
||||||
|
|
||||||
for (Requires d : md.requires()) {
|
// service use and provides
|
||||||
ostream.format(" requires %s", d);
|
|
||||||
String suffix = finder.find(d.name())
|
|
||||||
.map(ModuleReference::descriptor)
|
|
||||||
.map(any -> any.isAutomatic() ? " automatic" : "")
|
|
||||||
.orElse(" not found");
|
|
||||||
ostream.println(suffix);
|
|
||||||
}
|
|
||||||
for (String s : md.uses()) {
|
for (String s : md.uses()) {
|
||||||
ostream.format(" uses %s%n", s);
|
ostream.format("uses %s%n", s);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (Provides ps : md.provides()) {
|
for (Provides ps : md.provides()) {
|
||||||
ostream.format(" provides %s with %s%n", ps.service(),
|
String names = ps.providers().stream().collect(Collectors.joining(" "));
|
||||||
ps.providers().stream().collect(Collectors.joining(", ")));
|
ostream.format("provides %s with %s%n", ps.service(), names);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// qualified exports
|
// qualified exports
|
||||||
for (Exports e : md.exports()) {
|
for (Exports e : md.exports()) {
|
||||||
if (e.isQualified()) {
|
if (e.isQualified()) {
|
||||||
String modsAndSource = Stream.concat(toStringStream(e.modifiers()),
|
String who = e.targets().stream().collect(Collectors.joining(" "));
|
||||||
Stream.of(e.source()))
|
ostream.format("qualified exports %s to %s%n", e.source(), who);
|
||||||
.collect(Collectors.joining(" "));
|
|
||||||
ostream.format(" exports %s", modsAndSource);
|
|
||||||
formatCommaList(ostream, " to", e.targets());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// open packages
|
// open packages
|
||||||
for (Opens obj: md.opens()) {
|
for (Opens opens: md.opens()) {
|
||||||
String modsAndSource = Stream.concat(toStringStream(obj.modifiers()),
|
if (opens.isQualified())
|
||||||
Stream.of(obj.source()))
|
ostream.print("qualified ");
|
||||||
|
String sourceAndMods = Stream.concat(Stream.of(opens.source()),
|
||||||
|
toStringStream(opens.modifiers()))
|
||||||
.collect(Collectors.joining(" "));
|
.collect(Collectors.joining(" "));
|
||||||
ostream.format(" opens %s", modsAndSource);
|
ostream.format("opens %s", sourceAndMods);
|
||||||
if (obj.isQualified())
|
if (opens.isQualified()) {
|
||||||
formatCommaList(ostream, " to", obj.targets());
|
String who = opens.targets().stream().collect(Collectors.joining(" "));
|
||||||
else
|
ostream.format(" to %s", who);
|
||||||
ostream.println();
|
}
|
||||||
|
ostream.println();
|
||||||
}
|
}
|
||||||
|
|
||||||
// non-exported/non-open packages
|
// non-exported/non-open packages
|
||||||
Set<String> concealed = new TreeSet<>(md.packages());
|
Set<String> concealed = new TreeSet<>(md.packages());
|
||||||
md.exports().stream().map(Exports::source).forEach(concealed::remove);
|
md.exports().stream().map(Exports::source).forEach(concealed::remove);
|
||||||
md.opens().stream().map(Opens::source).forEach(concealed::remove);
|
md.opens().stream().map(Opens::source).forEach(concealed::remove);
|
||||||
concealed.forEach(p -> ostream.format(" contains %s%n", p));
|
concealed.forEach(p -> ostream.format("contains %s%n", p));
|
||||||
}
|
}
|
||||||
|
|
||||||
static <T> String toString(Set<T> s) {
|
/**
|
||||||
return toStringStream(s).collect(Collectors.joining(" "));
|
* Prints a single line with the module name, version and modifiers
|
||||||
|
*/
|
||||||
|
private static void showModule(ModuleReference mref) {
|
||||||
|
ModuleDescriptor md = mref.descriptor();
|
||||||
|
ostream.print(md.toNameAndVersion());
|
||||||
|
mref.location()
|
||||||
|
.filter(uri -> !isJrt(uri))
|
||||||
|
.ifPresent(uri -> ostream.format(" %s", uri));
|
||||||
|
if (md.isOpen())
|
||||||
|
ostream.print(" open");
|
||||||
|
if (md.isAutomatic())
|
||||||
|
ostream.print(" automatic");
|
||||||
|
ostream.println();
|
||||||
}
|
}
|
||||||
|
|
||||||
static <T> Stream<String> toStringStream(Set<T> s) {
|
/**
|
||||||
|
* A ModuleReference comparator that considers modules in the run-time
|
||||||
|
* image to be less than modules than not in the run-time image.
|
||||||
|
*/
|
||||||
|
private static class JrtFirstComparator implements Comparator<ModuleReference> {
|
||||||
|
private final Comparator<ModuleReference> real;
|
||||||
|
|
||||||
|
JrtFirstComparator() {
|
||||||
|
this.real = Comparator.comparing(ModuleReference::descriptor);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compare(ModuleReference a, ModuleReference b) {
|
||||||
|
if (isJrt(a)) {
|
||||||
|
return isJrt(b) ? real.compare(a, b) : -1;
|
||||||
|
} else {
|
||||||
|
return isJrt(b) ? 1 : real.compare(a, b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static <T> Stream<String> toStringStream(Set<T> s) {
|
||||||
return s.stream().map(e -> e.toString().toLowerCase());
|
return s.stream().map(e -> e.toString().toLowerCase());
|
||||||
}
|
}
|
||||||
|
|
||||||
static String midAndLocation(ModuleDescriptor md, Optional<URI> location ) {
|
private static boolean isJrt(ModuleReference mref) {
|
||||||
URI loc = location.orElse(null);
|
return isJrt(mref.location().orElse(null));
|
||||||
if (loc == null || loc.getScheme().equalsIgnoreCase("jrt"))
|
}
|
||||||
return md.toNameAndVersion();
|
|
||||||
else
|
private static boolean isJrt(URI uri) {
|
||||||
return md.toNameAndVersion() + " (" + loc + ")";
|
return (uri != null && uri.getScheme().equalsIgnoreCase("jrt"));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called by the launcher to validate the modules on the upgrade and
|
||||||
|
* application module paths.
|
||||||
|
*
|
||||||
|
* @return {@code true} if no errors are found
|
||||||
|
*/
|
||||||
|
private static boolean validateModules() {
|
||||||
|
initOutput(System.out);
|
||||||
|
|
||||||
|
ModuleValidator validator = new ModuleValidator();
|
||||||
|
|
||||||
|
// upgrade module path
|
||||||
|
String value = System.getProperty("jdk.module.upgrade.path");
|
||||||
|
if (value != null) {
|
||||||
|
Stream.of(value.split(File.pathSeparator))
|
||||||
|
.map(Paths::get)
|
||||||
|
.forEach(validator::scan);
|
||||||
|
}
|
||||||
|
|
||||||
|
// system modules
|
||||||
|
ModuleFinder.ofSystem().findAll().stream()
|
||||||
|
.sorted(Comparator.comparing(ModuleReference::descriptor))
|
||||||
|
.forEach(validator::process);
|
||||||
|
|
||||||
|
// application module path
|
||||||
|
value = System.getProperty("jdk.module.path");
|
||||||
|
if (value != null) {
|
||||||
|
Stream.of(value.split(File.pathSeparator))
|
||||||
|
.map(Paths::get)
|
||||||
|
.forEach(validator::scan);
|
||||||
|
}
|
||||||
|
|
||||||
|
return !validator.foundErrors();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A simple validator to check for errors and conflicts between modules.
|
||||||
|
*/
|
||||||
|
static class ModuleValidator {
|
||||||
|
private static final String MODULE_INFO = "module-info.class";
|
||||||
|
|
||||||
|
private Map<String, ModuleReference> nameToModule = new HashMap<>();
|
||||||
|
private Map<String, ModuleReference> packageToModule = new HashMap<>();
|
||||||
|
private boolean errorFound;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if at least one error was found
|
||||||
|
*/
|
||||||
|
boolean foundErrors() {
|
||||||
|
return errorFound;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prints the module location and name.
|
||||||
|
*/
|
||||||
|
private void printModule(ModuleReference mref) {
|
||||||
|
mref.location()
|
||||||
|
.filter(uri -> !isJrt(uri))
|
||||||
|
.ifPresent(uri -> ostream.print(uri + " "));
|
||||||
|
ModuleDescriptor descriptor = mref.descriptor();
|
||||||
|
ostream.print(descriptor.name());
|
||||||
|
if (descriptor.isAutomatic())
|
||||||
|
ostream.print(" automatic");
|
||||||
|
ostream.println();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prints the module location and name, checks if the module is
|
||||||
|
* shadowed by a previously seen module, and finally checks for
|
||||||
|
* package conflicts with previously seen modules.
|
||||||
|
*/
|
||||||
|
void process(ModuleReference mref) {
|
||||||
|
printModule(mref);
|
||||||
|
|
||||||
|
String name = mref.descriptor().name();
|
||||||
|
ModuleReference previous = nameToModule.putIfAbsent(name, mref);
|
||||||
|
if (previous != null) {
|
||||||
|
ostream.print(INDENT + "shadowed by ");
|
||||||
|
printModule(previous);
|
||||||
|
} else {
|
||||||
|
// check for package conflicts when not shadowed
|
||||||
|
for (String pkg : mref.descriptor().packages()) {
|
||||||
|
previous = packageToModule.putIfAbsent(pkg, mref);
|
||||||
|
if (previous != null) {
|
||||||
|
String mn = previous.descriptor().name();
|
||||||
|
ostream.println(INDENT + "contains " + pkg
|
||||||
|
+ " conflicts with module " + mn);
|
||||||
|
errorFound = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Scan an element on a module path. The element is a directory
|
||||||
|
* of modules, an exploded module, or a JAR file.
|
||||||
|
*/
|
||||||
|
void scan(Path entry) {
|
||||||
|
BasicFileAttributes attrs;
|
||||||
|
try {
|
||||||
|
attrs = Files.readAttributes(entry, BasicFileAttributes.class);
|
||||||
|
} catch (NoSuchFileException ignore) {
|
||||||
|
return;
|
||||||
|
} catch (IOException ioe) {
|
||||||
|
ostream.println(entry + " " + ioe);
|
||||||
|
errorFound = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String fn = entry.getFileName().toString();
|
||||||
|
if (attrs.isRegularFile() && fn.endsWith(".jar")) {
|
||||||
|
// JAR file, explicit or automatic module
|
||||||
|
scanModule(entry).ifPresent(this::process);
|
||||||
|
} else if (attrs.isDirectory()) {
|
||||||
|
Path mi = entry.resolve(MODULE_INFO);
|
||||||
|
if (Files.exists(mi)) {
|
||||||
|
// exploded module
|
||||||
|
scanModule(entry).ifPresent(this::process);
|
||||||
|
} else {
|
||||||
|
// directory of modules
|
||||||
|
scanDirectory(entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Scan the JAR files and exploded modules in a directory.
|
||||||
|
*/
|
||||||
|
private void scanDirectory(Path dir) {
|
||||||
|
try (DirectoryStream<Path> stream = Files.newDirectoryStream(dir)) {
|
||||||
|
Map<String, Path> moduleToEntry = new HashMap<>();
|
||||||
|
|
||||||
|
for (Path entry : stream) {
|
||||||
|
BasicFileAttributes attrs;
|
||||||
|
try {
|
||||||
|
attrs = Files.readAttributes(entry, BasicFileAttributes.class);
|
||||||
|
} catch (IOException ioe) {
|
||||||
|
ostream.println(entry + " " + ioe);
|
||||||
|
errorFound = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
ModuleReference mref = null;
|
||||||
|
|
||||||
|
String fn = entry.getFileName().toString();
|
||||||
|
if (attrs.isRegularFile() && fn.endsWith(".jar")) {
|
||||||
|
mref = scanModule(entry).orElse(null);
|
||||||
|
} else if (attrs.isDirectory()) {
|
||||||
|
Path mi = entry.resolve(MODULE_INFO);
|
||||||
|
if (Files.exists(mi)) {
|
||||||
|
mref = scanModule(entry).orElse(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mref != null) {
|
||||||
|
String name = mref.descriptor().name();
|
||||||
|
Path previous = moduleToEntry.putIfAbsent(name, entry);
|
||||||
|
if (previous != null) {
|
||||||
|
// same name as other module in the directory
|
||||||
|
printModule(mref);
|
||||||
|
ostream.println(INDENT + "contains same module as "
|
||||||
|
+ previous.getFileName());
|
||||||
|
errorFound = true;
|
||||||
|
} else {
|
||||||
|
process(mref);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (IOException ioe) {
|
||||||
|
ostream.println(dir + " " + ioe);
|
||||||
|
errorFound = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Scan a JAR file or exploded module.
|
||||||
|
*/
|
||||||
|
private Optional<ModuleReference> scanModule(Path entry) {
|
||||||
|
ModuleFinder finder = ModuleFinder.of(entry);
|
||||||
|
try {
|
||||||
|
return finder.findAll().stream().findFirst();
|
||||||
|
} catch (FindException e) {
|
||||||
|
ostream.println(entry);
|
||||||
|
ostream.println(INDENT + e.getMessage());
|
||||||
|
Throwable cause = e.getCause();
|
||||||
|
if (cause != null) {
|
||||||
|
ostream.println(INDENT + cause);
|
||||||
|
}
|
||||||
|
errorFound = true;
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -53,26 +53,33 @@ java.launcher.opt.footer = \
|
|||||||
\ A {0} separated list of directories, each directory\n\
|
\ A {0} separated list of directories, each directory\n\
|
||||||
\ is a directory of modules that replace upgradeable\n\
|
\ is a directory of modules that replace upgradeable\n\
|
||||||
\ modules in the runtime image\n\
|
\ modules in the runtime image\n\
|
||||||
\ --add-modules <modulename>[,<modulename>...]\n\
|
\ --add-modules <module name>[,<module name>...]\n\
|
||||||
\ root modules to resolve in addition to the initial module.\n\
|
\ root modules to resolve in addition to the initial module.\n\
|
||||||
\ <modulename> can also be ALL-DEFAULT, ALL-SYSTEM,\n\
|
\ <module name> can also be ALL-DEFAULT, ALL-SYSTEM,\n\
|
||||||
\ ALL-MODULE-PATH.\n\
|
\ ALL-MODULE-PATH.\n\
|
||||||
\ --limit-modules <modulename>[,<modulename>...]\n\
|
\ --list-modules\n\
|
||||||
\ limit the universe of observable modules\n\
|
\ list observable modules and exit\n\
|
||||||
\ --list-modules [<modulename>[,<modulename>...]]\n\
|
\ --d <module name>\n\
|
||||||
\ list the observable modules and exit\n\
|
\ --describe-module <module name>\n\
|
||||||
\ --dry-run create VM but do not execute main method.\n\
|
\ describe a module and exit\n\
|
||||||
\ This --dry-run option may be useful for validating the\n\
|
\ --dry-run create VM and load main class but do not execute main method.\n\
|
||||||
|
\ The --dry-run option may be useful for validating the\n\
|
||||||
\ command-line options such as the module system configuration.\n\
|
\ command-line options such as the module system configuration.\n\
|
||||||
|
\ --validate-modules\n\
|
||||||
|
\ validate all modules and exit\n\
|
||||||
|
\ The --validate-modules option may be useful for finding\n\
|
||||||
|
\ conflicts and other errors with modules on the module path.\n\
|
||||||
\ -D<name>=<value>\n\
|
\ -D<name>=<value>\n\
|
||||||
\ set a system property\n\
|
\ set a system property\n\
|
||||||
\ -verbose:[class|gc|jni]\n\
|
\ -verbose:[class|module|gc|jni]\n\
|
||||||
\ enable verbose output\n\
|
\ enable verbose output\n\
|
||||||
\ -version print product version to the error stream and exit\n\
|
\ -version print product version to the error stream and exit\n\
|
||||||
\ --version print product version to the output stream and exit\n\
|
\ --version print product version to the output stream and exit\n\
|
||||||
\ -showversion print product version to the error stream and continue\n\
|
\ -showversion print product version to the error stream and continue\n\
|
||||||
\ --show-version\n\
|
\ --show-version\n\
|
||||||
\ print product version to the output stream and continue\n\
|
\ print product version to the output stream and continue\n\
|
||||||
|
\ --show-module-resolution\n\
|
||||||
|
\ show module resolution output during startup\n\
|
||||||
\ -? -h -help\n\
|
\ -? -h -help\n\
|
||||||
\ print this help message to the error stream\n\
|
\ print this help message to the error stream\n\
|
||||||
\ --help print this help message to the output stream\n\
|
\ --help print this help message to the output stream\n\
|
||||||
@ -119,7 +126,6 @@ java.launcher.X.usage=\n\
|
|||||||
\ -Xcomp forces compilation of methods on first invocation\n\
|
\ -Xcomp forces compilation of methods on first invocation\n\
|
||||||
\ -Xdebug provided for backward compatibility\n\
|
\ -Xdebug provided for backward compatibility\n\
|
||||||
\ -Xdiag show additional diagnostic messages\n\
|
\ -Xdiag show additional diagnostic messages\n\
|
||||||
\ -Xdiag:resolver show resolver diagnostic messages\n\
|
|
||||||
\ -Xfuture enable strictest checks, anticipating future default\n\
|
\ -Xfuture enable strictest checks, anticipating future default\n\
|
||||||
\ -Xint interpreted mode execution only\n\
|
\ -Xint interpreted mode execution only\n\
|
||||||
\ -Xinternalversion\n\
|
\ -Xinternalversion\n\
|
||||||
@ -164,10 +170,12 @@ java.launcher.X.usage=\n\
|
|||||||
\ permit illegal access to members of types in named modules\n\
|
\ permit illegal access to members of types in named modules\n\
|
||||||
\ by code in unnamed modules. This compatibility option will\n\
|
\ by code in unnamed modules. This compatibility option will\n\
|
||||||
\ be removed in the next release.\n\
|
\ be removed in the next release.\n\
|
||||||
\ --disable-@files disable further argument file expansion\n\
|
\ --limit-modules <module name>[,<module name>...]\n\
|
||||||
|
\ limit the universe of observable modules\n\
|
||||||
\ --patch-module <module>=<file>({0}<file>)*\n\
|
\ --patch-module <module>=<file>({0}<file>)*\n\
|
||||||
\ Override or augment a module with classes and resources\n\
|
\ override or augment a module with classes and resources\n\
|
||||||
\ in JAR files or directories.\n\n\
|
\ in JAR files or directories.\n\
|
||||||
|
\ --disable-@files disable further argument file expansion\n\n\
|
||||||
These extra options are subject to change without notice.\n
|
These extra options are subject to change without notice.\n
|
||||||
|
|
||||||
# Translators please note do not translate the options themselves
|
# Translators please note do not translate the options themselves
|
||||||
@ -204,6 +212,7 @@ java.launcher.jar.error1=\
|
|||||||
Error: An unexpected error occurred while trying to open file {0}
|
Error: An unexpected error occurred while trying to open file {0}
|
||||||
java.launcher.jar.error2=manifest not found in {0}
|
java.launcher.jar.error2=manifest not found in {0}
|
||||||
java.launcher.jar.error3=no main manifest attribute, in {0}
|
java.launcher.jar.error3=no main manifest attribute, in {0}
|
||||||
|
java.launcher.jar.error4=error loading java agent in {0}
|
||||||
java.launcher.init.error=initialization error
|
java.launcher.init.error=initialization error
|
||||||
java.launcher.javafx.error1=\
|
java.launcher.javafx.error1=\
|
||||||
Error: The JavaFX launchApplication method has the wrong signature, it\n\
|
Error: The JavaFX launchApplication method has the wrong signature, it\n\
|
||||||
@ -215,4 +224,5 @@ java.launcher.module.error2=\
|
|||||||
java.launcher.module.error3=\
|
java.launcher.module.error3=\
|
||||||
Error: Unable to load main class {0} from module {1}\n\
|
Error: Unable to load main class {0} from module {1}\n\
|
||||||
\t{2}
|
\t{2}
|
||||||
|
java.launcher.module.error4=\
|
||||||
|
{0} not found
|
||||||
|
@ -43,13 +43,14 @@
|
|||||||
#define ARG_ERROR2 "Error: %s requires jar file specification"
|
#define ARG_ERROR2 "Error: %s requires jar file specification"
|
||||||
#define ARG_ERROR3 "Error: The -J option should not be followed by a space."
|
#define ARG_ERROR3 "Error: The -J option should not be followed by a space."
|
||||||
#define ARG_ERROR4 "Error: %s requires module path specification"
|
#define ARG_ERROR4 "Error: %s requires module path specification"
|
||||||
#define ARG_ERROR5 "Error: %s requires module id"
|
#define ARG_ERROR5 "Error: %s requires module name"
|
||||||
#define ARG_ERROR6 "Error: %s requires modules to be specified"
|
#define ARG_ERROR6 "Error: %s requires modules to be specified"
|
||||||
#define ARG_ERROR7 "Error: %s can only be specified once"
|
#define ARG_ERROR7 "Error: %s can only be specified once"
|
||||||
#define ARG_ERROR8 "Error: Unmatched quote in environment variable %s"
|
#define ARG_ERROR8 "Error: Unmatched quote in environment variable %s"
|
||||||
#define ARG_ERROR9 "Error: Option %s is not allowed in environment variable %s"
|
#define ARG_ERROR9 "Error: Option %s is not allowed in environment variable %s"
|
||||||
#define ARG_ERROR10 "Error: Option %s in %s is not allowed in environment variable %s"
|
#define ARG_ERROR10 "Error: Option %s in %s is not allowed in environment variable %s"
|
||||||
#define ARG_ERROR11 "Error: Cannot specify main class in environment variable %s"
|
#define ARG_ERROR11 "Error: Cannot specify main class in environment variable %s"
|
||||||
|
#define ARG_ERROR12 "Error: %s requires module name"
|
||||||
|
|
||||||
#define JVM_ERROR1 "Error: Could not create the Java Virtual Machine.\n" GEN_ERROR
|
#define JVM_ERROR1 "Error: Could not create the Java Virtual Machine.\n" GEN_ERROR
|
||||||
#define JVM_ERROR2 "Error: Could not detach main thread.\n" JNI_ERROR
|
#define JVM_ERROR2 "Error: Could not detach main thread.\n" JNI_ERROR
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 1995, 2016, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 1995, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -71,7 +71,10 @@ static jboolean printTo = USE_STDERR; /* where to print version/usage */
|
|||||||
static jboolean printXUsage = JNI_FALSE; /* print and exit*/
|
static jboolean printXUsage = JNI_FALSE; /* print and exit*/
|
||||||
static jboolean dryRun = JNI_FALSE; /* initialize VM and exit */
|
static jboolean dryRun = JNI_FALSE; /* initialize VM and exit */
|
||||||
static char *showSettings = NULL; /* print but continue */
|
static char *showSettings = NULL; /* print but continue */
|
||||||
static char *listModules = NULL;
|
static jboolean showResolvedModules = JNI_FALSE;
|
||||||
|
static jboolean listModules = JNI_FALSE;
|
||||||
|
static char *describeModule = NULL;
|
||||||
|
static jboolean validateModules = JNI_FALSE;
|
||||||
|
|
||||||
static const char *_program_name;
|
static const char *_program_name;
|
||||||
static const char *_launcher_name;
|
static const char *_launcher_name;
|
||||||
@ -118,7 +121,10 @@ static void SetApplicationClassPath(const char**);
|
|||||||
static void PrintJavaVersion(JNIEnv *env, jboolean extraLF);
|
static void PrintJavaVersion(JNIEnv *env, jboolean extraLF);
|
||||||
static void PrintUsage(JNIEnv* env, jboolean doXUsage);
|
static void PrintUsage(JNIEnv* env, jboolean doXUsage);
|
||||||
static void ShowSettings(JNIEnv* env, char *optString);
|
static void ShowSettings(JNIEnv* env, char *optString);
|
||||||
static void ListModules(JNIEnv* env, char *optString);
|
static void ShowResolvedModules(JNIEnv* env);
|
||||||
|
static void ListModules(JNIEnv* env);
|
||||||
|
static void DescribeModule(JNIEnv* env, char* optString);
|
||||||
|
static jboolean ValidateModules(JNIEnv* env);
|
||||||
|
|
||||||
static void SetPaths(int argc, char **argv);
|
static void SetPaths(int argc, char **argv);
|
||||||
|
|
||||||
@ -409,9 +415,31 @@ JavaMain(void * _args)
|
|||||||
CHECK_EXCEPTION_LEAVE(1);
|
CHECK_EXCEPTION_LEAVE(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (listModules != NULL) {
|
// show resolved modules and continue
|
||||||
ListModules(env, listModules);
|
if (showResolvedModules) {
|
||||||
|
ShowResolvedModules(env);
|
||||||
CHECK_EXCEPTION_LEAVE(1);
|
CHECK_EXCEPTION_LEAVE(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// list observable modules, then exit
|
||||||
|
if (listModules) {
|
||||||
|
ListModules(env);
|
||||||
|
CHECK_EXCEPTION_LEAVE(1);
|
||||||
|
LEAVE();
|
||||||
|
}
|
||||||
|
|
||||||
|
// describe a module, then exit
|
||||||
|
if (describeModule != NULL) {
|
||||||
|
DescribeModule(env, describeModule);
|
||||||
|
CHECK_EXCEPTION_LEAVE(1);
|
||||||
|
LEAVE();
|
||||||
|
}
|
||||||
|
|
||||||
|
// validate modules on the module path, then exit
|
||||||
|
if (validateModules) {
|
||||||
|
jboolean okay = ValidateModules(env);
|
||||||
|
CHECK_EXCEPTION_LEAVE(1);
|
||||||
|
if (!okay) ret = 1;
|
||||||
LEAVE();
|
LEAVE();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -552,7 +580,8 @@ static jboolean
|
|||||||
IsLauncherOption(const char* name) {
|
IsLauncherOption(const char* name) {
|
||||||
return IsClassPathOption(name) ||
|
return IsClassPathOption(name) ||
|
||||||
IsLauncherMainOption(name) ||
|
IsLauncherMainOption(name) ||
|
||||||
JLI_StrCmp(name, "--list-modules") == 0;
|
JLI_StrCmp(name, "--describe-module") == 0 ||
|
||||||
|
JLI_StrCmp(name, "-d") == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1199,7 +1228,7 @@ GetOpt(int *pargc, char ***pargv, char **poption, char **pvalue) {
|
|||||||
|
|
||||||
} else if (JLI_StrCCmp(arg, "--") == 0 && (equals = JLI_StrChr(arg, '=')) != NULL) {
|
} else if (JLI_StrCCmp(arg, "--") == 0 && (equals = JLI_StrChr(arg, '=')) != NULL) {
|
||||||
value = equals+1;
|
value = equals+1;
|
||||||
if (JLI_StrCCmp(arg, "--list-modules=") == 0 ||
|
if (JLI_StrCCmp(arg, "--describe-module=") == 0 ||
|
||||||
JLI_StrCCmp(arg, "--module=") == 0 ||
|
JLI_StrCCmp(arg, "--module=") == 0 ||
|
||||||
JLI_StrCCmp(arg, "--class-path=") == 0) {
|
JLI_StrCCmp(arg, "--class-path=") == 0) {
|
||||||
kind = LAUNCHER_OPTION_WITH_ARGUMENT;
|
kind = LAUNCHER_OPTION_WITH_ARGUMENT;
|
||||||
@ -1263,18 +1292,18 @@ ParseArguments(int *pargc, char ***pargv,
|
|||||||
REPORT_ERROR (has_arg_any_len, ARG_ERROR1, arg);
|
REPORT_ERROR (has_arg_any_len, ARG_ERROR1, arg);
|
||||||
SetClassPath(value);
|
SetClassPath(value);
|
||||||
mode = LM_CLASS;
|
mode = LM_CLASS;
|
||||||
} else if (JLI_StrCmp(arg, "--list-modules") == 0 ||
|
} else if (JLI_StrCmp(arg, "--list-modules") == 0) {
|
||||||
JLI_StrCCmp(arg, "--list-modules=") == 0) {
|
listModules = JNI_TRUE;
|
||||||
listModules = arg;
|
} else if (JLI_StrCmp(arg, "--show-resolved-modules") == 0) {
|
||||||
|
showResolvedModules = JNI_TRUE;
|
||||||
// set listModules to --list-modules=<module-names> if argument is specified
|
} else if (JLI_StrCmp(arg, "--validate-modules") == 0) {
|
||||||
if (JLI_StrCmp(arg, "--list-modules") == 0 && has_arg) {
|
AddOption("-Djdk.module.minimumBoot=true", NULL);
|
||||||
static const char format[] = "%s=%s";
|
validateModules = JNI_TRUE;
|
||||||
size_t buflen = JLI_StrLen(option) + 2 + JLI_StrLen(value);
|
} else if (JLI_StrCmp(arg, "--describe-module") == 0 ||
|
||||||
listModules = JLI_MemAlloc(buflen);
|
JLI_StrCCmp(arg, "--describe-module=") == 0 ||
|
||||||
JLI_Snprintf(listModules, buflen, format, option, value);
|
JLI_StrCmp(arg, "-d") == 0) {
|
||||||
}
|
REPORT_ERROR (has_arg_any_len, ARG_ERROR12, arg);
|
||||||
return JNI_TRUE;
|
describeModule = value;
|
||||||
/*
|
/*
|
||||||
* Parse white-space options
|
* Parse white-space options
|
||||||
*/
|
*/
|
||||||
@ -1336,9 +1365,8 @@ ParseArguments(int *pargc, char ***pargv,
|
|||||||
showSettings = arg;
|
showSettings = arg;
|
||||||
} else if (JLI_StrCmp(arg, "-Xdiag") == 0) {
|
} else if (JLI_StrCmp(arg, "-Xdiag") == 0) {
|
||||||
AddOption("-Dsun.java.launcher.diag=true", NULL);
|
AddOption("-Dsun.java.launcher.diag=true", NULL);
|
||||||
AddOption("-Djdk.launcher.traceResolver=true", NULL);
|
} else if (JLI_StrCmp(arg, "--show-module-resolution") == 0) {
|
||||||
} else if (JLI_StrCmp(arg, "-Xdiag:resolver") == 0) {
|
AddOption("-Djdk.module.showModuleResolution=true", NULL);
|
||||||
AddOption("-Djdk.launcher.traceResolver=true", NULL);
|
|
||||||
/*
|
/*
|
||||||
* The following case provide backward compatibility with old-style
|
* The following case provide backward compatibility with old-style
|
||||||
* command line options.
|
* command line options.
|
||||||
@ -1399,7 +1427,10 @@ ParseArguments(int *pargc, char ***pargv,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (*pwhat == NULL) {
|
if (*pwhat == NULL) {
|
||||||
*pret = 1;
|
/* LM_UNKNOWN okay for options that exit */
|
||||||
|
if (!listModules && !describeModule && !validateModules) {
|
||||||
|
*pret = 1;
|
||||||
|
}
|
||||||
} else if (mode == LM_UNKNOWN) {
|
} else if (mode == LM_UNKNOWN) {
|
||||||
/* default to LM_CLASS if -m, -jar and -cp options are
|
/* default to LM_CLASS if -m, -jar and -cp options are
|
||||||
* not specified */
|
* not specified */
|
||||||
@ -1828,21 +1859,61 @@ ShowSettings(JNIEnv *env, char *optString)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* List modules supported by the runtime
|
* Show resolved modules
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
ListModules(JNIEnv *env, char *optString)
|
ShowResolvedModules(JNIEnv *env)
|
||||||
|
{
|
||||||
|
jmethodID showResolvedModulesID;
|
||||||
|
jclass cls = GetLauncherHelperClass(env);
|
||||||
|
NULL_CHECK(cls);
|
||||||
|
NULL_CHECK(showResolvedModulesID = (*env)->GetStaticMethodID(env, cls,
|
||||||
|
"showResolvedModules", "()V"));
|
||||||
|
(*env)->CallStaticVoidMethod(env, cls, showResolvedModulesID);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List observable modules
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
ListModules(JNIEnv *env)
|
||||||
{
|
{
|
||||||
jmethodID listModulesID;
|
jmethodID listModulesID;
|
||||||
jstring joptString = NULL;
|
|
||||||
jclass cls = GetLauncherHelperClass(env);
|
jclass cls = GetLauncherHelperClass(env);
|
||||||
NULL_CHECK(cls);
|
NULL_CHECK(cls);
|
||||||
NULL_CHECK(listModulesID = (*env)->GetStaticMethodID(env, cls,
|
NULL_CHECK(listModulesID = (*env)->GetStaticMethodID(env, cls,
|
||||||
"listModules", "(ZLjava/lang/String;)V"));
|
"listModules", "()V"));
|
||||||
|
(*env)->CallStaticVoidMethod(env, cls, listModulesID);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Describe a module
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
DescribeModule(JNIEnv *env, char *optString)
|
||||||
|
{
|
||||||
|
jmethodID describeModuleID;
|
||||||
|
jstring joptString = NULL;
|
||||||
|
jclass cls = GetLauncherHelperClass(env);
|
||||||
|
NULL_CHECK(cls);
|
||||||
|
NULL_CHECK(describeModuleID = (*env)->GetStaticMethodID(env, cls,
|
||||||
|
"describeModule", "(Ljava/lang/String;)V"));
|
||||||
NULL_CHECK(joptString = (*env)->NewStringUTF(env, optString));
|
NULL_CHECK(joptString = (*env)->NewStringUTF(env, optString));
|
||||||
(*env)->CallStaticVoidMethod(env, cls, listModulesID,
|
(*env)->CallStaticVoidMethod(env, cls, describeModuleID, joptString);
|
||||||
USE_STDOUT,
|
}
|
||||||
joptString);
|
|
||||||
|
/**
|
||||||
|
* Validate modules
|
||||||
|
*/
|
||||||
|
static jboolean
|
||||||
|
ValidateModules(JNIEnv *env)
|
||||||
|
{
|
||||||
|
jmethodID validateModulesID;
|
||||||
|
jclass cls = GetLauncherHelperClass(env);
|
||||||
|
NULL_CHECK_RETURN_VALUE(cls, JNI_FALSE);
|
||||||
|
validateModulesID = (*env)->GetStaticMethodID(env, cls, "validateModules", "()Z");
|
||||||
|
NULL_CHECK_RETURN_VALUE(cls, JNI_FALSE);
|
||||||
|
return (*env)->CallStaticBooleanMethod(env, cls, validateModulesID);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -729,7 +729,8 @@ public interface Instrumentation {
|
|||||||
* Tests whether a module can be modified with {@link #redefineModule
|
* Tests whether a module can be modified with {@link #redefineModule
|
||||||
* redefineModule}. If a module is modifiable then this method returns
|
* redefineModule}. If a module is modifiable then this method returns
|
||||||
* {@code true}. If a module is not modifiable then this method returns
|
* {@code true}. If a module is not modifiable then this method returns
|
||||||
* {@code false}.
|
* {@code false}. This method always returns {@code true} when the module
|
||||||
|
* is an unnamed module (as redefining an unnamed module is a no-op).
|
||||||
*
|
*
|
||||||
* @param module the module to test if it can be modified
|
* @param module the module to test if it can be modified
|
||||||
* @return {@code true} if the module is modifiable, otherwise {@code false}
|
* @return {@code true} if the module is modifiable, otherwise {@code false}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<!--
|
<!--
|
||||||
Copyright (c) 2003, 2016, 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.
|
DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
|
||||||
This code is free software; you can redistribute it and/or modify it
|
This code is free software; you can redistribute it and/or modify it
|
||||||
@ -112,7 +112,9 @@ If it is a custom system class loader then it must define the
|
|||||||
The <code>premain</code> methods will be run under the same security and classloader
|
The <code>premain</code> methods will be run under the same security and classloader
|
||||||
rules as the application <code>main</code> method.
|
rules as the application <code>main</code> method.
|
||||||
There are no modeling restrictions on what the agent <code>premain</code> method may do.
|
There are no modeling restrictions on what the agent <code>premain</code> method may do.
|
||||||
Anything application <code>main</code> can do, including creating threads, is legal from <code>premain</code>.
|
Anything application <code>main</code> can do, including creating threads, is legal from
|
||||||
|
<code>premain</code>.
|
||||||
|
|
||||||
|
|
||||||
<P>
|
<P>
|
||||||
Each agent is passed its agent options via the <code>agentArgs</code> parameter.
|
Each agent is passed its agent options via the <code>agentArgs</code> parameter.
|
||||||
@ -126,7 +128,6 @@ or because the agent class does not have an appropriate <code>premain</code> met
|
|||||||
If a <code>premain</code> method throws an uncaught exception, the JVM will abort.
|
If a <code>premain</code> method throws an uncaught exception, the JVM will abort.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<h3>Starting Agents After VM Startup</h3>
|
<h3>Starting Agents After VM Startup</h3>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
@ -191,76 +192,134 @@ or because the agent class does not have a conformant <code>agentmain</code> met
|
|||||||
not abort. If the <code>agentmain</code> method throws an uncaught exception it will be ignored.
|
not abort. If the <code>agentmain</code> method throws an uncaught exception it will be ignored.
|
||||||
|
|
||||||
|
|
||||||
|
<h3>Deploying Agents in Executable JAR file</h3>
|
||||||
|
|
||||||
|
The JAR File Specification defines manifest attributes for standalone applications that are
|
||||||
|
bundled as <em>executable JAR files</em>. If an implementation supports a mechanism to start
|
||||||
|
an application as an executable JAR then the main manifest may include the
|
||||||
|
<code>Launcher-Agent-Class</code> attribute to specify the class name
|
||||||
|
of an agent to start before the application <code>main</code> method is invoked. The Java
|
||||||
|
virtual machine attempts to invoke the following method on the agent class:
|
||||||
|
|
||||||
|
<blockquote>
|
||||||
|
<code>public static void
|
||||||
|
agentmain(String agentArgs, Instrumentation inst);
|
||||||
|
</code>
|
||||||
|
</blockquote>
|
||||||
|
|
||||||
|
<P>
|
||||||
|
If the agent class does not implement this method then the JVM will attempt to invoke:
|
||||||
|
|
||||||
|
<blockquote>
|
||||||
|
<code>public static void
|
||||||
|
agentmain(String agentArgs);
|
||||||
|
</code>
|
||||||
|
</blockquote>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
The value of the <code>agentArgs</code> parameter is always the empty string.
|
||||||
|
|
||||||
|
<P>
|
||||||
|
The <code>agentmain</code> method should do any necessary initialization
|
||||||
|
required to start the agent and return. If the agent cannot be started, for
|
||||||
|
example the agent class cannot be loaded, the agent class does not define a
|
||||||
|
conformant <code>agentmain</code> method, or the <code>agentmain</code> method
|
||||||
|
throws an uncaught exception or error, the JVM will abort.
|
||||||
|
|
||||||
|
|
||||||
|
<h3>Visibility</h3>
|
||||||
|
|
||||||
|
The types visible to the agent class are the types visible to the system class
|
||||||
|
loader. They minimally include the types in packages exported by
|
||||||
|
<a href="{@docRoot}/java.base-summary.html">java.base</a> and
|
||||||
|
<a href="{@docRoot}/java.instrument-summary.html">java.instrument</a>.
|
||||||
|
Whether all {@linkplain ClassLoader#getPlatformClassLoader() platform classes}
|
||||||
|
are visible or not will depend on the initial module or application.
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Supporting classes that the agent makes visible to the bootstrap class loader
|
||||||
|
(by means of {@link Instrumentation#appendToBootstrapClassLoaderSearch
|
||||||
|
appendToBootstrapClassLoaderSearch} or the <code>Boot-Class-Path</code> attribute
|
||||||
|
specified below) can only link to types defined to the bootstrap class loader.
|
||||||
|
There is no guarantee that all platform classes are visible to the boot class
|
||||||
|
loader.
|
||||||
|
|
||||||
|
|
||||||
<h3>Manifest Attributes</h3>
|
<h3>Manifest Attributes</h3>
|
||||||
|
|
||||||
The following manifest attributes are defined for an agent JAR file:
|
The following manifest attributes are defined for an agent JAR file:
|
||||||
<blockquote>
|
<blockquote>
|
||||||
<dl>
|
<dl>
|
||||||
<dt><code>Premain-Class</code></dt>
|
<dt><code>Premain-Class</code></dt>
|
||||||
<dd>
|
<dd>
|
||||||
When an agent is specified at JVM launch time this attribute
|
When an agent is specified at JVM launch time this attribute
|
||||||
specifies the agent class.
|
specifies the agent class.
|
||||||
That is, the class containing the <code>premain</code> method.
|
That is, the class containing the <code>premain</code> method.
|
||||||
When an agent is specified at JVM launch time this attribute
|
When an agent is specified at JVM launch time this attribute
|
||||||
is required. If the attribute is not present the JVM will abort.
|
is required. If the attribute is not present the JVM will abort.
|
||||||
Note: this is a class name, not a file name or path.
|
Note: this is a class name, not a file name or path.
|
||||||
</dd>
|
</dd>
|
||||||
|
|
||||||
<dt><code>Agent-Class</code></dt>
|
<dt><code>Agent-Class</code></dt>
|
||||||
<dd>
|
<dd>
|
||||||
If an implementation supports a mechanism to start agents
|
If an implementation supports a mechanism to start agents
|
||||||
sometime after the VM has started then this attribute specifies
|
sometime after the VM has started then this attribute specifies
|
||||||
the agent class.
|
the agent class.
|
||||||
That is, the class containing the <code>agentmain</code> method.
|
That is, the class containing the <code>agentmain</code> method.
|
||||||
This attribute is required, if it is not present the agent
|
This attribute is required, if it is not present the agent
|
||||||
will not be started.
|
will not be started.
|
||||||
Note: this is a class name, not a file name or path.
|
Note: this is a class name, not a file name or path.
|
||||||
</dd>
|
</dd>
|
||||||
|
<dt><code>Launcher-Agent-Class</code></dt>
|
||||||
|
<dd>
|
||||||
|
If an implementation supports a mechanism to start an application
|
||||||
|
as an executable JAR then the main manifest may include this
|
||||||
|
attribute to specify the class name of an agent to start before the
|
||||||
|
application <code>main</code> method is invoked.
|
||||||
|
</dd>
|
||||||
<dt><code>Boot-Class-Path</code></dt>
|
<dt><code>Boot-Class-Path</code></dt>
|
||||||
<dd>
|
<dd>
|
||||||
A list of paths to be searched by the bootstrap class
|
A list of paths to be searched by the bootstrap class
|
||||||
loader. Paths represent directories or libraries
|
loader. Paths represent directories or libraries
|
||||||
(commonly referred to as JAR or zip libraries on
|
(commonly referred to as JAR or zip libraries on
|
||||||
many platforms).
|
many platforms).
|
||||||
These paths are searched by the
|
These paths are searched by the
|
||||||
bootstrap class loader after the platform specific
|
bootstrap class loader after the platform specific
|
||||||
mechanisms of locating a class have failed.
|
mechanisms of locating a class have failed.
|
||||||
Paths are searched in the order listed.
|
Paths are searched in the order listed.
|
||||||
Paths in the list are separated by one or more spaces.
|
Paths in the list are separated by one or more spaces.
|
||||||
A path takes the syntax of the path component of a
|
A path takes the syntax of the path component of a
|
||||||
hierarchical URI. The path is
|
hierarchical URI. The path is
|
||||||
absolute if it begins with a slash character ('/'),
|
absolute if it begins with a slash character ('/'),
|
||||||
otherwise it is relative. A relative path is resolved
|
otherwise it is relative. A relative path is resolved
|
||||||
against the absolute path of the agent JAR file.
|
against the absolute path of the agent JAR file.
|
||||||
Malformed and non-existent paths are ignored.
|
Malformed and non-existent paths are ignored.
|
||||||
When an agent is started sometime after the VM has
|
When an agent is started sometime after the VM has
|
||||||
started then paths that do not represent a JAR file
|
started then paths that do not represent a JAR file
|
||||||
are ignored.
|
are ignored.
|
||||||
This attribute is optional.
|
This attribute is optional.
|
||||||
</dd>
|
</dd>
|
||||||
<dt><code>Can-Redefine-Classes</code></dt>
|
<dt><code>Can-Redefine-Classes</code></dt>
|
||||||
<dd>
|
<dd>
|
||||||
Boolean (<code>true</code> or <code>false</code>, case irrelevant).
|
Boolean (<code>true</code> or <code>false</code>, case irrelevant).
|
||||||
Is the ability to redefine classes
|
Is the ability to redefine classes
|
||||||
needed by this agent.
|
needed by this agent.
|
||||||
Values other than <code>true</code> are considered <code>false</code>.
|
Values other than <code>true</code> are considered <code>false</code>.
|
||||||
This attribute is optional, the default is <code>false</code>.
|
This attribute is optional, the default is <code>false</code>.
|
||||||
</dd>
|
</dd>
|
||||||
<dt><code>Can-Retransform-Classes</code></dt>
|
<dt><code>Can-Retransform-Classes</code></dt>
|
||||||
<dd>
|
<dd>
|
||||||
Boolean (<code>true</code> or <code>false</code>, case irrelevant).
|
Boolean (<code>true</code> or <code>false</code>, case irrelevant).
|
||||||
Is the ability to retransform classes
|
Is the ability to retransform classes
|
||||||
needed by this agent.
|
needed by this agent.
|
||||||
Values other than <code>true</code> are considered <code>false</code>.
|
Values other than <code>true</code> are considered <code>false</code>.
|
||||||
This attribute is optional, the default is <code>false</code>.
|
This attribute is optional, the default is <code>false</code>.
|
||||||
</dd>
|
</dd>
|
||||||
<dt><code>Can-Set-Native-Method-Prefix</code></dt>
|
<dt><code>Can-Set-Native-Method-Prefix</code></dt>
|
||||||
<dd>
|
<dd>
|
||||||
Boolean (<code>true</code> or <code>false</code>, case irrelevant).
|
Boolean (<code>true</code> or <code>false</code>, case irrelevant).
|
||||||
Is the ability to set native method prefix needed by this agent.
|
Is the ability to set native method prefix needed by this agent.
|
||||||
Values other than <code>true</code> are considered <code>false</code>.
|
Values other than <code>true</code> are considered <code>false</code>.
|
||||||
This attribute is optional, the default is <code>false</code>.
|
This attribute is optional, the default is <code>false</code>.
|
||||||
</dd>
|
</dd>
|
||||||
</dl>
|
</dl>
|
||||||
</blockquote>
|
</blockquote>
|
||||||
|
@ -32,5 +32,8 @@
|
|||||||
*/
|
*/
|
||||||
module java.instrument {
|
module java.instrument {
|
||||||
exports java.lang.instrument;
|
exports java.lang.instrument;
|
||||||
|
|
||||||
|
// allow java launcher to load agents in executable JAR files
|
||||||
|
exports sun.instrument to java.base;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2003, 2016, 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.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -555,4 +555,15 @@ public class InstrumentationImpl implements Instrumentation {
|
|||||||
classfileBuffer);
|
classfileBuffer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invoked by the java launcher to load a java agent that is packaged with
|
||||||
|
* the main application in an executable JAR file.
|
||||||
|
*/
|
||||||
|
public static void loadAgent(String path) {
|
||||||
|
loadAgent0(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static native void loadAgent0(String path);
|
||||||
}
|
}
|
||||||
|
@ -159,3 +159,20 @@ JNIEXPORT void JNICALL Java_sun_instrument_InstrumentationImpl_setNativeMethodPr
|
|||||||
(JNIEnv * jnienv, jobject implThis, jlong agent, jobjectArray prefixArray, jboolean isRetransformable) {
|
(JNIEnv * jnienv, jobject implThis, jlong agent, jobjectArray prefixArray, jboolean isRetransformable) {
|
||||||
setNativeMethodPrefixes(jnienv, (JPLISAgent*)(intptr_t)agent, prefixArray, isRetransformable);
|
setNativeMethodPrefixes(jnienv, (JPLISAgent*)(intptr_t)agent, prefixArray, isRetransformable);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Class: sun_instrument_InstrumentationImpl
|
||||||
|
* Method: loadAgent0
|
||||||
|
*/
|
||||||
|
JNIEXPORT void JNICALL Java_sun_instrument_InstrumentationImpl_loadAgent0
|
||||||
|
(JNIEnv* env, jclass clazz, jstring jarfile)
|
||||||
|
{
|
||||||
|
extern jint loadAgent(JNIEnv* env, jstring path);
|
||||||
|
if (loadAgent(env, jarfile) != JNI_OK) {
|
||||||
|
if (!(*env)->ExceptionCheck(env)) {
|
||||||
|
createAndThrowInternalError(env);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2003, 2016, 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.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -106,7 +106,7 @@ getBooleanAttribute(const jarAttribute* attributes, const char* name) {
|
|||||||
* convert them to JVM TI capabilities.
|
* convert them to JVM TI capabilities.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
convertCapabilityAtrributes(const jarAttribute* attributes, JPLISAgent* agent) {
|
convertCapabilityAttributes(const jarAttribute* attributes, JPLISAgent* agent) {
|
||||||
/* set redefineClasses capability */
|
/* set redefineClasses capability */
|
||||||
if (getBooleanAttribute(attributes, "Can-Redefine-Classes")) {
|
if (getBooleanAttribute(attributes, "Can-Redefine-Classes")) {
|
||||||
addRedefineClassesCapability(agent);
|
addRedefineClassesCapability(agent);
|
||||||
@ -229,7 +229,7 @@ DEF_Agent_OnLoad(JavaVM *vm, char *tail, void * reserved) {
|
|||||||
/*
|
/*
|
||||||
* Convert JAR attributes into agent capabilities
|
* Convert JAR attributes into agent capabilities
|
||||||
*/
|
*/
|
||||||
convertCapabilityAtrributes(attributes, agent);
|
convertCapabilityAttributes(attributes, agent);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Track (record) the agent class name and options data
|
* Track (record) the agent class name and options data
|
||||||
@ -386,7 +386,7 @@ DEF_Agent_OnAttach(JavaVM* vm, char *args, void * reserved) {
|
|||||||
/*
|
/*
|
||||||
* Convert JAR attributes into agent capabilities
|
* Convert JAR attributes into agent capabilities
|
||||||
*/
|
*/
|
||||||
convertCapabilityAtrributes(attributes, agent);
|
convertCapabilityAttributes(attributes, agent);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Create the java.lang.instrument.Instrumentation instance
|
* Create the java.lang.instrument.Instrumentation instance
|
||||||
@ -435,6 +435,109 @@ JNIEXPORT void JNICALL
|
|||||||
DEF_Agent_OnUnload(JavaVM *vm) {
|
DEF_Agent_OnUnload(JavaVM *vm) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invoked by the java launcher to load an agent in the main executable JAR.
|
||||||
|
* The Launcher-Agent-Class attribute in the main manifest of the JAR file
|
||||||
|
* is the agent class.
|
||||||
|
*
|
||||||
|
* Returns JNI_OK if the agent is loaded and initialized; JNI_ERR if this
|
||||||
|
* function fails, possibly with a pending exception.
|
||||||
|
*/
|
||||||
|
jint loadAgent(JNIEnv* env, jstring path) {
|
||||||
|
JavaVM* vm;
|
||||||
|
JPLISAgent* agent;
|
||||||
|
const char* jarfile = NULL;
|
||||||
|
jarAttribute* attributes = NULL;
|
||||||
|
char* agentClass = NULL;
|
||||||
|
char* bootClassPath;
|
||||||
|
int oldLen, newLen;
|
||||||
|
jint result = JNI_ERR;
|
||||||
|
|
||||||
|
if ((*env)->GetJavaVM(env, &vm) < 0) {
|
||||||
|
return JNI_ERR;
|
||||||
|
}
|
||||||
|
|
||||||
|
// create JPLISAgent with JVMTI environment
|
||||||
|
if (createNewJPLISAgent(vm, &agent) != JPLIS_INIT_ERROR_NONE) {
|
||||||
|
return JNI_ERR;
|
||||||
|
}
|
||||||
|
|
||||||
|
// get path to JAR file as UTF-8 string
|
||||||
|
jarfile = (*env)->GetStringUTFChars(env, path, NULL);
|
||||||
|
if (jarfile == NULL) {
|
||||||
|
return JNI_ERR;
|
||||||
|
}
|
||||||
|
|
||||||
|
// read the attributes in the main section of JAR manifest
|
||||||
|
attributes = readAttributes(jarfile);
|
||||||
|
if (attributes == NULL) {
|
||||||
|
goto releaseAndReturn;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Launcher-Agent-Class is required
|
||||||
|
agentClass = getAttribute(attributes, "Launcher-Agent-Class");
|
||||||
|
if (agentClass == NULL) {
|
||||||
|
goto releaseAndReturn;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The value of Launcher-Agent-Class is in UTF-8, convert it to modified UTF-8
|
||||||
|
oldLen = (int) strlen(agentClass);
|
||||||
|
newLen = modifiedUtf8LengthOfUtf8(agentClass, oldLen);
|
||||||
|
if (newLen == oldLen) {
|
||||||
|
agentClass = strdup(agentClass);
|
||||||
|
} else {
|
||||||
|
char* str = (char*) malloc(newLen + 1);
|
||||||
|
if (str != NULL) {
|
||||||
|
convertUtf8ToModifiedUtf8(agentClass, oldLen, str, newLen);
|
||||||
|
}
|
||||||
|
agentClass = str;
|
||||||
|
}
|
||||||
|
if (agentClass == NULL) {
|
||||||
|
jthrowable oome = createThrowable(env, "java/lang/OutOfMemoryError", NULL);
|
||||||
|
if (oome != NULL) (*env)->Throw(env, oome);
|
||||||
|
goto releaseAndReturn;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Boot-Class-Path
|
||||||
|
bootClassPath = getAttribute(attributes, "Boot-Class-Path");
|
||||||
|
if (bootClassPath != NULL) {
|
||||||
|
appendBootClassPath(agent, jarfile, bootClassPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Can-XXXX capabilities
|
||||||
|
convertCapabilityAttributes(attributes, agent);
|
||||||
|
|
||||||
|
// Create the java.lang.instrument.Instrumentation object
|
||||||
|
if (!createInstrumentationImpl(env, agent)) {
|
||||||
|
goto releaseAndReturn;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Enable the ClassFileLoadHook
|
||||||
|
if (!setLivePhaseEventHandlers(agent)) {
|
||||||
|
goto releaseAndReturn;
|
||||||
|
}
|
||||||
|
|
||||||
|
// invoke the agentmain method
|
||||||
|
if (!startJavaAgent(agent, env, agentClass, "", agent->mAgentmainCaller)) {
|
||||||
|
goto releaseAndReturn;
|
||||||
|
}
|
||||||
|
|
||||||
|
// initialization complete
|
||||||
|
result = JNI_OK;
|
||||||
|
|
||||||
|
releaseAndReturn:
|
||||||
|
if (agentClass != NULL) {
|
||||||
|
free(agentClass);
|
||||||
|
}
|
||||||
|
if (attributes != NULL) {
|
||||||
|
freeAttributes(attributes);
|
||||||
|
}
|
||||||
|
if (jarfile != NULL) {
|
||||||
|
(*env)->ReleaseStringUTFChars(env, path, jarfile);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* JVMTI callback support
|
* JVMTI callback support
|
||||||
|
@ -841,6 +841,9 @@ public class ThreadInfo {
|
|||||||
* @return a {@code ThreadInfo} object represented
|
* @return a {@code ThreadInfo} object represented
|
||||||
* by {@code cd} if {@code cd} is not {@code null};
|
* by {@code cd} if {@code cd} is not {@code null};
|
||||||
* {@code null} otherwise.
|
* {@code null} otherwise.
|
||||||
|
*
|
||||||
|
* @revised 9
|
||||||
|
* @spec JPMS
|
||||||
*/
|
*/
|
||||||
public static ThreadInfo from(CompositeData cd) {
|
public static ThreadInfo from(CompositeData cd) {
|
||||||
if (cd == null) {
|
if (cd == null) {
|
||||||
|
@ -214,13 +214,14 @@ public class VirtualMachineImpl extends HotSpotVirtualMachine {
|
|||||||
// Special-case the "load" command so that the right exception is
|
// Special-case the "load" command so that the right exception is
|
||||||
// thrown.
|
// thrown.
|
||||||
if (cmd.equals("load")) {
|
if (cmd.equals("load")) {
|
||||||
throw new AgentLoadException("Failed to load agent library");
|
String msg = "Failed to load agent library";
|
||||||
|
if (!message.isEmpty())
|
||||||
|
msg += ": " + message;
|
||||||
|
throw new AgentLoadException(msg);
|
||||||
} else {
|
} else {
|
||||||
if (message == null) {
|
if (message.isEmpty())
|
||||||
throw new AttachOperationFailedException("Command failed in target VM");
|
message = "Command failed in target VM";
|
||||||
} else {
|
throw new AttachOperationFailedException(message);
|
||||||
throw new AttachOperationFailedException(message);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -211,13 +211,14 @@ public class VirtualMachineImpl extends HotSpotVirtualMachine {
|
|||||||
// Special-case the "load" command so that the right exception is
|
// Special-case the "load" command so that the right exception is
|
||||||
// thrown.
|
// thrown.
|
||||||
if (cmd.equals("load")) {
|
if (cmd.equals("load")) {
|
||||||
throw new AgentLoadException("Failed to load agent library");
|
String msg = "Failed to load agent library";
|
||||||
|
if (!message.isEmpty())
|
||||||
|
msg += ": " + message;
|
||||||
|
throw new AgentLoadException(msg);
|
||||||
} else {
|
} else {
|
||||||
if (message == null) {
|
if (message.isEmpty())
|
||||||
throw new AttachOperationFailedException("Command failed in target VM");
|
message = "Command failed in target VM";
|
||||||
} else {
|
throw new AttachOperationFailedException(message);
|
||||||
throw new AttachOperationFailedException(message);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -213,13 +213,14 @@ public class VirtualMachineImpl extends HotSpotVirtualMachine {
|
|||||||
// Special-case the "load" command so that the right exception is
|
// Special-case the "load" command so that the right exception is
|
||||||
// thrown.
|
// thrown.
|
||||||
if (cmd.equals("load")) {
|
if (cmd.equals("load")) {
|
||||||
throw new AgentLoadException("Failed to load agent library");
|
String msg = "Failed to load agent library";
|
||||||
|
if (!message.isEmpty())
|
||||||
|
msg += ": " + message;
|
||||||
|
throw new AgentLoadException(msg);
|
||||||
} else {
|
} else {
|
||||||
if (message == null) {
|
if (message.isEmpty())
|
||||||
throw new AttachOperationFailedException("Command failed in target VM");
|
message = "Command failed in target VM";
|
||||||
} else {
|
throw new AttachOperationFailedException(message);
|
||||||
throw new AttachOperationFailedException(message);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2005, 2014, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2005, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -25,15 +25,19 @@
|
|||||||
|
|
||||||
package sun.tools.attach;
|
package sun.tools.attach;
|
||||||
|
|
||||||
|
import com.sun.tools.attach.AttachNotSupportedException;
|
||||||
import com.sun.tools.attach.VirtualMachine;
|
import com.sun.tools.attach.VirtualMachine;
|
||||||
import com.sun.tools.attach.AgentLoadException;
|
import com.sun.tools.attach.AgentLoadException;
|
||||||
import com.sun.tools.attach.AgentInitializationException;
|
import com.sun.tools.attach.AgentInitializationException;
|
||||||
import com.sun.tools.attach.spi.AttachProvider;
|
import com.sun.tools.attach.spi.AttachProvider;
|
||||||
|
import jdk.internal.misc.VM;
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
import java.io.BufferedReader;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
|
import java.security.AccessController;
|
||||||
|
import java.security.PrivilegedAction;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
@ -43,8 +47,33 @@ import java.util.stream.Collectors;
|
|||||||
|
|
||||||
public abstract class HotSpotVirtualMachine extends VirtualMachine {
|
public abstract class HotSpotVirtualMachine extends VirtualMachine {
|
||||||
|
|
||||||
HotSpotVirtualMachine(AttachProvider provider, String id) {
|
private static final long CURRENT_PID;
|
||||||
|
private static final boolean ALLOW_ATTACH_SELF;
|
||||||
|
static {
|
||||||
|
PrivilegedAction<ProcessHandle> pa = ProcessHandle::current;
|
||||||
|
CURRENT_PID = AccessController.doPrivileged(pa).pid();
|
||||||
|
|
||||||
|
String s = VM.getSavedProperty("jdk.attach.allowAttachSelf");
|
||||||
|
ALLOW_ATTACH_SELF = "".equals(s) || Boolean.parseBoolean(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
HotSpotVirtualMachine(AttachProvider provider, String id)
|
||||||
|
throws AttachNotSupportedException, IOException
|
||||||
|
{
|
||||||
super(provider, id);
|
super(provider, id);
|
||||||
|
|
||||||
|
int pid;
|
||||||
|
try {
|
||||||
|
pid = Integer.parseInt(id);
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
throw new AttachNotSupportedException("Invalid process identifier");
|
||||||
|
}
|
||||||
|
|
||||||
|
// The tool should be a different VM to the target. This check will
|
||||||
|
// eventually be enforced by the target VM.
|
||||||
|
if (!ALLOW_ATTACH_SELF && (pid == 0 || pid == CURRENT_PID)) {
|
||||||
|
throw new IOException("Can not attach to current VM");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -103,8 +132,6 @@ public abstract class HotSpotVirtualMachine extends VirtualMachine {
|
|||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
loadAgentLibrary("instrument", args);
|
loadAgentLibrary("instrument", args);
|
||||||
} catch (AgentLoadException x) {
|
|
||||||
throw new InternalError("instrument library is missing in target VM", x);
|
|
||||||
} catch (AgentInitializationException x) {
|
} catch (AgentInitializationException x) {
|
||||||
/*
|
/*
|
||||||
* Translate interesting errors into the right exception and
|
* Translate interesting errors into the right exception and
|
||||||
@ -116,13 +143,17 @@ public abstract class HotSpotVirtualMachine extends VirtualMachine {
|
|||||||
case JNI_ENOMEM:
|
case JNI_ENOMEM:
|
||||||
throw new AgentLoadException("Insuffient memory");
|
throw new AgentLoadException("Insuffient memory");
|
||||||
case ATTACH_ERROR_BADJAR:
|
case ATTACH_ERROR_BADJAR:
|
||||||
throw new AgentLoadException("Agent JAR not found or no Agent-Class attribute");
|
throw new AgentLoadException(
|
||||||
|
"Agent JAR not found or no Agent-Class attribute");
|
||||||
case ATTACH_ERROR_NOTONCP:
|
case ATTACH_ERROR_NOTONCP:
|
||||||
throw new AgentLoadException("Unable to add JAR file to system class path");
|
throw new AgentLoadException(
|
||||||
|
"Unable to add JAR file to system class path");
|
||||||
case ATTACH_ERROR_STARTFAIL:
|
case ATTACH_ERROR_STARTFAIL:
|
||||||
throw new AgentInitializationException("Agent JAR loaded but agent failed to initialize");
|
throw new AgentInitializationException(
|
||||||
|
"Agent JAR loaded but agent failed to initialize");
|
||||||
default :
|
default :
|
||||||
throw new AgentLoadException("Failed to load agent - unknown reason: " + rc);
|
throw new AgentLoadException("" +
|
||||||
|
"Failed to load agent - unknown reason: " + rc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -163,20 +194,20 @@ public abstract class HotSpotVirtualMachine extends VirtualMachine {
|
|||||||
return props;
|
return props;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final String MANAGMENT_PREFIX = "com.sun.management.";
|
private static final String MANAGEMENT_PREFIX = "com.sun.management.";
|
||||||
|
|
||||||
private static boolean checkedKeyName(Object key) {
|
private static boolean checkedKeyName(Object key) {
|
||||||
if (!(key instanceof String)) {
|
if (!(key instanceof String)) {
|
||||||
throw new IllegalArgumentException("Invalid option (not a String): "+key);
|
throw new IllegalArgumentException("Invalid option (not a String): "+key);
|
||||||
}
|
}
|
||||||
if (!((String)key).startsWith(MANAGMENT_PREFIX)) {
|
if (!((String)key).startsWith(MANAGEMENT_PREFIX)) {
|
||||||
throw new IllegalArgumentException("Invalid option: "+key);
|
throw new IllegalArgumentException("Invalid option: "+key);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String stripKeyName(Object key) {
|
private static String stripKeyName(Object key) {
|
||||||
return ((String)key).substring(MANAGMENT_PREFIX.length());
|
return ((String)key).substring(MANAGEMENT_PREFIX.length());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -204,9 +235,11 @@ public abstract class HotSpotVirtualMachine extends VirtualMachine {
|
|||||||
@Override
|
@Override
|
||||||
public String startLocalManagementAgent() throws IOException {
|
public String startLocalManagementAgent() throws IOException {
|
||||||
executeJCmd("ManagementAgent.start_local").close();
|
executeJCmd("ManagementAgent.start_local").close();
|
||||||
return getAgentProperties().getProperty("com.sun.management.jmxremote.localConnectorAddress");
|
String prop = MANAGEMENT_PREFIX + "jmxremote.localConnectorAddress";
|
||||||
|
return getAgentProperties().getProperty(prop);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// --- HotSpot specific methods ---
|
// --- HotSpot specific methods ---
|
||||||
|
|
||||||
// same as SIGQUIT
|
// same as SIGQUIT
|
||||||
@ -245,8 +278,8 @@ public abstract class HotSpotVirtualMachine extends VirtualMachine {
|
|||||||
return executeCommand("jcmd", command);
|
return executeCommand("jcmd", command);
|
||||||
}
|
}
|
||||||
|
|
||||||
// -- Supporting methods
|
|
||||||
|
|
||||||
|
// -- Supporting methods
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Execute the given command in the target VM - specific platform
|
* Execute the given command in the target VM - specific platform
|
||||||
@ -306,10 +339,10 @@ public abstract class HotSpotVirtualMachine extends VirtualMachine {
|
|||||||
/*
|
/*
|
||||||
* Utility method to read data into a String.
|
* Utility method to read data into a String.
|
||||||
*/
|
*/
|
||||||
String readErrorMessage(InputStream sis) throws IOException {
|
String readErrorMessage(InputStream in) throws IOException {
|
||||||
String s;
|
String s;
|
||||||
StringBuilder message = new StringBuilder();
|
StringBuilder message = new StringBuilder();
|
||||||
BufferedReader br = new BufferedReader(new InputStreamReader(sis));
|
BufferedReader br = new BufferedReader(new InputStreamReader(in));
|
||||||
while ((s = br.readLine()) != null) {
|
while ((s = br.readLine()) != null) {
|
||||||
message.append(s);
|
message.append(s);
|
||||||
}
|
}
|
||||||
|
@ -160,13 +160,14 @@ public class VirtualMachineImpl extends HotSpotVirtualMachine {
|
|||||||
String message = readErrorMessage(sis);
|
String message = readErrorMessage(sis);
|
||||||
sis.close();
|
sis.close();
|
||||||
if (cmd.equals("load")) {
|
if (cmd.equals("load")) {
|
||||||
throw new AgentLoadException("Failed to load agent library");
|
String msg = "Failed to load agent library";
|
||||||
|
if (!message.isEmpty())
|
||||||
|
msg += ": " + message;
|
||||||
|
throw new AgentLoadException(msg);
|
||||||
} else {
|
} else {
|
||||||
if (message == null) {
|
if (message.isEmpty())
|
||||||
throw new AttachOperationFailedException("Command failed in target VM");
|
message = "Command failed in target VM";
|
||||||
} else {
|
throw new AttachOperationFailedException(message);
|
||||||
throw new AttachOperationFailedException(message);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -100,28 +100,29 @@ public class VirtualMachineImpl extends HotSpotVirtualMachine {
|
|||||||
connectPipe(hPipe);
|
connectPipe(hPipe);
|
||||||
|
|
||||||
// create an input stream for the pipe
|
// create an input stream for the pipe
|
||||||
PipedInputStream is = new PipedInputStream(hPipe);
|
PipedInputStream in = new PipedInputStream(hPipe);
|
||||||
|
|
||||||
// read completion status
|
// read completion status
|
||||||
int status = readInt(is);
|
int status = readInt(in);
|
||||||
if (status != 0) {
|
if (status != 0) {
|
||||||
// read from the stream and use that as the error message
|
// read from the stream and use that as the error message
|
||||||
String message = readErrorMessage(is);
|
String message = readErrorMessage(in);
|
||||||
is.close();
|
in.close();
|
||||||
// special case the load command so that the right exception is thrown
|
// special case the load command so that the right exception is thrown
|
||||||
if (cmd.equals("load")) {
|
if (cmd.equals("load")) {
|
||||||
throw new AgentLoadException("Failed to load agent library");
|
String msg = "Failed to load agent library";
|
||||||
|
if (!message.isEmpty())
|
||||||
|
msg += ": " + message;
|
||||||
|
throw new AgentLoadException(msg);
|
||||||
} else {
|
} else {
|
||||||
if (message == null) {
|
if (message.isEmpty())
|
||||||
throw new AttachOperationFailedException("Command failed in target VM");
|
message = "Command failed in target VM";
|
||||||
} else {
|
throw new AttachOperationFailedException(message);
|
||||||
throw new AttachOperationFailedException(message);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// return the input stream
|
// return the input stream
|
||||||
return is;
|
return in;
|
||||||
|
|
||||||
} catch (IOException ioe) {
|
} catch (IOException ioe) {
|
||||||
closePipe(hPipe);
|
closePipe(hPipe);
|
||||||
|
@ -71,6 +71,7 @@ import static jdk.internal.util.jar.JarIndex.INDEX_NAME;
|
|||||||
import static java.util.jar.JarFile.MANIFEST_NAME;
|
import static java.util.jar.JarFile.MANIFEST_NAME;
|
||||||
import static java.util.stream.Collectors.joining;
|
import static java.util.stream.Collectors.joining;
|
||||||
import static java.nio.file.StandardCopyOption.REPLACE_EXISTING;
|
import static java.nio.file.StandardCopyOption.REPLACE_EXISTING;
|
||||||
|
import static sun.tools.jar.Validator.ENTRYNAME_COMPARATOR;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class implements a simple utility for creating files in the JAR
|
* This class implements a simple utility for creating files in the JAR
|
||||||
@ -132,6 +133,10 @@ public class Main {
|
|||||||
// if --release option found followed by at least file
|
// if --release option found followed by at least file
|
||||||
boolean isMultiRelease;
|
boolean isMultiRelease;
|
||||||
|
|
||||||
|
// The last parsed --release value, if any. Used in conjunction with
|
||||||
|
// "-d,--describe-module" to select the operative module descriptor.
|
||||||
|
int releaseValue = -1;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* cflag: create
|
* cflag: create
|
||||||
* uflag: update
|
* uflag: update
|
||||||
@ -413,7 +418,7 @@ public class Main {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
try (FileInputStream fin = new FileInputStream(FileDescriptor.in)) {
|
try (FileInputStream fin = new FileInputStream(FileDescriptor.in)) {
|
||||||
found = describeModule(fin);
|
found = describeModuleFromStream(fin);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!found)
|
if (!found)
|
||||||
@ -604,11 +609,6 @@ public class Main {
|
|||||||
/* parse file arguments */
|
/* parse file arguments */
|
||||||
int n = args.length - count;
|
int n = args.length - count;
|
||||||
if (n > 0) {
|
if (n > 0) {
|
||||||
if (dflag) {
|
|
||||||
// "--describe-module/-d" does not require file argument(s)
|
|
||||||
usageError(formatMsg("error.bad.dflag", args[count]));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
int version = BASE_VERSION;
|
int version = BASE_VERSION;
|
||||||
int k = 0;
|
int k = 0;
|
||||||
String[] nameBuf = new String[n];
|
String[] nameBuf = new String[n];
|
||||||
@ -616,6 +616,12 @@ public class Main {
|
|||||||
try {
|
try {
|
||||||
for (int i = count; i < args.length; i++) {
|
for (int i = count; i < args.length; i++) {
|
||||||
if (args[i].equals("-C")) {
|
if (args[i].equals("-C")) {
|
||||||
|
if (dflag) {
|
||||||
|
// "--describe-module/-d" does not require file argument(s),
|
||||||
|
// but does accept --release
|
||||||
|
usageError(getMsg("error.bad.dflag"));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
/* change the directory */
|
/* change the directory */
|
||||||
String dir = args[++i];
|
String dir = args[++i];
|
||||||
dir = (dir.endsWith(File.separator) ?
|
dir = (dir.endsWith(File.separator) ?
|
||||||
@ -649,8 +655,15 @@ public class Main {
|
|||||||
k = 0;
|
k = 0;
|
||||||
nameBuf = new String[n];
|
nameBuf = new String[n];
|
||||||
version = v;
|
version = v;
|
||||||
|
releaseValue = version;
|
||||||
pathsMap.put(version, new HashSet<>());
|
pathsMap.put(version, new HashSet<>());
|
||||||
} else {
|
} else {
|
||||||
|
if (dflag) {
|
||||||
|
// "--describe-module/-d" does not require file argument(s),
|
||||||
|
// but does accept --release
|
||||||
|
usageError(getMsg("error.bad.dflag"));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
nameBuf[k++] = args[i];
|
nameBuf[k++] = args[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -756,7 +769,7 @@ public class Main {
|
|||||||
* can be found by recursively descending directories.
|
* can be found by recursively descending directories.
|
||||||
*
|
*
|
||||||
* @param dir parent directory
|
* @param dir parent directory
|
||||||
* @param file s list of files to expand
|
* @param files list of files to expand
|
||||||
* @param cpaths set of directories specified by -C option for the files
|
* @param cpaths set of directories specified by -C option for the files
|
||||||
* @throws IOException if an I/O error occurs
|
* @throws IOException if an I/O error occurs
|
||||||
*/
|
*/
|
||||||
@ -1721,23 +1734,62 @@ public class Main {
|
|||||||
|
|
||||||
// Modular jar support
|
// Modular jar support
|
||||||
|
|
||||||
static <T> String toString(Collection<T> c,
|
/**
|
||||||
CharSequence prefix,
|
* Associates a module descriptor's zip entry name along with its
|
||||||
CharSequence suffix ) {
|
* bytes and an optional URI. Used when describing modules.
|
||||||
if (c.isEmpty())
|
*/
|
||||||
return "";
|
interface ModuleInfoEntry {
|
||||||
return c.stream().map(e -> e.toString())
|
String name();
|
||||||
.collect(joining(", ", prefix, suffix));
|
Optional<String> uriString();
|
||||||
|
InputStream bytes() throws IOException;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean describeModule(ZipFile zipFile) throws IOException {
|
static class ZipFileModuleInfoEntry implements ModuleInfoEntry {
|
||||||
ZipEntry[] zes = zipFile.stream()
|
private final ZipFile zipFile;
|
||||||
.filter(e -> isModuleInfoEntry(e.getName()))
|
private final ZipEntry entry;
|
||||||
.sorted(Validator.ENTRY_COMPARATOR)
|
ZipFileModuleInfoEntry(ZipFile zipFile, ZipEntry entry) {
|
||||||
.toArray(ZipEntry[]::new);
|
this.zipFile = zipFile;
|
||||||
|
this.entry = entry;
|
||||||
|
}
|
||||||
|
@Override public String name() { return entry.getName(); }
|
||||||
|
@Override public InputStream bytes() throws IOException {
|
||||||
|
return zipFile.getInputStream(entry);
|
||||||
|
}
|
||||||
|
/** Returns an optional containing the effective URI. */
|
||||||
|
@Override public Optional<String> uriString() {
|
||||||
|
String uri = (Paths.get(zipFile.getName())).toUri().toString();
|
||||||
|
uri = "jar:" + uri + "/!" + entry.getName();
|
||||||
|
return Optional.of(uri);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (zes.length == 0) {
|
static class StreamedModuleInfoEntry implements ModuleInfoEntry {
|
||||||
// No module descriptor found, derive the automatic module name
|
private final String name;
|
||||||
|
private final byte[] bytes;
|
||||||
|
StreamedModuleInfoEntry(String name, byte[] bytes) {
|
||||||
|
this.name = name;
|
||||||
|
this.bytes = bytes;
|
||||||
|
}
|
||||||
|
@Override public String name() { return name; }
|
||||||
|
@Override public InputStream bytes() throws IOException {
|
||||||
|
return new ByteArrayInputStream(bytes);
|
||||||
|
}
|
||||||
|
/** Returns an empty optional. */
|
||||||
|
@Override public Optional<String> uriString() {
|
||||||
|
return Optional.empty(); // no URI can be derived
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Describes a module from a given zip file. */
|
||||||
|
private boolean describeModule(ZipFile zipFile) throws IOException {
|
||||||
|
ZipFileModuleInfoEntry[] infos = zipFile.stream()
|
||||||
|
.filter(e -> isModuleInfoEntry(e.getName()))
|
||||||
|
.sorted(Validator.ENTRY_COMPARATOR)
|
||||||
|
.map(e -> new ZipFileModuleInfoEntry(zipFile, e))
|
||||||
|
.toArray(ZipFileModuleInfoEntry[]::new);
|
||||||
|
|
||||||
|
if (infos.length == 0) {
|
||||||
|
// No module descriptor found, derive and describe the automatic module
|
||||||
String fn = zipFile.getName();
|
String fn = zipFile.getName();
|
||||||
ModuleFinder mf = ModuleFinder.of(Paths.get(fn));
|
ModuleFinder mf = ModuleFinder.of(Paths.get(fn));
|
||||||
try {
|
try {
|
||||||
@ -1747,8 +1799,8 @@ public class Main {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
ModuleDescriptor md = mref.iterator().next().descriptor();
|
ModuleDescriptor md = mref.iterator().next().descriptor();
|
||||||
output(getMsg("out.automodule"));
|
output(getMsg("out.automodule") + "\n");
|
||||||
describeModule(md, null, null, "automatic");
|
describeModule(md, null, null, "");
|
||||||
} catch (FindException e) {
|
} catch (FindException e) {
|
||||||
String msg = formatMsg("error.unable.derive.automodule", fn);
|
String msg = formatMsg("error.unable.derive.automodule", fn);
|
||||||
Throwable t = e.getCause();
|
Throwable t = e.getCause();
|
||||||
@ -1757,46 +1809,117 @@ public class Main {
|
|||||||
output(msg);
|
output(msg);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for (ZipEntry ze : zes) {
|
return describeModuleFromEntries(infos);
|
||||||
try (InputStream is = zipFile.getInputStream(ze)) {
|
|
||||||
describeModule(is, ze.getName());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean describeModule(FileInputStream fis)
|
private boolean describeModuleFromStream(FileInputStream fis)
|
||||||
throws IOException
|
throws IOException
|
||||||
{
|
{
|
||||||
|
List<ModuleInfoEntry> infos = new LinkedList<>();
|
||||||
|
|
||||||
try (BufferedInputStream bis = new BufferedInputStream(fis);
|
try (BufferedInputStream bis = new BufferedInputStream(fis);
|
||||||
ZipInputStream zis = new ZipInputStream(bis)) {
|
ZipInputStream zis = new ZipInputStream(bis)) {
|
||||||
ZipEntry e;
|
ZipEntry e;
|
||||||
while ((e = zis.getNextEntry()) != null) {
|
while ((e = zis.getNextEntry()) != null) {
|
||||||
String ename = e.getName();
|
String ename = e.getName();
|
||||||
if (isModuleInfoEntry(ename)){
|
if (isModuleInfoEntry(ename)) {
|
||||||
moduleInfos.put(ename, zis.readAllBytes());
|
infos.add(new StreamedModuleInfoEntry(ename, zis.readAllBytes()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (moduleInfos.size() == 0)
|
|
||||||
|
if (infos.size() == 0)
|
||||||
return false;
|
return false;
|
||||||
String[] names = moduleInfos.keySet().stream()
|
|
||||||
.sorted(Validator.ENTRYNAME_COMPARATOR)
|
ModuleInfoEntry[] sorted = infos.stream()
|
||||||
.toArray(String[]::new);
|
.sorted(Comparator.comparing(ModuleInfoEntry::name, ENTRYNAME_COMPARATOR))
|
||||||
for (String name : names) {
|
.toArray(ModuleInfoEntry[]::new);
|
||||||
describeModule(new ByteArrayInputStream(moduleInfos.get(name)), name);
|
|
||||||
|
return describeModuleFromEntries(sorted);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean lessThanEqualReleaseValue(ModuleInfoEntry entry) {
|
||||||
|
return intVersionFromEntry(entry) <= releaseValue ? true : false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String versionFromEntryName(String name) {
|
||||||
|
String s = name.substring(VERSIONS_DIR_LENGTH);
|
||||||
|
return s.substring(0, s.indexOf("/"));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int intVersionFromEntry(ModuleInfoEntry entry) {
|
||||||
|
String name = entry.name();
|
||||||
|
if (!name.startsWith(VERSIONS_DIR))
|
||||||
|
return BASE_VERSION;
|
||||||
|
|
||||||
|
String s = name.substring(VERSIONS_DIR_LENGTH);
|
||||||
|
s = s.substring(0, s.indexOf('/'));
|
||||||
|
return Integer.valueOf(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Describes a single module descriptor, determined by the specified
|
||||||
|
* --release, if any, from the given ordered entries.
|
||||||
|
* The given infos must be ordered as per ENTRY_COMPARATOR.
|
||||||
|
*/
|
||||||
|
private boolean describeModuleFromEntries(ModuleInfoEntry[] infos)
|
||||||
|
throws IOException
|
||||||
|
{
|
||||||
|
assert infos.length > 0;
|
||||||
|
|
||||||
|
// Informative: output all non-root descriptors, if any
|
||||||
|
String releases = Arrays.stream(infos)
|
||||||
|
.filter(e -> !e.name().equals(MODULE_INFO))
|
||||||
|
.map(ModuleInfoEntry::name)
|
||||||
|
.map(Main::versionFromEntryName)
|
||||||
|
.collect(joining(" "));
|
||||||
|
if (!releases.equals(""))
|
||||||
|
output("releases: " + releases + "\n");
|
||||||
|
|
||||||
|
// Describe the operative descriptor for the specified --release, if any
|
||||||
|
if (releaseValue != -1) {
|
||||||
|
ModuleInfoEntry entry = null;
|
||||||
|
int i = 0;
|
||||||
|
while (i < infos.length && lessThanEqualReleaseValue(infos[i])) {
|
||||||
|
entry = infos[i];
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (entry == null) {
|
||||||
|
output(formatMsg("error.no.operative.descriptor",
|
||||||
|
String.valueOf(releaseValue)));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
String uriString = entry.uriString().orElse("");
|
||||||
|
try (InputStream is = entry.bytes()) {
|
||||||
|
describeModule(is, uriString);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// no specific --release specified, output the root, if any
|
||||||
|
if (infos[0].name().equals(MODULE_INFO)) {
|
||||||
|
String uriString = infos[0].uriString().orElse("");
|
||||||
|
try (InputStream is = infos[0].bytes()) {
|
||||||
|
describeModule(is, uriString);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// no root, output message to specify --release
|
||||||
|
output(getMsg("error.no.root.descriptor"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static <T> String toString(Collection<T> set) {
|
static <T> String toString(Collection<T> set) {
|
||||||
if (set.isEmpty()) { return ""; }
|
if (set.isEmpty()) { return ""; }
|
||||||
return set.stream().map(e -> e.toString().toLowerCase(Locale.ROOT))
|
return " " + set.stream().map(e -> e.toString().toLowerCase(Locale.ROOT))
|
||||||
.collect(joining(" "));
|
.sorted().collect(joining(" "));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void describeModule(InputStream entryInputStream, String ename)
|
|
||||||
|
private void describeModule(InputStream entryInputStream, String uriString)
|
||||||
throws IOException
|
throws IOException
|
||||||
{
|
{
|
||||||
ModuleInfo.Attributes attrs = ModuleInfo.read(entryInputStream, null);
|
ModuleInfo.Attributes attrs = ModuleInfo.read(entryInputStream, null);
|
||||||
@ -1804,71 +1927,94 @@ public class Main {
|
|||||||
ModuleTarget target = attrs.target();
|
ModuleTarget target = attrs.target();
|
||||||
ModuleHashes hashes = attrs.recordedHashes();
|
ModuleHashes hashes = attrs.recordedHashes();
|
||||||
|
|
||||||
describeModule(md, target, hashes, ename);
|
describeModule(md, target, hashes, uriString);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void describeModule(ModuleDescriptor md,
|
private void describeModule(ModuleDescriptor md,
|
||||||
ModuleTarget target,
|
ModuleTarget target,
|
||||||
ModuleHashes hashes,
|
ModuleHashes hashes,
|
||||||
String ename)
|
String uriString)
|
||||||
throws IOException
|
throws IOException
|
||||||
{
|
{
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
sb.append("\nmodule ")
|
|
||||||
.append(md.toNameAndVersion())
|
|
||||||
.append(" (").append(ename).append(")");
|
|
||||||
|
|
||||||
|
sb.append(md.toNameAndVersion());
|
||||||
|
|
||||||
|
if (!uriString.equals(""))
|
||||||
|
sb.append(" ").append(uriString);
|
||||||
if (md.isOpen())
|
if (md.isOpen())
|
||||||
sb.append("\n open ");
|
sb.append(" open");
|
||||||
|
if (md.isAutomatic())
|
||||||
md.requires().stream()
|
sb.append(" automatic");
|
||||||
.sorted(Comparator.comparing(Requires::name))
|
sb.append("\n");
|
||||||
.forEach(r -> {
|
|
||||||
sb.append("\n requires ");
|
|
||||||
if (!r.modifiers().isEmpty())
|
|
||||||
sb.append(toString(r.modifiers())).append(" ");
|
|
||||||
sb.append(r.name());
|
|
||||||
});
|
|
||||||
|
|
||||||
md.uses().stream().sorted()
|
|
||||||
.forEach(p -> sb.append("\n uses ").append(p));
|
|
||||||
|
|
||||||
|
// unqualified exports (sorted by package)
|
||||||
md.exports().stream()
|
md.exports().stream()
|
||||||
.sorted(Comparator.comparing(Exports::source))
|
.sorted(Comparator.comparing(Exports::source))
|
||||||
.forEach(p -> sb.append("\n exports ").append(p));
|
.filter(e -> !e.isQualified())
|
||||||
|
.forEach(e -> sb.append("exports ").append(e.source())
|
||||||
|
.append(toString(e.modifiers())).append("\n"));
|
||||||
|
|
||||||
md.opens().stream()
|
// dependences
|
||||||
.sorted(Comparator.comparing(Opens::source))
|
md.requires().stream().sorted()
|
||||||
.forEach(p -> sb.append("\n opens ").append(p));
|
.forEach(r -> sb.append("requires ").append(r.name())
|
||||||
|
.append(toString(r.modifiers())).append("\n"));
|
||||||
|
|
||||||
Set<String> concealed = new HashSet<>(md.packages());
|
// service use and provides
|
||||||
md.exports().stream().map(Exports::source).forEach(concealed::remove);
|
md.uses().stream().sorted()
|
||||||
md.opens().stream().map(Opens::source).forEach(concealed::remove);
|
.forEach(s -> sb.append("uses ").append(s).append("\n"));
|
||||||
concealed.stream().sorted()
|
|
||||||
.forEach(p -> sb.append("\n contains ").append(p));
|
|
||||||
|
|
||||||
md.provides().stream()
|
md.provides().stream()
|
||||||
.sorted(Comparator.comparing(Provides::service))
|
.sorted(Comparator.comparing(Provides::service))
|
||||||
.forEach(p -> sb.append("\n provides ").append(p.service())
|
.forEach(p -> sb.append("provides ").append(p.service())
|
||||||
.append(" with ")
|
.append(" with")
|
||||||
.append(toString(p.providers())));
|
.append(toString(p.providers()))
|
||||||
|
.append("\n"));
|
||||||
|
|
||||||
md.mainClass().ifPresent(v -> sb.append("\n main-class " + v));
|
// qualified exports
|
||||||
|
md.exports().stream()
|
||||||
|
.sorted(Comparator.comparing(Exports::source))
|
||||||
|
.filter(Exports::isQualified)
|
||||||
|
.forEach(e -> sb.append("qualified exports ").append(e.source())
|
||||||
|
.append(" to").append(toString(e.targets()))
|
||||||
|
.append("\n"));
|
||||||
|
|
||||||
|
// open packages
|
||||||
|
md.opens().stream()
|
||||||
|
.sorted(Comparator.comparing(Opens::source))
|
||||||
|
.filter(o -> !o.isQualified())
|
||||||
|
.forEach(o -> sb.append("opens ").append(o.source())
|
||||||
|
.append(toString(o.modifiers()))
|
||||||
|
.append("\n"));
|
||||||
|
|
||||||
|
md.opens().stream()
|
||||||
|
.sorted(Comparator.comparing(Opens::source))
|
||||||
|
.filter(Opens::isQualified)
|
||||||
|
.forEach(o -> sb.append("qualified opens ").append(o.source())
|
||||||
|
.append(toString(o.modifiers()))
|
||||||
|
.append(" to").append(toString(o.targets()))
|
||||||
|
.append("\n"));
|
||||||
|
|
||||||
|
// non-exported/non-open packages
|
||||||
|
Set<String> concealed = new TreeSet<>(md.packages());
|
||||||
|
md.exports().stream().map(Exports::source).forEach(concealed::remove);
|
||||||
|
md.opens().stream().map(Opens::source).forEach(concealed::remove);
|
||||||
|
concealed.forEach(p -> sb.append("contains ").append(p).append("\n"));
|
||||||
|
|
||||||
|
md.mainClass().ifPresent(v -> sb.append("main-class ").append(v).append("\n"));
|
||||||
|
|
||||||
if (target != null) {
|
if (target != null) {
|
||||||
String osName = target.osName();
|
String targetPlatform = target.targetPlatform();
|
||||||
if (osName != null)
|
if (!targetPlatform.isEmpty())
|
||||||
sb.append("\n operating-system-name " + osName);
|
sb.append("platform ").append(targetPlatform).append("\n");
|
||||||
String osArch = target.osArch();
|
|
||||||
if (osArch != null)
|
|
||||||
sb.append("\n operating-system-architecture " + osArch);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hashes != null) {
|
if (hashes != null) {
|
||||||
hashes.names().stream().sorted().forEach(
|
hashes.names().stream().sorted().forEach(
|
||||||
mod -> sb.append("\n hashes ").append(mod).append(" ")
|
mod -> sb.append("hashes ").append(mod).append(" ")
|
||||||
.append(hashes.algorithm()).append(" ")
|
.append(hashes.algorithm()).append(" ")
|
||||||
.append(toHex(hashes.hashFor(mod))));
|
.append(toHex(hashes.hashFor(mod)))
|
||||||
|
.append("\n"));
|
||||||
}
|
}
|
||||||
|
|
||||||
output(sb.toString());
|
output(sb.toString());
|
||||||
|
@ -116,7 +116,7 @@ final class Validator {
|
|||||||
// version number strings need to be sorted numerically
|
// version number strings need to be sorted numerically
|
||||||
n = VERSIONS_DIR.length(); // skip the common prefix
|
n = VERSIONS_DIR.length(); // skip the common prefix
|
||||||
int i1 = s1.indexOf('/', n);
|
int i1 = s1.indexOf('/', n);
|
||||||
int i2 = s1.indexOf('/', n);
|
int i2 = s2.indexOf('/', n);
|
||||||
if (i1 == -1) throw new InvalidJarException(s1);
|
if (i1 == -1) throw new InvalidJarException(s1);
|
||||||
if (i2 == -1) throw new InvalidJarException(s2);
|
if (i2 == -1) throw new InvalidJarException(s2);
|
||||||
// shorter version numbers go first
|
// shorter version numbers go first
|
||||||
|
@ -45,7 +45,7 @@ error.bad.eflag=\
|
|||||||
'e' flag and manifest with the 'Main-Class' attribute cannot be specified \n\
|
'e' flag and manifest with the 'Main-Class' attribute cannot be specified \n\
|
||||||
together!
|
together!
|
||||||
error.bad.dflag=\
|
error.bad.dflag=\
|
||||||
'-d, --describe-module' option requires no input file(s) to be specified: {0}
|
'-d, --describe-module' option requires no input file(s) to be specified
|
||||||
error.bad.reason=\
|
error.bad.reason=\
|
||||||
bad reason: {0}, must be one of deprecated, deprecated-for-removal, or incubating
|
bad reason: {0}, must be one of deprecated, deprecated-for-removal, or incubating
|
||||||
error.nosuch.fileordir=\
|
error.nosuch.fileordir=\
|
||||||
@ -62,6 +62,10 @@ error.hash.dep=\
|
|||||||
Hashing module {0} dependences, unable to find module {1} on module path
|
Hashing module {0} dependences, unable to find module {1} on module path
|
||||||
error.module.options.without.info=\
|
error.module.options.without.info=\
|
||||||
One of --module-version or --hash-modules without module-info.class
|
One of --module-version or --hash-modules without module-info.class
|
||||||
|
error.no.operative.descriptor=\
|
||||||
|
No operative descriptor for release: {0}
|
||||||
|
error.no.root.descriptor=\
|
||||||
|
No root module descriptor, specify --release
|
||||||
error.unable.derive.automodule=\
|
error.unable.derive.automodule=\
|
||||||
Unable to derive module descriptor for: {0}
|
Unable to derive module descriptor for: {0}
|
||||||
error.unexpected.module-info=\
|
error.unexpected.module-info=\
|
||||||
|
@ -152,14 +152,14 @@ public final class DefaultImageBuilder implements ImageBuilder {
|
|||||||
@Override
|
@Override
|
||||||
public void storeFiles(ResourcePool files) {
|
public void storeFiles(ResourcePool files) {
|
||||||
try {
|
try {
|
||||||
String targetOsName = files.moduleView()
|
String value = files.moduleView()
|
||||||
.findModule("java.base")
|
.findModule("java.base")
|
||||||
.map(ResourcePoolModule::osName)
|
.map(ResourcePoolModule::targetPlatform)
|
||||||
.orElse(null);
|
.orElse(null);
|
||||||
if (targetOsName == null) {
|
if (value == null) {
|
||||||
throw new PluginException("ModuleTarget attribute is missing for java.base module");
|
throw new PluginException("ModuleTarget attribute is missing for java.base module");
|
||||||
}
|
}
|
||||||
this.targetPlatform = Platform.toPlatform(targetOsName);
|
this.targetPlatform = Platform.toPlatform(value);
|
||||||
|
|
||||||
checkResourcePool(files);
|
checkResourcePool(files);
|
||||||
|
|
||||||
|
@ -324,15 +324,9 @@ public final class ImagePluginStack {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String osName() {
|
public String targetPlatform() {
|
||||||
initModuleAttributes();
|
initModuleAttributes();
|
||||||
return target != null? target.osName() : null;
|
return target != null? target.targetPlatform() : null;
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String osArch() {
|
|
||||||
initModuleAttributes();
|
|
||||||
return target != null? target.osArch() : null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void initModuleAttributes() {
|
private void initModuleAttributes() {
|
||||||
|
@ -40,12 +40,17 @@ public enum Platform {
|
|||||||
UNKNOWN;
|
UNKNOWN;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the {@code Platform} of the given OS name specified
|
* Returns the {@code Platform} derived from the target platform
|
||||||
* in the {@code ModuleTarget} attribute.
|
* in the {@code ModuleTarget} attribute.
|
||||||
*
|
|
||||||
* @param osName OS name in ModuleTarget attribute
|
|
||||||
*/
|
*/
|
||||||
public static Platform toPlatform(String osName) {
|
public static Platform toPlatform(String targetPlatform) {
|
||||||
|
String osName;
|
||||||
|
int index = targetPlatform.indexOf("-");
|
||||||
|
if (index < 0) {
|
||||||
|
osName = targetPlatform;
|
||||||
|
} else {
|
||||||
|
osName = targetPlatform.substring(0, index);
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
return Platform.valueOf(osName.toUpperCase(Locale.ENGLISH));
|
return Platform.valueOf(osName.toUpperCase(Locale.ENGLISH));
|
||||||
} catch (IllegalArgumentException e) {
|
} catch (IllegalArgumentException e) {
|
||||||
@ -57,9 +62,9 @@ public enum Platform {
|
|||||||
* Returns the {@code Platform} to which the given module is target to.
|
* Returns the {@code Platform} to which the given module is target to.
|
||||||
*/
|
*/
|
||||||
public static Platform getTargetPlatform(ResourcePoolModule module) {
|
public static Platform getTargetPlatform(ResourcePoolModule module) {
|
||||||
String osName = module.osName();
|
String targetPlatform = module.targetPlatform();
|
||||||
if (osName != null) {
|
if (targetPlatform != null) {
|
||||||
return toPlatform(osName);
|
return toPlatform(targetPlatform);
|
||||||
} else {
|
} else {
|
||||||
return Platform.UNKNOWN;
|
return Platform.UNKNOWN;
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2015, 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.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -110,15 +110,9 @@ public class ResourcePoolManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String osName() {
|
public String targetPlatform() {
|
||||||
initModuleAttributes();
|
initModuleAttributes();
|
||||||
return target != null? target.osName() : null;
|
return target != null? target.targetPlatform() : null;
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String osArch() {
|
|
||||||
initModuleAttributes();
|
|
||||||
return target != null? target.osArch() : null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void initModuleAttributes() {
|
private void initModuleAttributes() {
|
||||||
|
@ -33,13 +33,13 @@ import java.lang.module.ModuleDescriptor;
|
|||||||
import java.util.EnumSet;
|
import java.util.EnumSet;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Optional;
|
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import jdk.tools.jlink.internal.ModuleSorter;
|
import jdk.tools.jlink.internal.ModuleSorter;
|
||||||
import jdk.tools.jlink.internal.Utils;
|
import jdk.tools.jlink.internal.Utils;
|
||||||
|
import jdk.tools.jlink.plugin.PluginException;
|
||||||
import jdk.tools.jlink.plugin.ResourcePool;
|
import jdk.tools.jlink.plugin.ResourcePool;
|
||||||
import jdk.tools.jlink.plugin.ResourcePoolBuilder;
|
import jdk.tools.jlink.plugin.ResourcePoolBuilder;
|
||||||
import jdk.tools.jlink.plugin.ResourcePoolEntry;
|
import jdk.tools.jlink.plugin.ResourcePoolEntry;
|
||||||
@ -132,18 +132,16 @@ public final class ReleaseInfoPlugin implements Plugin {
|
|||||||
public ResourcePool transform(ResourcePool in, ResourcePoolBuilder out) {
|
public ResourcePool transform(ResourcePool in, ResourcePoolBuilder out) {
|
||||||
in.transformAndCopy(Function.identity(), out);
|
in.transformAndCopy(Function.identity(), out);
|
||||||
|
|
||||||
Optional<ResourcePoolModule> javaBase = in.moduleView().findModule("java.base");
|
ResourcePoolModule javaBase = in.moduleView().findModule("java.base")
|
||||||
javaBase.ifPresent(mod -> {
|
.orElse(null);
|
||||||
// fill release information available from transformed "java.base" module!
|
if (javaBase == null || javaBase.targetPlatform() == null) {
|
||||||
ModuleDescriptor desc = mod.descriptor();
|
throw new PluginException("ModuleTarget attribute is missing for java.base module");
|
||||||
desc.version().ifPresent(s -> release.put("JAVA_VERSION",
|
}
|
||||||
quote(parseVersion(s.toString()))));
|
|
||||||
desc.version().ifPresent(s -> release.put("JAVA_FULL_VERSION",
|
|
||||||
quote(s.toString())));
|
|
||||||
|
|
||||||
release.put("OS_NAME", quote(mod.osName()));
|
// fill release information available from transformed "java.base" module!
|
||||||
release.put("OS_ARCH", quote(mod.osArch()));
|
ModuleDescriptor desc = javaBase.descriptor();
|
||||||
});
|
desc.version().ifPresent(v -> release.put("JAVA_VERSION",
|
||||||
|
quote(parseVersion(v))));
|
||||||
|
|
||||||
// put topological sorted module names separated by space
|
// put topological sorted module names separated by space
|
||||||
release.put("MODULES", new ModuleSorter(in.moduleView())
|
release.put("MODULES", new ModuleSorter(in.moduleView())
|
||||||
@ -152,14 +150,15 @@ public final class ReleaseInfoPlugin implements Plugin {
|
|||||||
|
|
||||||
// create a TOP level ResourcePoolEntry for "release" file.
|
// create a TOP level ResourcePoolEntry for "release" file.
|
||||||
out.add(ResourcePoolEntry.create("/java.base/release",
|
out.add(ResourcePoolEntry.create("/java.base/release",
|
||||||
ResourcePoolEntry.Type.TOP, releaseFileContent()));
|
ResourcePoolEntry.Type.TOP,
|
||||||
|
releaseFileContent()));
|
||||||
return out.build();
|
return out.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse version string and return a string that includes only version part
|
// Parse version string and return a string that includes only version part
|
||||||
// leaving "pre", "build" information. See also: java.lang.Runtime.Version.
|
// leaving "pre", "build" information. See also: java.lang.Runtime.Version.
|
||||||
private static String parseVersion(String str) {
|
private static String parseVersion(ModuleDescriptor.Version v) {
|
||||||
return Runtime.Version.parse(str)
|
return Runtime.Version.parse(v.toString())
|
||||||
.version()
|
.version()
|
||||||
.stream()
|
.stream()
|
||||||
.map(Object::toString)
|
.map(Object::toString)
|
||||||
|
@ -211,8 +211,7 @@ public final class SystemModulesPlugin implements Plugin {
|
|||||||
// drop target attribute only if any OS property is present
|
// drop target attribute only if any OS property is present
|
||||||
ModuleTarget target = attrs.target();
|
ModuleTarget target = attrs.target();
|
||||||
if (dropModuleTarget && target != null) {
|
if (dropModuleTarget && target != null) {
|
||||||
this.dropModuleTarget = (target.osName() != null)
|
this.dropModuleTarget = (target.targetPlatform() != null);
|
||||||
|| (target.osArch() != null);
|
|
||||||
} else {
|
} else {
|
||||||
this.dropModuleTarget = false;
|
this.dropModuleTarget = false;
|
||||||
}
|
}
|
||||||
@ -377,7 +376,7 @@ public final class SystemModulesPlugin implements Plugin {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void dropModuleTarget() {
|
void dropModuleTarget() {
|
||||||
extender.targetPlatform("", "");
|
extender.targetPlatform("");
|
||||||
}
|
}
|
||||||
|
|
||||||
byte[] getBytes() throws IOException {
|
byte[] getBytes() throws IOException {
|
||||||
@ -527,8 +526,7 @@ public final class SystemModulesPlugin implements Plugin {
|
|||||||
ModuleDescriptor md = moduleInfo.descriptor;
|
ModuleDescriptor md = moduleInfo.descriptor;
|
||||||
// drop ModuleTarget attribute if java.base has all OS properties
|
// drop ModuleTarget attribute if java.base has all OS properties
|
||||||
ModuleTarget target = moduleInfo.target();
|
ModuleTarget target = moduleInfo.target();
|
||||||
if (dropModuleTarget
|
if (dropModuleTarget && target.targetPlatform() != null) {
|
||||||
&& (target.osName() != null) && (target.osArch() != null)) {
|
|
||||||
dropModuleTarget = true;
|
dropModuleTarget = true;
|
||||||
} else {
|
} else {
|
||||||
dropModuleTarget = false;
|
dropModuleTarget = false;
|
||||||
@ -543,7 +541,7 @@ public final class SystemModulesPlugin implements Plugin {
|
|||||||
moduleInfo.validatePackages();
|
moduleInfo.validatePackages();
|
||||||
|
|
||||||
// module-info.class may be overridden for optimization
|
// module-info.class may be overridden for optimization
|
||||||
// 1. update ModuleTarget attribute to drop osName, osArch, osVersion
|
// 1. update ModuleTarget attribute to drop targetPlartform
|
||||||
// 2. add/update ModulePackages attribute
|
// 2. add/update ModulePackages attribute
|
||||||
if (moduleInfo.shouldRewrite()) {
|
if (moduleInfo.shouldRewrite()) {
|
||||||
entry = entry.copyWithContent(moduleInfo.getBytes());
|
entry = entry.copyWithContent(moduleInfo.getBytes());
|
||||||
@ -655,10 +653,9 @@ public final class SystemModulesPlugin implements Plugin {
|
|||||||
// new ModuleTarget(String, String)
|
// new ModuleTarget(String, String)
|
||||||
mv.visitTypeInsn(NEW, MODULE_TARGET_CLASSNAME);
|
mv.visitTypeInsn(NEW, MODULE_TARGET_CLASSNAME);
|
||||||
mv.visitInsn(DUP);
|
mv.visitInsn(DUP);
|
||||||
mv.visitLdcInsn(minfo.target().osName());
|
mv.visitLdcInsn(minfo.target().targetPlatform());
|
||||||
mv.visitLdcInsn(minfo.target().osArch());
|
|
||||||
mv.visitMethodInsn(INVOKESPECIAL, MODULE_TARGET_CLASSNAME,
|
mv.visitMethodInsn(INVOKESPECIAL, MODULE_TARGET_CLASSNAME,
|
||||||
"<init>", "(Ljava/lang/String;Ljava/lang/String;)V", false);
|
"<init>", "(Ljava/lang/String;)V", false);
|
||||||
|
|
||||||
mv.visitInsn(AASTORE);
|
mv.visitInsn(AASTORE);
|
||||||
}
|
}
|
||||||
|
@ -58,18 +58,11 @@ public interface ResourcePoolModule {
|
|||||||
public ModuleDescriptor descriptor();
|
public ModuleDescriptor descriptor();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The module target OS name for this module.
|
* The target platform
|
||||||
*
|
*
|
||||||
* @return The module target OS name
|
* @return The target platform
|
||||||
*/
|
*/
|
||||||
public String osName();
|
public String targetPlatform();
|
||||||
|
|
||||||
/**
|
|
||||||
* The module target OS arch for this module.
|
|
||||||
*
|
|
||||||
* @return The module target OS arch
|
|
||||||
*/
|
|
||||||
public String osArch();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves all the packages located in this module.
|
* Retrieves all the packages located in this module.
|
||||||
|
@ -177,8 +177,7 @@ public class JmodTask {
|
|||||||
ModuleFinder moduleFinder;
|
ModuleFinder moduleFinder;
|
||||||
Version moduleVersion;
|
Version moduleVersion;
|
||||||
String mainClass;
|
String mainClass;
|
||||||
String osName;
|
String targetPlatform;
|
||||||
String osArch;
|
|
||||||
Pattern modulesToHash;
|
Pattern modulesToHash;
|
||||||
ModuleResolution moduleResolution;
|
ModuleResolution moduleResolution;
|
||||||
boolean dryrun;
|
boolean dryrun;
|
||||||
@ -311,9 +310,9 @@ public class JmodTask {
|
|||||||
try (JmodFile jf = new JmodFile(options.jmodFile)) {
|
try (JmodFile jf = new JmodFile(options.jmodFile)) {
|
||||||
try (InputStream in = jf.getInputStream(Section.CLASSES, MODULE_INFO)) {
|
try (InputStream in = jf.getInputStream(Section.CLASSES, MODULE_INFO)) {
|
||||||
ModuleInfo.Attributes attrs = ModuleInfo.read(in, null);
|
ModuleInfo.Attributes attrs = ModuleInfo.read(in, null);
|
||||||
printModuleDescriptor(attrs.descriptor(),
|
describeModule(attrs.descriptor(),
|
||||||
attrs.target(),
|
attrs.target(),
|
||||||
attrs.recordedHashes());
|
attrs.recordedHashes());
|
||||||
return true;
|
return true;
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new CommandException("err.module.descriptor.not.found");
|
throw new CommandException("err.module.descriptor.not.found");
|
||||||
@ -323,66 +322,92 @@ public class JmodTask {
|
|||||||
|
|
||||||
static <T> String toString(Collection<T> c) {
|
static <T> String toString(Collection<T> c) {
|
||||||
if (c.isEmpty()) { return ""; }
|
if (c.isEmpty()) { return ""; }
|
||||||
return c.stream().map(e -> e.toString().toLowerCase(Locale.ROOT))
|
return " " + c.stream().map(e -> e.toString().toLowerCase(Locale.ROOT))
|
||||||
.collect(joining(" "));
|
.sorted().collect(joining(" "));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void printModuleDescriptor(ModuleDescriptor md,
|
private void describeModule(ModuleDescriptor md,
|
||||||
ModuleTarget target,
|
ModuleTarget target,
|
||||||
ModuleHashes hashes)
|
ModuleHashes hashes)
|
||||||
throws IOException
|
throws IOException
|
||||||
{
|
{
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
sb.append("\n").append(md.toNameAndVersion());
|
|
||||||
|
|
||||||
md.requires().stream()
|
sb.append(md.toNameAndVersion());
|
||||||
.sorted(Comparator.comparing(Requires::name))
|
|
||||||
.forEach(r -> {
|
|
||||||
sb.append("\n requires ");
|
|
||||||
if (!r.modifiers().isEmpty())
|
|
||||||
sb.append(toString(r.modifiers())).append(" ");
|
|
||||||
sb.append(r.name());
|
|
||||||
});
|
|
||||||
|
|
||||||
md.uses().stream().sorted()
|
if (md.isOpen())
|
||||||
.forEach(s -> sb.append("\n uses ").append(s));
|
sb.append(" open");
|
||||||
|
if (md.isAutomatic())
|
||||||
|
sb.append(" automatic");
|
||||||
|
sb.append("\n");
|
||||||
|
|
||||||
|
// unqualified exports (sorted by package)
|
||||||
md.exports().stream()
|
md.exports().stream()
|
||||||
.sorted(Comparator.comparing(Exports::source))
|
.sorted(Comparator.comparing(Exports::source))
|
||||||
.forEach(p -> sb.append("\n exports ").append(p));
|
.filter(e -> !e.isQualified())
|
||||||
|
.forEach(e -> sb.append("exports ").append(e.source())
|
||||||
|
.append(toString(e.modifiers())).append("\n"));
|
||||||
|
|
||||||
md.opens().stream()
|
// dependences
|
||||||
.sorted(Comparator.comparing(Opens::source))
|
md.requires().stream().sorted()
|
||||||
.forEach(p -> sb.append("\n opens ").append(p));
|
.forEach(r -> sb.append("requires ").append(r.name())
|
||||||
|
.append(toString(r.modifiers())).append("\n"));
|
||||||
|
|
||||||
Set<String> concealed = new HashSet<>(md.packages());
|
// service use and provides
|
||||||
md.exports().stream().map(Exports::source).forEach(concealed::remove);
|
md.uses().stream().sorted()
|
||||||
md.opens().stream().map(Opens::source).forEach(concealed::remove);
|
.forEach(s -> sb.append("uses ").append(s).append("\n"));
|
||||||
concealed.stream().sorted()
|
|
||||||
.forEach(p -> sb.append("\n contains ").append(p));
|
|
||||||
|
|
||||||
md.provides().stream()
|
md.provides().stream()
|
||||||
.sorted(Comparator.comparing(Provides::service))
|
.sorted(Comparator.comparing(Provides::service))
|
||||||
.forEach(p -> sb.append("\n provides ").append(p.service())
|
.forEach(p -> sb.append("provides ").append(p.service())
|
||||||
.append(" with ")
|
.append(" with")
|
||||||
.append(toString(p.providers())));
|
.append(toString(p.providers()))
|
||||||
|
.append("\n"));
|
||||||
|
|
||||||
md.mainClass().ifPresent(v -> sb.append("\n main-class " + v));
|
// qualified exports
|
||||||
|
md.exports().stream()
|
||||||
|
.sorted(Comparator.comparing(Exports::source))
|
||||||
|
.filter(Exports::isQualified)
|
||||||
|
.forEach(e -> sb.append("qualified exports ").append(e.source())
|
||||||
|
.append(" to").append(toString(e.targets()))
|
||||||
|
.append("\n"));
|
||||||
|
|
||||||
|
// open packages
|
||||||
|
md.opens().stream()
|
||||||
|
.sorted(Comparator.comparing(Opens::source))
|
||||||
|
.filter(o -> !o.isQualified())
|
||||||
|
.forEach(o -> sb.append("opens ").append(o.source())
|
||||||
|
.append(toString(o.modifiers()))
|
||||||
|
.append("\n"));
|
||||||
|
|
||||||
|
md.opens().stream()
|
||||||
|
.sorted(Comparator.comparing(Opens::source))
|
||||||
|
.filter(Opens::isQualified)
|
||||||
|
.forEach(o -> sb.append("qualified opens ").append(o.source())
|
||||||
|
.append(toString(o.modifiers()))
|
||||||
|
.append(" to").append(toString(o.targets()))
|
||||||
|
.append("\n"));
|
||||||
|
|
||||||
|
// non-exported/non-open packages
|
||||||
|
Set<String> concealed = new TreeSet<>(md.packages());
|
||||||
|
md.exports().stream().map(Exports::source).forEach(concealed::remove);
|
||||||
|
md.opens().stream().map(Opens::source).forEach(concealed::remove);
|
||||||
|
concealed.forEach(p -> sb.append("contains ").append(p).append("\n"));
|
||||||
|
|
||||||
|
md.mainClass().ifPresent(v -> sb.append("main-class ").append(v).append("\n"));
|
||||||
|
|
||||||
if (target != null) {
|
if (target != null) {
|
||||||
String osName = target.osName();
|
String targetPlatform = target.targetPlatform();
|
||||||
if (osName != null)
|
if (!targetPlatform.isEmpty())
|
||||||
sb.append("\n operating-system-name " + osName);
|
sb.append("platform ").append(targetPlatform).append("\n");
|
||||||
String osArch = target.osArch();
|
}
|
||||||
if (osArch != null)
|
|
||||||
sb.append("\n operating-system-architecture " + osArch);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hashes != null) {
|
if (hashes != null) {
|
||||||
hashes.names().stream().sorted().forEach(
|
hashes.names().stream().sorted().forEach(
|
||||||
mod -> sb.append("\n hashes ").append(mod).append(" ")
|
mod -> sb.append("hashes ").append(mod).append(" ")
|
||||||
.append(hashes.algorithm()).append(" ")
|
.append(hashes.algorithm()).append(" ")
|
||||||
.append(toHex(hashes.hashFor(mod))));
|
.append(toHex(hashes.hashFor(mod)))
|
||||||
|
.append("\n"));
|
||||||
}
|
}
|
||||||
|
|
||||||
out.println(sb.toString());
|
out.println(sb.toString());
|
||||||
@ -437,8 +462,7 @@ public class JmodTask {
|
|||||||
|
|
||||||
final Version moduleVersion = options.moduleVersion;
|
final Version moduleVersion = options.moduleVersion;
|
||||||
final String mainClass = options.mainClass;
|
final String mainClass = options.mainClass;
|
||||||
final String osName = options.osName;
|
final String targetPlatform = options.targetPlatform;
|
||||||
final String osArch = options.osArch;
|
|
||||||
final List<PathMatcher> excludes = options.excludes;
|
final List<PathMatcher> excludes = options.excludes;
|
||||||
final ModuleResolution moduleResolution = options.moduleResolution;
|
final ModuleResolution moduleResolution = options.moduleResolution;
|
||||||
|
|
||||||
@ -534,9 +558,10 @@ public class JmodTask {
|
|||||||
if (mainClass != null)
|
if (mainClass != null)
|
||||||
extender.mainClass(mainClass);
|
extender.mainClass(mainClass);
|
||||||
|
|
||||||
// --os-name, --os-arch
|
// --target-platform
|
||||||
if (osName != null || osArch != null)
|
if (targetPlatform != null) {
|
||||||
extender.targetPlatform(osName, osArch);
|
extender.targetPlatform(targetPlatform);
|
||||||
|
}
|
||||||
|
|
||||||
// --module-version
|
// --module-version
|
||||||
if (moduleVersion != null)
|
if (moduleVersion != null)
|
||||||
@ -1327,15 +1352,10 @@ public class JmodTask {
|
|||||||
.withRequiredArg()
|
.withRequiredArg()
|
||||||
.withValuesConvertedBy(new ModuleVersionConverter());
|
.withValuesConvertedBy(new ModuleVersionConverter());
|
||||||
|
|
||||||
OptionSpec<String> osName
|
OptionSpec<String> targetPlatform
|
||||||
= parser.accepts("os-name", getMessage("main.opt.os-name"))
|
= parser.accepts("target-platform", getMessage("main.opt.target-platform"))
|
||||||
.withRequiredArg()
|
.withRequiredArg()
|
||||||
.describedAs(getMessage("main.opt.os-name.arg"));
|
.describedAs(getMessage("main.opt.target-platform.arg"));
|
||||||
|
|
||||||
OptionSpec<String> osArch
|
|
||||||
= parser.accepts("os-arch", getMessage("main.opt.os-arch"))
|
|
||||||
.withRequiredArg()
|
|
||||||
.describedAs(getMessage("main.opt.os-arch.arg"));
|
|
||||||
|
|
||||||
OptionSpec<Void> doNotResolveByDefault
|
OptionSpec<Void> doNotResolveByDefault
|
||||||
= parser.accepts("do-not-resolve-by-default",
|
= parser.accepts("do-not-resolve-by-default",
|
||||||
@ -1400,10 +1420,8 @@ public class JmodTask {
|
|||||||
options.moduleVersion = getLastElement(opts.valuesOf(moduleVersion));
|
options.moduleVersion = getLastElement(opts.valuesOf(moduleVersion));
|
||||||
if (opts.has(mainClass))
|
if (opts.has(mainClass))
|
||||||
options.mainClass = getLastElement(opts.valuesOf(mainClass));
|
options.mainClass = getLastElement(opts.valuesOf(mainClass));
|
||||||
if (opts.has(osName))
|
if (opts.has(targetPlatform))
|
||||||
options.osName = getLastElement(opts.valuesOf(osName));
|
options.targetPlatform = getLastElement(opts.valuesOf(targetPlatform));
|
||||||
if (opts.has(osArch))
|
|
||||||
options.osArch = getLastElement(opts.valuesOf(osArch));
|
|
||||||
if (opts.has(warnIfResolved))
|
if (opts.has(warnIfResolved))
|
||||||
options.moduleResolution = getLastElement(opts.valuesOf(warnIfResolved));
|
options.moduleResolution = getLastElement(opts.valuesOf(warnIfResolved));
|
||||||
if (opts.has(doNotResolveByDefault)) {
|
if (opts.has(doNotResolveByDefault)) {
|
||||||
|
@ -64,10 +64,8 @@ main.opt.module-version= Module version
|
|||||||
main.opt.main-class=Main class
|
main.opt.main-class=Main class
|
||||||
main.opt.main-class.arg=class-name
|
main.opt.main-class.arg=class-name
|
||||||
main.opt.man-pages=Location of man pages
|
main.opt.man-pages=Location of man pages
|
||||||
main.opt.os-name=Operating system name
|
main.opt.target-platform=Target platform
|
||||||
main.opt.os-name.arg=os-name
|
main.opt.target-platform.arg=target-platform
|
||||||
main.opt.os-arch=Operating system architecture
|
|
||||||
main.opt.os-arch.arg=os-arch
|
|
||||||
main.opt.module-path=Module path
|
main.opt.module-path=Module path
|
||||||
main.opt.hash-modules=Compute and record hashes to tie a packaged module\
|
main.opt.hash-modules=Compute and record hashes to tie a packaged module\
|
||||||
\ with modules matching the given <regex-pattern> and depending upon it directly\
|
\ with modules matching the given <regex-pattern> and depending upon it directly\
|
||||||
|
@ -66,6 +66,7 @@ public class CheckOrigin {
|
|||||||
"-XX:+UseCodeAging",
|
"-XX:+UseCodeAging",
|
||||||
"-XX:+UseCerealGC", // Should be ignored.
|
"-XX:+UseCerealGC", // Should be ignored.
|
||||||
"-XX:Flags=" + flagsFile.getAbsolutePath(),
|
"-XX:Flags=" + flagsFile.getAbsolutePath(),
|
||||||
|
"-Djdk.attach.allowAttachSelf",
|
||||||
"-cp", System.getProperty("test.class.path"),
|
"-cp", System.getProperty("test.class.path"),
|
||||||
"CheckOrigin",
|
"CheckOrigin",
|
||||||
"-runtests");
|
"-runtests");
|
||||||
|
61
jdk/test/com/sun/tools/attach/AttachSelf.java
Normal file
61
jdk/test/com/sun/tools/attach/AttachSelf.java
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import com.sun.tools.attach.VirtualMachine;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @test
|
||||||
|
* @modules jdk.attach
|
||||||
|
* @run main AttachSelf
|
||||||
|
* @run main/othervm -Djdk.attach.allowAttachSelf AttachSelf
|
||||||
|
* @run main/othervm -Djdk.attach.allowAttachSelf=true AttachSelf
|
||||||
|
* @run main/othervm -Djdk.attach.allowAttachSelf=false AttachSelf
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class AttachSelf {
|
||||||
|
|
||||||
|
public static void main(String[] args) throws Exception {
|
||||||
|
|
||||||
|
String value = System.getProperty("jdk.attach.allowAttachSelf");
|
||||||
|
boolean canAttachSelf = (value != null) && !value.equals("false");
|
||||||
|
|
||||||
|
String vmid = "" + ProcessHandle.current().pid();
|
||||||
|
|
||||||
|
VirtualMachine vm = null;
|
||||||
|
try {
|
||||||
|
vm = VirtualMachine.attach(vmid);
|
||||||
|
if (!canAttachSelf)
|
||||||
|
throw new RuntimeException("Attached to self not expected");
|
||||||
|
} catch (IOException ioe) {
|
||||||
|
if (canAttachSelf)
|
||||||
|
throw ioe;
|
||||||
|
} finally {
|
||||||
|
if (vm != null) vm.detach();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -48,7 +48,10 @@ public class RunnerUtil {
|
|||||||
*/
|
*/
|
||||||
public static ProcessThread startApplication(String... additionalOpts) throws Throwable {
|
public static ProcessThread startApplication(String... additionalOpts) throws Throwable {
|
||||||
String classpath = System.getProperty("test.class.path", ".");
|
String classpath = System.getProperty("test.class.path", ".");
|
||||||
String[] myArgs = concat(additionalOpts, new String [] { "-XX:+UsePerfData", "-Dattach.test=true", "-classpath", classpath, "Application" });
|
String[] myArgs = concat(additionalOpts, new String [] {
|
||||||
|
"-XX:+UsePerfData", "-XX:+EnableDynamicAgentLoading",
|
||||||
|
"-Dattach.test=true", "-classpath", classpath, "Application"
|
||||||
|
});
|
||||||
String[] args = Utils.addTestJavaOpts(myArgs);
|
String[] args = Utils.addTestJavaOpts(myArgs);
|
||||||
ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(args);
|
ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(args);
|
||||||
ProcessThread pt = new ProcessThread("runApplication", (line) -> line.equals(Application.READY_MSG), pb);
|
ProcessThread pt = new ProcessThread("runApplication", (line) -> line.equals(Application.READY_MSG), pb);
|
||||||
|
@ -8,7 +8,8 @@ grant {
|
|||||||
permission com.sun.tools.attach.AttachPermission "createAttachProvider";
|
permission com.sun.tools.attach.AttachPermission "createAttachProvider";
|
||||||
|
|
||||||
/* implementation specific */
|
/* implementation specific */
|
||||||
permission java.lang.RuntimePermission "accessClassInPackage.sun.misc";
|
permission java.lang.RuntimePermission "manageProcess";
|
||||||
|
permission java.lang.RuntimePermission "accessClassInPackage.jdk.internal.misc";
|
||||||
permission java.lang.RuntimePermission "accessClassInPackage.sun.tools.attach";
|
permission java.lang.RuntimePermission "accessClassInPackage.sun.tools.attach";
|
||||||
permission java.lang.RuntimePermission "accessClassInPackage.sun.jvmstat.monitor";
|
permission java.lang.RuntimePermission "accessClassInPackage.sun.jvmstat.monitor";
|
||||||
permission java.lang.RuntimePermission "loadLibrary.attach";
|
permission java.lang.RuntimePermission "loadLibrary.attach";
|
||||||
|
30
jdk/test/com/sun/tools/attach/modules/Agent.java
Normal file
30
jdk/test/com/sun/tools/attach/modules/Agent.java
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import java.lang.instrument.Instrumentation;
|
||||||
|
|
||||||
|
public class Agent {
|
||||||
|
|
||||||
|
public static void agentmain(String agentArgs, Instrumentation inst) {
|
||||||
|
}
|
||||||
|
}
|
35
jdk/test/com/sun/tools/attach/modules/Driver.java
Normal file
35
jdk/test/com/sun/tools/attach/modules/Driver.java
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
/*
|
||||||
|
* 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 jdk.attach
|
||||||
|
* @build m/* Agent
|
||||||
|
* @run main/othervm -Djdk.attach.allowAttachSelf m/p.Main jmx javaagent
|
||||||
|
* @run main/othervm -Djdk.attach.allowAttachSelf m/p.Main javaagent jmx
|
||||||
|
* @run main/othervm --limit-modules=jdk.attach -Djdk.attach.allowAttachSelf m/p.Main jmx javaagent
|
||||||
|
* @run main/othervm --limit-modules=jdk.attach -Djdk.attach.allowAttachSelf m/p.Main javaagent jmx
|
||||||
|
* @summary Basic test to ensure that a JMX agent or a tool agent can be loaded/started in
|
||||||
|
* a modular application.
|
||||||
|
*/
|
||||||
|
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -21,8 +21,7 @@
|
|||||||
* questions.
|
* questions.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package javax.transaction.atomic;
|
module m {
|
||||||
|
exports p;
|
||||||
public interface Atomic {
|
requires jdk.attach;
|
||||||
|
|
||||||
}
|
}
|
164
jdk/test/com/sun/tools/attach/modules/m/p/Main.java
Normal file
164
jdk/test/com/sun/tools/attach/modules/m/p/Main.java
Normal file
@ -0,0 +1,164 @@
|
|||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package p;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.Paths;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.jar.Attributes;
|
||||||
|
import java.util.jar.JarEntry;
|
||||||
|
import java.util.jar.JarFile;
|
||||||
|
import java.util.jar.JarOutputStream;
|
||||||
|
import java.util.jar.Manifest;
|
||||||
|
|
||||||
|
import com.sun.tools.attach.VirtualMachine;
|
||||||
|
|
||||||
|
public class Main {
|
||||||
|
|
||||||
|
public static void main(String[] args) throws Exception {
|
||||||
|
System.out.println("#modules loaded: " + moduleInfoCont());
|
||||||
|
|
||||||
|
String vmid = "" + ProcessHandle.current().pid();
|
||||||
|
VirtualMachine vm = VirtualMachine.attach(vmid);
|
||||||
|
|
||||||
|
for (String test : args) {
|
||||||
|
switch (test) {
|
||||||
|
case "jmx" :
|
||||||
|
startJMXAgent(vm);
|
||||||
|
break;
|
||||||
|
case "javaagent" :
|
||||||
|
startJavaAgent(vm, createAgentJar());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
System.out.println("#modules loaded: " + moduleInfoCont());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Locates module-info.class resources to get a count of the module of system
|
||||||
|
* modules.
|
||||||
|
*/
|
||||||
|
static long moduleInfoCont() {
|
||||||
|
ClassLoader scl = ClassLoader.getSystemClassLoader();
|
||||||
|
return scl.resources("module-info.class").count();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Starts a JMX agent and checks that java.management is loaded.
|
||||||
|
*/
|
||||||
|
static void startJMXAgent(VirtualMachine vm) throws Exception {
|
||||||
|
System.out.println("Start JMX agent");
|
||||||
|
vm.startLocalManagementAgent();
|
||||||
|
|
||||||
|
// types in java.management should be visible
|
||||||
|
Class.forName("javax.management.MXBean");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads a java agent into the VM and checks that java.instrument is loaded.
|
||||||
|
*/
|
||||||
|
static void startJavaAgent(VirtualMachine vm, Path agent) throws Exception {
|
||||||
|
System.out.println("Load java agent ...");
|
||||||
|
vm.loadAgent(agent.toString());
|
||||||
|
|
||||||
|
// the Agent class should be visible
|
||||||
|
Class.forName("Agent");
|
||||||
|
|
||||||
|
// types in java.instrument should be visible
|
||||||
|
Class.forName("java.lang.instrument.Instrumentation");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a java agent, return the file path to the agent JAR file.
|
||||||
|
*/
|
||||||
|
static Path createAgentJar() throws IOException {
|
||||||
|
Manifest man = new Manifest();
|
||||||
|
Attributes attrs = man.getMainAttributes();
|
||||||
|
attrs.put(Attributes.Name.MANIFEST_VERSION, "1.0.0");
|
||||||
|
attrs.put(new Attributes.Name("Agent-Class"), "Agent");
|
||||||
|
Path agent = Paths.get("agent.jar");
|
||||||
|
Path dir = Paths.get(System.getProperty("test.classes"));
|
||||||
|
createJarFile(agent, man, dir, "Agent.class");
|
||||||
|
return agent;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a JAR file.
|
||||||
|
*
|
||||||
|
* Equivalent to {@code jar cfm <jarfile> <manifest> -C <dir> file...}
|
||||||
|
*
|
||||||
|
* The input files are resolved against the given directory. Any input
|
||||||
|
* files that are directories are processed recursively.
|
||||||
|
*/
|
||||||
|
static void createJarFile(Path jarfile, Manifest man, Path dir, String... files)
|
||||||
|
throws IOException
|
||||||
|
{
|
||||||
|
// create the target directory
|
||||||
|
Path parent = jarfile.getParent();
|
||||||
|
if (parent != null)
|
||||||
|
Files.createDirectories(parent);
|
||||||
|
|
||||||
|
List<Path> entries = new ArrayList<>();
|
||||||
|
for (String file : files) {
|
||||||
|
Files.find(dir.resolve(file), Integer.MAX_VALUE,
|
||||||
|
(p, attrs) -> attrs.isRegularFile())
|
||||||
|
.map(e -> dir.relativize(e))
|
||||||
|
.forEach(entries::add);
|
||||||
|
}
|
||||||
|
|
||||||
|
try (OutputStream out = Files.newOutputStream(jarfile);
|
||||||
|
JarOutputStream jos = new JarOutputStream(out))
|
||||||
|
{
|
||||||
|
if (man != null) {
|
||||||
|
JarEntry je = new JarEntry(JarFile.MANIFEST_NAME);
|
||||||
|
jos.putNextEntry(je);
|
||||||
|
man.write(jos);
|
||||||
|
jos.closeEntry();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Path entry : entries) {
|
||||||
|
String name = toJarEntryName(entry);
|
||||||
|
jos.putNextEntry(new JarEntry(name));
|
||||||
|
Files.copy(dir.resolve(entry), jos);
|
||||||
|
jos.closeEntry();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Map a file path to the equivalent name in a JAR file
|
||||||
|
*/
|
||||||
|
static String toJarEntryName(Path file) {
|
||||||
|
Path normalized = file.normalize();
|
||||||
|
return normalized.subpath(0, normalized.getNameCount())
|
||||||
|
.toString()
|
||||||
|
.replace(File.separatorChar, '/');
|
||||||
|
}
|
||||||
|
}
|
33
jdk/test/java/lang/instrument/executableJAR/Agent.java
Normal file
33
jdk/test/java/lang/instrument/executableJAR/Agent.java
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import java.lang.instrument.Instrumentation;
|
||||||
|
|
||||||
|
public class Agent {
|
||||||
|
|
||||||
|
public static Instrumentation inst;
|
||||||
|
|
||||||
|
public static void agentmain(String agentArgs, Instrumentation inst) {
|
||||||
|
Agent.inst = inst;
|
||||||
|
}
|
||||||
|
}
|
25
jdk/test/java/lang/instrument/executableJAR/AgentHelper.java
Normal file
25
jdk/test/java/lang/instrument/executableJAR/AgentHelper.java
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class AgentHelper {
|
||||||
|
}
|
@ -0,0 +1,138 @@
|
|||||||
|
/*
|
||||||
|
* 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
|
||||||
|
* @library /lib/testlibrary
|
||||||
|
* @build ExecJarWithAgent Main Agent AgentHelper JarUtils jdk.testlibrary.*
|
||||||
|
* @run testng ExecJarWithAgent
|
||||||
|
* @summary Test starting agents in executable JAR files
|
||||||
|
*/
|
||||||
|
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.Paths;
|
||||||
|
import java.util.jar.Attributes;
|
||||||
|
import java.util.jar.Manifest;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
import org.testng.annotations.Test;
|
||||||
|
import static org.testng.Assert.*;
|
||||||
|
|
||||||
|
import jdk.testlibrary.ProcessTools;
|
||||||
|
import jdk.testlibrary.OutputAnalyzer;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public class ExecJarWithAgent {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Basic test of java -jar with agent in the executable JAR
|
||||||
|
*/
|
||||||
|
public void testBasic() throws Exception {
|
||||||
|
Manifest man = new Manifest();
|
||||||
|
Attributes attrs = man.getMainAttributes();
|
||||||
|
attrs.put(Attributes.Name.MANIFEST_VERSION, "1.0.0");
|
||||||
|
attrs.put(Attributes.Name.MAIN_CLASS, "Main");
|
||||||
|
attrs.put(new Attributes.Name("Launcher-Agent-Class"), "Agent");
|
||||||
|
|
||||||
|
// require all capabilities
|
||||||
|
attrs.put(new Attributes.Name("Can-Redefine-Classes"), "true");
|
||||||
|
attrs.put(new Attributes.Name("Can-Retransform-Classes"), "true");
|
||||||
|
attrs.put(new Attributes.Name("Can-Set-Native-Method-Prefix"), "true");
|
||||||
|
attrs.put(new Attributes.Name("Boot-Class-Path"), "helper.jar");
|
||||||
|
|
||||||
|
Path app = Paths.get("app.jar");
|
||||||
|
Path dir = Paths.get(System.getProperty("test.classes"));
|
||||||
|
|
||||||
|
Path[] paths = Stream.of("Main.class", "Agent.class")
|
||||||
|
.map(Paths::get)
|
||||||
|
.toArray(Path[]::new);
|
||||||
|
|
||||||
|
JarUtils.createJarFile(app, man, dir, paths);
|
||||||
|
|
||||||
|
// helper API to test that the BCP has been extended
|
||||||
|
Path helper = Paths.get("helper.jar");
|
||||||
|
JarUtils.createJarFile(helper, dir, "AgentHelper.class");
|
||||||
|
|
||||||
|
// java -jar app.jar
|
||||||
|
assertEquals(exec(app).getExitValue(), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test that java -jar fails when the executable JAR has the
|
||||||
|
* Launcher-Agent-Class attribute but the class cannot be loaded.
|
||||||
|
*/
|
||||||
|
public void testBadAgentClass() throws Exception {
|
||||||
|
Manifest man = new Manifest();
|
||||||
|
Attributes attrs = man.getMainAttributes();
|
||||||
|
attrs.put(Attributes.Name.MANIFEST_VERSION, "1.0.0");
|
||||||
|
attrs.put(Attributes.Name.MAIN_CLASS, "Main");
|
||||||
|
|
||||||
|
// agent class does not exist
|
||||||
|
attrs.put(new Attributes.Name("Launcher-Agent-Class"), "BadAgent");
|
||||||
|
|
||||||
|
Path app = Paths.get("app.jar");
|
||||||
|
Path dir = Paths.get(System.getProperty("test.classes"));
|
||||||
|
|
||||||
|
JarUtils.createJarFile(app, man, dir, Paths.get("Main.class"));
|
||||||
|
|
||||||
|
// java -jar app.jar
|
||||||
|
int exitCode = exec(app).shouldContain("ClassNotFoundException").getExitValue();
|
||||||
|
assertNotEquals(exitCode, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test that java -jar fails when the executable JAR has the
|
||||||
|
* Launcher-Agent-Class attribute and the class does not define an
|
||||||
|
* agentmain method.
|
||||||
|
*/
|
||||||
|
public void testNoAgentMain() throws Exception {
|
||||||
|
// manifest for the executable JAR
|
||||||
|
Manifest man = new Manifest();
|
||||||
|
Attributes attrs = man.getMainAttributes();
|
||||||
|
attrs.put(Attributes.Name.MANIFEST_VERSION, "1.0.0");
|
||||||
|
attrs.put(Attributes.Name.MAIN_CLASS, "Main");
|
||||||
|
|
||||||
|
// the main class does not define the agentmain method
|
||||||
|
attrs.put(new Attributes.Name("Launcher-Agent-Class"), "Main");
|
||||||
|
|
||||||
|
Path app = Paths.get("app.jar");
|
||||||
|
Path dir = Paths.get(System.getProperty("test.classes"));
|
||||||
|
|
||||||
|
JarUtils.createJarFile(app, man, dir, Paths.get("Main.class"));
|
||||||
|
|
||||||
|
// java -jar app.jar
|
||||||
|
int exitCode = exec(app).shouldContain("NoSuchMethodException").getExitValue();
|
||||||
|
assertNotEquals(exitCode, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* java -jar app.jar, returning the OutputAnalyzer to analyze the output
|
||||||
|
*/
|
||||||
|
private OutputAnalyzer exec(Path appJar) throws Exception {
|
||||||
|
return ProcessTools.executeTestJava("-jar", appJar.toString())
|
||||||
|
.outputTo(System.out)
|
||||||
|
.errorTo(System.out);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
41
jdk/test/java/lang/instrument/executableJAR/Main.java
Normal file
41
jdk/test/java/lang/instrument/executableJAR/Main.java
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import java.lang.instrument.Instrumentation;
|
||||||
|
|
||||||
|
public class Main {
|
||||||
|
public static void main(String[] args) throws Exception {
|
||||||
|
Instrumentation inst = Agent.inst;
|
||||||
|
if (inst == null)
|
||||||
|
throw new RuntimeException("Agent not loaded");
|
||||||
|
|
||||||
|
// check boot class path has been extended
|
||||||
|
Class<?> helper = Class.forName("AgentHelper");
|
||||||
|
if (helper.getClassLoader() != null)
|
||||||
|
throw new RuntimeException("AgentHelper not loaded by boot loader");
|
||||||
|
|
||||||
|
// check Instrumentation object can be used
|
||||||
|
Class<?>[] classes = inst.getAllLoadedClasses();
|
||||||
|
System.out.println(classes.length + " classes loaded");
|
||||||
|
}
|
||||||
|
}
|
@ -75,7 +75,7 @@ public class DefineClassTest {
|
|||||||
@Test
|
@Test
|
||||||
public void testDefineClass() throws Exception {
|
public void testDefineClass() throws Exception {
|
||||||
final String CLASS_NAME = THIS_PACKAGE + ".Foo";
|
final String CLASS_NAME = THIS_PACKAGE + ".Foo";
|
||||||
Lookup lookup = lookup().dropLookupMode(PRIVATE);
|
Lookup lookup = lookup();
|
||||||
Class<?> clazz = lookup.defineClass(generateClass(CLASS_NAME));
|
Class<?> clazz = lookup.defineClass(generateClass(CLASS_NAME));
|
||||||
|
|
||||||
// test name
|
// test name
|
||||||
@ -101,7 +101,7 @@ public class DefineClassTest {
|
|||||||
public void testAccess() throws Exception {
|
public void testAccess() throws Exception {
|
||||||
final String THIS_CLASS = this.getClass().getName();
|
final String THIS_CLASS = this.getClass().getName();
|
||||||
final String CLASS_NAME = THIS_PACKAGE + ".Runner";
|
final String CLASS_NAME = THIS_PACKAGE + ".Runner";
|
||||||
Lookup lookup = lookup().dropLookupMode(PRIVATE);
|
Lookup lookup = lookup();
|
||||||
|
|
||||||
// public
|
// public
|
||||||
byte[] classBytes = generateRunner(CLASS_NAME + nextNumber(), THIS_CLASS, "method1");
|
byte[] classBytes = generateRunner(CLASS_NAME + nextNumber(), THIS_CLASS, "method1");
|
||||||
@ -144,9 +144,8 @@ public class DefineClassTest {
|
|||||||
final String CLASS_NAME = THIS_PACKAGE + ".ClassWithClinit";
|
final String CLASS_NAME = THIS_PACKAGE + ".ClassWithClinit";
|
||||||
|
|
||||||
byte[] classBytes = generateClassWithInitializer(CLASS_NAME, THIS_CLASS, "fail");
|
byte[] classBytes = generateClassWithInitializer(CLASS_NAME, THIS_CLASS, "fail");
|
||||||
Lookup lookup = lookup().dropLookupMode(PRIVATE);
|
Class<?> clazz = lookup().defineClass(classBytes);
|
||||||
|
|
||||||
Class<?> clazz = lookup.defineClass(classBytes);
|
|
||||||
// trigger initializer to run
|
// trigger initializer to run
|
||||||
try {
|
try {
|
||||||
clazz.newInstance();
|
clazz.newInstance();
|
||||||
@ -186,14 +185,14 @@ public class DefineClassTest {
|
|||||||
assertNotEquals(target1.getProtectionDomain(), target2.getProtectionDomain());
|
assertNotEquals(target1.getProtectionDomain(), target2.getProtectionDomain());
|
||||||
|
|
||||||
// protection domain 1
|
// protection domain 1
|
||||||
Lookup lookup1 = privateLookupIn(target1, lookup()).dropLookupMode(PRIVATE);
|
Lookup lookup1 = privateLookupIn(target1, lookup());
|
||||||
|
|
||||||
Class<?> clazz = lookup1.defineClass(generateClass("p.Foo"));
|
Class<?> clazz = lookup1.defineClass(generateClass("p.Foo"));
|
||||||
testSameAbode(clazz, lookup1.lookupClass());
|
testSameAbode(clazz, lookup1.lookupClass());
|
||||||
testDiscoverable(clazz, lookup1);
|
testDiscoverable(clazz, lookup1);
|
||||||
|
|
||||||
// protection domain 2
|
// protection domain 2
|
||||||
Lookup lookup2 = privateLookupIn(target2, lookup()).dropLookupMode(PRIVATE);
|
Lookup lookup2 = privateLookupIn(target2, lookup());
|
||||||
|
|
||||||
clazz = lookup2.defineClass(generateClass("p.Bar"));
|
clazz = lookup2.defineClass(generateClass("p.Bar"));
|
||||||
testSameAbode(clazz, lookup2.lookupClass());
|
testSameAbode(clazz, lookup2.lookupClass());
|
||||||
@ -205,7 +204,7 @@ public class DefineClassTest {
|
|||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void testBootLoader() throws Exception {
|
public void testBootLoader() throws Exception {
|
||||||
Lookup lookup = privateLookupIn(Thread.class, lookup()).dropLookupMode(PRIVATE);
|
Lookup lookup = privateLookupIn(Thread.class, lookup());
|
||||||
assertTrue(lookup.getClass().getClassLoader() == null);
|
assertTrue(lookup.getClass().getClassLoader() == null);
|
||||||
|
|
||||||
Class<?> clazz = lookup.defineClass(generateClass("java.lang.Foo"));
|
Class<?> clazz = lookup.defineClass(generateClass("java.lang.Foo"));
|
||||||
@ -216,8 +215,7 @@ public class DefineClassTest {
|
|||||||
|
|
||||||
@Test(expectedExceptions = { IllegalArgumentException.class })
|
@Test(expectedExceptions = { IllegalArgumentException.class })
|
||||||
public void testWrongPackage() throws Exception {
|
public void testWrongPackage() throws Exception {
|
||||||
Lookup lookup = lookup().dropLookupMode(PRIVATE);
|
lookup().defineClass(generateClass("other.C"));
|
||||||
lookup.defineClass(generateClass("other.C"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expectedExceptions = { IllegalAccessException.class })
|
@Test(expectedExceptions = { IllegalAccessException.class })
|
||||||
@ -226,23 +224,14 @@ public class DefineClassTest {
|
|||||||
lookup.defineClass(generateClass(THIS_PACKAGE + ".C"));
|
lookup.defineClass(generateClass(THIS_PACKAGE + ".C"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expectedExceptions = { UnsupportedOperationException.class })
|
|
||||||
public void testHasPrivateAccess() throws Exception {
|
|
||||||
Lookup lookup = lookup();
|
|
||||||
assertTrue(lookup.hasPrivateAccess());
|
|
||||||
lookup.defineClass(generateClass(THIS_PACKAGE + ".C"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test(expectedExceptions = { ClassFormatError.class })
|
@Test(expectedExceptions = { ClassFormatError.class })
|
||||||
public void testTruncatedClassFile() throws Exception {
|
public void testTruncatedClassFile() throws Exception {
|
||||||
Lookup lookup = lookup().dropLookupMode(PRIVATE);
|
lookup().defineClass(new byte[0]);
|
||||||
lookup.defineClass(new byte[0]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expectedExceptions = { NullPointerException.class })
|
@Test(expectedExceptions = { NullPointerException.class })
|
||||||
public void testNull() throws Exception {
|
public void testNull() throws Exception {
|
||||||
Lookup lookup = lookup().dropLookupMode(PRIVATE);
|
lookup().defineClass(null);
|
||||||
lookup.defineClass(null);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -402,9 +402,7 @@ public class AutomaticModulesTest {
|
|||||||
// Main-Class files that do not map to a legal qualified type name
|
// Main-Class files that do not map to a legal qualified type name
|
||||||
@DataProvider(name = "badmainclass")
|
@DataProvider(name = "badmainclass")
|
||||||
public Object[][] createBadMainClass() {
|
public Object[][] createBadMainClass() {
|
||||||
return new Object[][]{
|
return new Object[][] {
|
||||||
|
|
||||||
{ "Main", null },
|
|
||||||
{ "p..Main", null },
|
{ "p..Main", null },
|
||||||
{ "p-.Main", null },
|
{ "p-.Main", null },
|
||||||
|
|
||||||
@ -415,7 +413,7 @@ public class AutomaticModulesTest {
|
|||||||
* Test that a JAR file with a Main-Class attribute that is not a qualified
|
* Test that a JAR file with a Main-Class attribute that is not a qualified
|
||||||
* type name.
|
* type name.
|
||||||
*/
|
*/
|
||||||
@Test(dataProvider = "badmainclass", expectedExceptions = FindException.class)
|
@Test(dataProvider = "badmainclass")
|
||||||
public void testBadMainClass(String mainClass, String ignore) throws IOException {
|
public void testBadMainClass(String mainClass, String ignore) throws IOException {
|
||||||
Manifest man = new Manifest();
|
Manifest man = new Manifest();
|
||||||
Attributes attrs = man.getMainAttributes();
|
Attributes attrs = man.getMainAttributes();
|
||||||
@ -426,14 +424,16 @@ public class AutomaticModulesTest {
|
|||||||
String entry = mainClass.replace('.', '/') + ".class";
|
String entry = mainClass.replace('.', '/') + ".class";
|
||||||
createDummyJarFile(dir.resolve("m.jar"), man, entry);
|
createDummyJarFile(dir.resolve("m.jar"), man, entry);
|
||||||
|
|
||||||
// should throw FindException
|
// bad Main-Class value should be ignored
|
||||||
ModuleFinder.of(dir).findAll();
|
Optional<ModuleReference> omref = ModuleFinder.of(dir).find("m");
|
||||||
|
assertTrue(omref.isPresent());
|
||||||
|
ModuleDescriptor descriptor = omref.get().descriptor();
|
||||||
|
assertFalse(descriptor.mainClass().isPresent());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test that a JAR file with a Main-Class attribute that is not in the module
|
* Test that a JAR file with a Main-Class attribute that is not in the module
|
||||||
*/
|
*/
|
||||||
@Test(expectedExceptions = FindException.class)
|
|
||||||
public void testMissingMainClassPackage() throws IOException {
|
public void testMissingMainClassPackage() throws IOException {
|
||||||
Manifest man = new Manifest();
|
Manifest man = new Manifest();
|
||||||
Attributes attrs = man.getMainAttributes();
|
Attributes attrs = man.getMainAttributes();
|
||||||
@ -443,8 +443,11 @@ public class AutomaticModulesTest {
|
|||||||
Path dir = Files.createTempDirectory(USER_DIR, "mods");
|
Path dir = Files.createTempDirectory(USER_DIR, "mods");
|
||||||
createDummyJarFile(dir.resolve("m.jar"), man);
|
createDummyJarFile(dir.resolve("m.jar"), man);
|
||||||
|
|
||||||
// should throw FindException
|
// Main-Class should be ignored because package p is not in module
|
||||||
ModuleFinder.of(dir).findAll();
|
Optional<ModuleReference> omref = ModuleFinder.of(dir).find("m");
|
||||||
|
assertTrue(omref.isPresent());
|
||||||
|
ModuleDescriptor descriptor = omref.get().descriptor();
|
||||||
|
assertFalse(descriptor.mainClass().isPresent());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1843,17 +1843,9 @@ public class ConfigurationTest {
|
|||||||
public Object[][] createPlatformMatches() {
|
public Object[][] createPlatformMatches() {
|
||||||
return new Object[][]{
|
return new Object[][]{
|
||||||
|
|
||||||
{ "linux-arm", "*-*" },
|
{ "", "" },
|
||||||
{ "linux-*", "*-*" },
|
{ "linux-arm", "" },
|
||||||
{ "*-arm", "*-*" },
|
{ "linux-arm", "linux-arm" },
|
||||||
|
|
||||||
{ "linux-*", "linux-*" },
|
|
||||||
{ "linux-arm", "linux-*" },
|
|
||||||
|
|
||||||
{ "*-arm", "*-arm" },
|
|
||||||
{ "linux-arm", "*-arm" },
|
|
||||||
|
|
||||||
{ "linux-arm", "linux-arm" },
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1863,9 +1855,8 @@ public class ConfigurationTest {
|
|||||||
public Object[][] createBad() {
|
public Object[][] createBad() {
|
||||||
return new Object[][] {
|
return new Object[][] {
|
||||||
|
|
||||||
{ "linux-*", "solaris-*" },
|
{ "linux-x64", "linux-arm" },
|
||||||
{ "*-arm", "*-sparc" },
|
{ "linux-x64", "windows-x64" },
|
||||||
{ "linux-x86", "solaris-sparc" },
|
|
||||||
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -1877,7 +1868,7 @@ public class ConfigurationTest {
|
|||||||
public void testPlatformMatch(String s1, String s2) throws IOException {
|
public void testPlatformMatch(String s1, String s2) throws IOException {
|
||||||
|
|
||||||
ModuleDescriptor base = ModuleDescriptor.newModule("java.base").build();
|
ModuleDescriptor base = ModuleDescriptor.newModule("java.base").build();
|
||||||
Path system = writeModule(base, "*-*");
|
Path system = writeModule(base, null);
|
||||||
|
|
||||||
ModuleDescriptor descriptor1 = ModuleDescriptor.newModule("m1")
|
ModuleDescriptor descriptor1 = ModuleDescriptor.newModule("m1")
|
||||||
.requires("m2")
|
.requires("m2")
|
||||||
@ -1928,7 +1919,7 @@ public class ConfigurationTest {
|
|||||||
throws IOException
|
throws IOException
|
||||||
{
|
{
|
||||||
ModuleDescriptor base = ModuleDescriptor.newModule("java.base").build();
|
ModuleDescriptor base = ModuleDescriptor.newModule("java.base").build();
|
||||||
Path system = writeModule(base, "*-*");
|
Path system = writeModule(base, null);
|
||||||
|
|
||||||
ModuleDescriptor descriptor1 = ModuleDescriptor.newModule("m1").build();
|
ModuleDescriptor descriptor1 = ModuleDescriptor.newModule("m1").build();
|
||||||
Path dir1 = writeModule(descriptor1, s1);
|
Path dir1 = writeModule(descriptor1, s1);
|
||||||
@ -2113,17 +2104,18 @@ public class ConfigurationTest {
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Decodes the platform string and calls the builder osName/osArch/osVersion
|
* Writes a module-info.class. If {@code targetPlatform} is not null then
|
||||||
* methods to set the platform constraints.
|
* it includes the ModuleTarget class file attribute with the target platform.
|
||||||
*/
|
*/
|
||||||
static Path writeModule(ModuleDescriptor descriptor, String platformString)
|
static Path writeModule(ModuleDescriptor descriptor, String targetPlatform)
|
||||||
throws IOException
|
throws IOException
|
||||||
{
|
{
|
||||||
String[] s = platformString.split("-");
|
ModuleTarget target;
|
||||||
String osName = !s[0].equals("*") ? s[0] : null;
|
if (targetPlatform != null) {
|
||||||
String osArch = !s[1].equals("*") ? s[1] : null;
|
target = new ModuleTarget(targetPlatform);
|
||||||
ModuleTarget target = new ModuleTarget(osName, osArch);
|
} else {
|
||||||
|
target = null;
|
||||||
|
}
|
||||||
String name = descriptor.name();
|
String name = descriptor.name();
|
||||||
Path dir = Files.createTempDirectory(name);
|
Path dir = Files.createTempDirectory(name);
|
||||||
Path mi = dir.resolve("module-info.class");
|
Path mi = dir.resolve("module-info.class");
|
||||||
|
@ -65,8 +65,8 @@ import static org.testng.Assert.*;
|
|||||||
@Test
|
@Test
|
||||||
public class ModuleDescriptorTest {
|
public class ModuleDescriptorTest {
|
||||||
|
|
||||||
@DataProvider(name = "invalidjavaidentifiers")
|
@DataProvider(name = "invalidNames")
|
||||||
public Object[][] invalidJavaIdentifiers() {
|
public Object[][] invalidNames() {
|
||||||
return new Object[][]{
|
return new Object[][]{
|
||||||
|
|
||||||
{ null, null },
|
{ null, null },
|
||||||
@ -84,6 +84,32 @@ public class ModuleDescriptorTest {
|
|||||||
{ "foo.bar.1gus", null },
|
{ "foo.bar.1gus", null },
|
||||||
{ "foo.bar.[gus]", null },
|
{ "foo.bar.[gus]", null },
|
||||||
|
|
||||||
|
{ "class", null },
|
||||||
|
{ "interface", null },
|
||||||
|
{ "true", null },
|
||||||
|
{ "false", null },
|
||||||
|
{ "null", null },
|
||||||
|
|
||||||
|
{ "x.class", null },
|
||||||
|
{ "x.interface", null },
|
||||||
|
{ "x.true", null },
|
||||||
|
{ "x.false", null },
|
||||||
|
{ "x.null", null },
|
||||||
|
|
||||||
|
{ "class.x", null },
|
||||||
|
{ "interface.x", null },
|
||||||
|
{ "true.x", null },
|
||||||
|
{ "false.x", null },
|
||||||
|
{ "null.x", null },
|
||||||
|
|
||||||
|
{ "x.class.x", null },
|
||||||
|
{ "x.interface.x", null },
|
||||||
|
{ "x.true.x", null },
|
||||||
|
{ "x.false.x", null },
|
||||||
|
{ "x.null.x", null },
|
||||||
|
|
||||||
|
{ "_", null },
|
||||||
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -199,7 +225,7 @@ public class ModuleDescriptorTest {
|
|||||||
ModuleDescriptor.newModule("m").requires(EnumSet.allOf(Modifier.class), "m");
|
ModuleDescriptor.newModule("m").requires(EnumSet.allOf(Modifier.class), "m");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(dataProvider = "invalidjavaidentifiers",
|
@Test(dataProvider = "invalidNames",
|
||||||
expectedExceptions = IllegalArgumentException.class )
|
expectedExceptions = IllegalArgumentException.class )
|
||||||
public void testRequiresWithBadModuleName(String mn, String ignore) {
|
public void testRequiresWithBadModuleName(String mn, String ignore) {
|
||||||
requires(EnumSet.noneOf(Modifier.class), mn);
|
requires(EnumSet.noneOf(Modifier.class), mn);
|
||||||
@ -406,7 +432,7 @@ public class ModuleDescriptorTest {
|
|||||||
ModuleDescriptor.newModule("foo").exports("p", Collections.emptySet());
|
ModuleDescriptor.newModule("foo").exports("p", Collections.emptySet());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(dataProvider = "invalidjavaidentifiers",
|
@Test(dataProvider = "invalidNames",
|
||||||
expectedExceptions = IllegalArgumentException.class )
|
expectedExceptions = IllegalArgumentException.class )
|
||||||
public void testExportsWithBadName(String pn, String ignore) {
|
public void testExportsWithBadName(String pn, String ignore) {
|
||||||
ModuleDescriptor.newModule("foo").exports(pn);
|
ModuleDescriptor.newModule("foo").exports(pn);
|
||||||
@ -568,7 +594,7 @@ public class ModuleDescriptorTest {
|
|||||||
ModuleDescriptor.newModule("foo").opens("p", Collections.emptySet());
|
ModuleDescriptor.newModule("foo").opens("p", Collections.emptySet());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(dataProvider = "invalidjavaidentifiers",
|
@Test(dataProvider = "invalidNames",
|
||||||
expectedExceptions = IllegalArgumentException.class )
|
expectedExceptions = IllegalArgumentException.class )
|
||||||
public void testOpensWithBadName(String pn, String ignore) {
|
public void testOpensWithBadName(String pn, String ignore) {
|
||||||
ModuleDescriptor.newModule("foo").opens(pn);
|
ModuleDescriptor.newModule("foo").opens(pn);
|
||||||
@ -664,7 +690,7 @@ public class ModuleDescriptorTest {
|
|||||||
ModuleDescriptor.newModule("foo").uses("S");
|
ModuleDescriptor.newModule("foo").uses("S");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(dataProvider = "invalidjavaidentifiers",
|
@Test(dataProvider = "invalidNames",
|
||||||
expectedExceptions = IllegalArgumentException.class )
|
expectedExceptions = IllegalArgumentException.class )
|
||||||
public void testUsesWithBadName(String service, String ignore) {
|
public void testUsesWithBadName(String service, String ignore) {
|
||||||
ModuleDescriptor.newModule("foo").uses(service);
|
ModuleDescriptor.newModule("foo").uses(service);
|
||||||
@ -737,13 +763,13 @@ public class ModuleDescriptorTest {
|
|||||||
ModuleDescriptor.newModule("foo").provides("p.S", List.of("P"));
|
ModuleDescriptor.newModule("foo").provides("p.S", List.of("P"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(dataProvider = "invalidjavaidentifiers",
|
@Test(dataProvider = "invalidNames",
|
||||||
expectedExceptions = IllegalArgumentException.class )
|
expectedExceptions = IllegalArgumentException.class )
|
||||||
public void testProvidesWithBadService(String service, String ignore) {
|
public void testProvidesWithBadService(String service, String ignore) {
|
||||||
ModuleDescriptor.newModule("foo").provides(service, List.of("p.Provider"));
|
ModuleDescriptor.newModule("foo").provides(service, List.of("p.Provider"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(dataProvider = "invalidjavaidentifiers",
|
@Test(dataProvider = "invalidNames",
|
||||||
expectedExceptions = IllegalArgumentException.class )
|
expectedExceptions = IllegalArgumentException.class )
|
||||||
public void testProvidesWithBadProvider(String provider, String ignore) {
|
public void testProvidesWithBadProvider(String provider, String ignore) {
|
||||||
List<String> names = new ArrayList<>(); // allows nulls
|
List<String> names = new ArrayList<>(); // allows nulls
|
||||||
@ -928,7 +954,7 @@ public class ModuleDescriptorTest {
|
|||||||
assertTrue(Objects.equals(packages, Set.of("p1", "p2", "p3", "p4", "p5")));
|
assertTrue(Objects.equals(packages, Set.of("p1", "p2", "p3", "p4", "p5")));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(dataProvider = "invalidjavaidentifiers",
|
@Test(dataProvider = "invalidNames",
|
||||||
expectedExceptions = IllegalArgumentException.class )
|
expectedExceptions = IllegalArgumentException.class )
|
||||||
public void testPackagesWithBadName(String pn, String ignore) {
|
public void testPackagesWithBadName(String pn, String ignore) {
|
||||||
Set<String> pkgs = new HashSet<>(); // allows nulls
|
Set<String> pkgs = new HashSet<>(); // allows nulls
|
||||||
@ -943,7 +969,7 @@ public class ModuleDescriptorTest {
|
|||||||
assertEquals(mn, "foo");
|
assertEquals(mn, "foo");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(dataProvider = "invalidjavaidentifiers",
|
@Test(dataProvider = "invalidNames",
|
||||||
expectedExceptions = IllegalArgumentException.class )
|
expectedExceptions = IllegalArgumentException.class )
|
||||||
public void testBadModuleName(String mn, String ignore) {
|
public void testBadModuleName(String mn, String ignore) {
|
||||||
ModuleDescriptor.newModule(mn);
|
ModuleDescriptor.newModule(mn);
|
||||||
@ -1264,7 +1290,7 @@ public class ModuleDescriptorTest {
|
|||||||
ModuleDescriptor.newModule("foo").mainClass("Main");
|
ModuleDescriptor.newModule("foo").mainClass("Main");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(dataProvider = "invalidjavaidentifiers",
|
@Test(dataProvider = "invalidNames",
|
||||||
expectedExceptions = IllegalArgumentException.class )
|
expectedExceptions = IllegalArgumentException.class )
|
||||||
public void testMainClassWithBadName(String mainClass, String ignore) {
|
public void testMainClassWithBadName(String mainClass, String ignore) {
|
||||||
Builder builder = ModuleDescriptor.newModule("foo");
|
Builder builder = ModuleDescriptor.newModule("foo");
|
||||||
|
@ -0,0 +1,142 @@
|
|||||||
|
/*
|
||||||
|
* 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 jdk.zipfs
|
||||||
|
* @library /lib/testlibrary
|
||||||
|
* @build ModulesInCustomFileSystem JarUtils m1/* m2/*
|
||||||
|
* @run testng/othervm ModulesInCustomFileSystem
|
||||||
|
* @summary Test ModuleFinder to find modules in a custom file system
|
||||||
|
*/
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.lang.module.Configuration;
|
||||||
|
import java.lang.module.ModuleFinder;
|
||||||
|
import java.lang.module.ModuleReader;
|
||||||
|
import java.lang.module.ModuleReference;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.nio.file.FileSystem;
|
||||||
|
import java.nio.file.FileSystems;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.Paths;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.testng.annotations.Test;
|
||||||
|
import static org.testng.Assert.*;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public class ModulesInCustomFileSystem {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test exploded modules in a JAR file system.
|
||||||
|
*/
|
||||||
|
public void testExplodedModulesInJarFileSystem() throws Exception {
|
||||||
|
Path m1 = findModuleDirectory("m1");
|
||||||
|
Path m2 = findModuleDirectory("m2");
|
||||||
|
Path mlib = m1.getParent();
|
||||||
|
assertEquals(mlib, m2.getParent());
|
||||||
|
|
||||||
|
// create JAR file containing m1/** and m2/**
|
||||||
|
Path jar = Files.createTempDirectory("mlib").resolve("modules.jar");
|
||||||
|
JarUtils.createJarFile(jar, mlib);
|
||||||
|
testJarFileSystem(jar);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test modular JARs in a JAR file system
|
||||||
|
*/
|
||||||
|
public void testModularJARsInJarFileSystem() throws Exception {
|
||||||
|
Path m1 = findModuleDirectory("m1");
|
||||||
|
Path m2 = findModuleDirectory("m2");
|
||||||
|
Path contents = Files.createTempDirectory("contents");
|
||||||
|
JarUtils.createJarFile(contents.resolve("m1.jar"), m1);
|
||||||
|
JarUtils.createJarFile(contents.resolve("m2.jar"), m2);
|
||||||
|
|
||||||
|
// create JAR file containing m1.jar and m2.jar
|
||||||
|
Path jar = Files.createTempDirectory("mlib").resolve("modules.jar");
|
||||||
|
JarUtils.createJarFile(jar, contents);
|
||||||
|
testJarFileSystem(jar);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Opens a JAR file as a file system
|
||||||
|
*/
|
||||||
|
private void testJarFileSystem(Path jar) throws Exception {
|
||||||
|
ClassLoader scl = ClassLoader.getSystemClassLoader();
|
||||||
|
try (FileSystem fs = FileSystems.newFileSystem(jar, scl)) {
|
||||||
|
// ModuleFinder to find modules in top-level directory
|
||||||
|
Path top = fs.getPath("/");
|
||||||
|
ModuleFinder finder = ModuleFinder.of(top);
|
||||||
|
|
||||||
|
// list the modules
|
||||||
|
listAllModules(finder);
|
||||||
|
|
||||||
|
// load modules into child layer, invoking m1/p.Main
|
||||||
|
loadAndRunModule(finder);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List all modules that the finder finds and the resources in the module.
|
||||||
|
*/
|
||||||
|
private void listAllModules(ModuleFinder finder) throws Exception {
|
||||||
|
for (ModuleReference mref : finder.findAll()) {
|
||||||
|
System.out.println(mref.descriptor());
|
||||||
|
try (ModuleReader reader = mref.open()) {
|
||||||
|
reader.list().forEach(name -> System.out.format(" %s%n", name));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a child layer with m1 and m2, invokes m1/p.Main to ensure that
|
||||||
|
* classes can be loaded.
|
||||||
|
*/
|
||||||
|
private void loadAndRunModule(ModuleFinder finder) throws Exception {
|
||||||
|
ModuleLayer bootLayer = ModuleLayer.boot();
|
||||||
|
Configuration cf = bootLayer.configuration()
|
||||||
|
.resolve(finder, ModuleFinder.of(), Set.of("m1"));
|
||||||
|
ClassLoader scl = ClassLoader.getSystemClassLoader();
|
||||||
|
ModuleLayer layer = bootLayer.defineModulesWithOneLoader(cf, scl);
|
||||||
|
Class<?> c = layer.findLoader("m1").loadClass("p.Main");
|
||||||
|
Method m = c.getMethod("main", String[].class);
|
||||||
|
m.invoke(null, (Object)new String[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find the directory for a module on the module path
|
||||||
|
*/
|
||||||
|
private Path findModuleDirectory(String name) {
|
||||||
|
String mp = System.getProperty("jdk.module.path");
|
||||||
|
for (String element : mp.split(File.pathSeparator)) {
|
||||||
|
Path dir = Paths.get(element).resolve(name);
|
||||||
|
if (Files.exists(dir)) {
|
||||||
|
return dir;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assertFalse(true);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
27
jdk/test/java/lang/module/customfs/m1/module-info.java
Normal file
27
jdk/test/java/lang/module/customfs/m1/module-info.java
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
module m1 {
|
||||||
|
exports p;
|
||||||
|
requires m2;
|
||||||
|
}
|
30
jdk/test/java/lang/module/customfs/m1/p/Main.java
Normal file
30
jdk/test/java/lang/module/customfs/m1/p/Main.java
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package p;
|
||||||
|
|
||||||
|
public class Main {
|
||||||
|
public static void main(String[] args) {
|
||||||
|
q.Hello.hello();
|
||||||
|
}
|
||||||
|
}
|
26
jdk/test/java/lang/module/customfs/m2/module-info.java
Normal file
26
jdk/test/java/lang/module/customfs/m2/module-info.java
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
module m2 {
|
||||||
|
exports q;
|
||||||
|
}
|
30
jdk/test/java/lang/module/customfs/m2/q/Hello.java
Normal file
30
jdk/test/java/lang/module/customfs/m2/q/Hello.java
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package q;
|
||||||
|
|
||||||
|
public class Hello {
|
||||||
|
public static void hello() {
|
||||||
|
System.out.println("hello");
|
||||||
|
}
|
||||||
|
}
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2008, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -21,23 +21,141 @@
|
|||||||
* questions.
|
* questions.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* @test
|
/**
|
||||||
* @bug 4313887 7006126
|
* @test
|
||||||
* @summary Unit test for java.nio.file.spi.FileSystemProvider
|
* @modules jdk.jartool
|
||||||
* @build TestProvider SetDefaultProvider
|
* @library /lib/testlibrary
|
||||||
* @run main/othervm -Djava.nio.file.spi.DefaultFileSystemProvider=TestProvider SetDefaultProvider
|
* @build SetDefaultProvider TestProvider m/* jdk.testlibrary.ProcessTools
|
||||||
|
* @run testng/othervm SetDefaultProvider
|
||||||
|
* @summary Runs tests with -Djava.nio.file.spi.DefaultFileSystemProvider set on
|
||||||
|
* the command line to override the default file system provider
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import java.nio.file.*;
|
import java.io.File;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.Paths;
|
||||||
|
import java.util.spi.ToolProvider;
|
||||||
|
|
||||||
|
import jdk.testlibrary.ProcessTools;
|
||||||
|
|
||||||
|
import org.testng.annotations.BeforeTest;
|
||||||
|
import org.testng.annotations.Test;
|
||||||
|
import static org.testng.Assert.*;
|
||||||
|
|
||||||
|
@Test
|
||||||
public class SetDefaultProvider {
|
public class SetDefaultProvider {
|
||||||
public static void main(String[] args) throws Exception {
|
|
||||||
Class<?> c = FileSystems.getDefault().provider().getClass();
|
|
||||||
|
|
||||||
Class<?> expected = Class.forName("TestProvider", false,
|
private static String SET_DEFAULT_FSP =
|
||||||
ClassLoader.getSystemClassLoader());
|
"-Djava.nio.file.spi.DefaultFileSystemProvider=TestProvider";
|
||||||
|
|
||||||
if (c != expected)
|
private static final ToolProvider JAR_TOOL = ToolProvider.findFirst("jar")
|
||||||
throw new RuntimeException();
|
.orElseThrow(() ->
|
||||||
|
new RuntimeException("jar tool not found")
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test override of default FileSystemProvider with the main application
|
||||||
|
* on the class path.
|
||||||
|
*/
|
||||||
|
public void testClassPath() throws Exception {
|
||||||
|
String moduleClasses = moduleClasses();
|
||||||
|
String testClasses = System.getProperty("test.classes");
|
||||||
|
String classpath = moduleClasses + File.pathSeparator + testClasses;
|
||||||
|
int exitValue = exec(SET_DEFAULT_FSP, "-cp", classpath, "p.Main");
|
||||||
|
assertTrue(exitValue == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test override of default FileSystemProvider with the main application
|
||||||
|
* on the module path as an exploded module.
|
||||||
|
*/
|
||||||
|
public void testExplodedModule() throws Exception {
|
||||||
|
String modulePath = System.getProperty("jdk.module.path");
|
||||||
|
int exitValue = exec(SET_DEFAULT_FSP, "-p", modulePath, "-m", "m/p.Main");
|
||||||
|
assertTrue(exitValue == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test override of default FileSystemProvider with the main application
|
||||||
|
* on the module path as a modular JAR.
|
||||||
|
*/
|
||||||
|
public void testModularJar() throws Exception {
|
||||||
|
String jarFile = createModularJar();
|
||||||
|
int exitValue = exec(SET_DEFAULT_FSP, "-p", jarFile, "-m", "m/p.Main");
|
||||||
|
assertTrue(exitValue == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test override of default FileSystemProvider where the main application
|
||||||
|
* is a module that is patched by an exploded patch.
|
||||||
|
*/
|
||||||
|
public void testExplodedModuleWithExplodedPatch() throws Exception {
|
||||||
|
Path patchdir = Files.createTempDirectory("patch");
|
||||||
|
String modulePath = System.getProperty("jdk.module.path");
|
||||||
|
int exitValue = exec(SET_DEFAULT_FSP,
|
||||||
|
"--patch-module", "m=" + patchdir,
|
||||||
|
"-p", modulePath,
|
||||||
|
"-m", "m/p.Main");
|
||||||
|
assertTrue(exitValue == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test override of default FileSystemProvider where the main application
|
||||||
|
* is a module that is patched by an exploded patch.
|
||||||
|
*/
|
||||||
|
public void testExplodedModuleWithJarPatch() throws Exception {
|
||||||
|
Path patchdir = Files.createTempDirectory("patch");
|
||||||
|
Files.createDirectory(patchdir.resolve("m.properties"));
|
||||||
|
Path patch = createJarFile(patchdir);
|
||||||
|
String modulePath = System.getProperty("jdk.module.path");
|
||||||
|
int exitValue = exec(SET_DEFAULT_FSP,
|
||||||
|
"--patch-module", "m=" + patch,
|
||||||
|
"-p", modulePath,
|
||||||
|
"-m", "m/p.Main");
|
||||||
|
assertTrue(exitValue == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the directory containing the classes for module "m".
|
||||||
|
*/
|
||||||
|
private String moduleClasses() {
|
||||||
|
String mp = System.getProperty("jdk.module.path");
|
||||||
|
for (String dir : mp.split(File.pathSeparator)) {
|
||||||
|
Path m = Paths.get(dir, "m");
|
||||||
|
if (Files.exists(m)) return m.toString();
|
||||||
|
}
|
||||||
|
assertFalse(true);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a modular JAR containing module "m".
|
||||||
|
*/
|
||||||
|
private String createModularJar() throws Exception {
|
||||||
|
Path dir = Paths.get(moduleClasses());
|
||||||
|
Path jar = createJarFile(dir);
|
||||||
|
return jar.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a JAR file containing the entries in the given file tree.
|
||||||
|
*/
|
||||||
|
private Path createJarFile(Path dir) throws Exception {
|
||||||
|
Path jar = Files.createTempDirectory("tmp").resolve("m.jar");
|
||||||
|
String[] args = { "--create", "--file=" + jar, "-C", dir.toString(), "." };
|
||||||
|
int ret = JAR_TOOL.run(System.out, System.out, args);
|
||||||
|
assertTrue(ret == 0);
|
||||||
|
return jar;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invokes the java launcher with the given arguments, returning the exit code.
|
||||||
|
*/
|
||||||
|
private int exec(String... args) throws Exception {
|
||||||
|
return ProcessTools.executeTestJava(args)
|
||||||
|
.outputTo(System.out)
|
||||||
|
.errorTo(System.out)
|
||||||
|
.getExitValue();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -77,7 +77,7 @@ public class TestProvider extends FileSystemProvider {
|
|||||||
LinkOption... options)
|
LinkOption... options)
|
||||||
throws IOException
|
throws IOException
|
||||||
{
|
{
|
||||||
throw new ReadOnlyFileSystemException();
|
throw new RuntimeException("not implemented");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -110,19 +110,20 @@ public class TestProvider extends FileSystemProvider {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void delete(Path file) throws IOException {
|
public void delete(Path file) throws IOException {
|
||||||
throw new ReadOnlyFileSystemException();
|
Path delegate = theFileSystem.unwrap(file);
|
||||||
|
defaultProvider.delete(delegate);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void createSymbolicLink(Path link, Path target, FileAttribute<?>... attrs)
|
public void createSymbolicLink(Path link, Path target, FileAttribute<?>... attrs)
|
||||||
throws IOException
|
throws IOException
|
||||||
{
|
{
|
||||||
throw new ReadOnlyFileSystemException();
|
throw new RuntimeException("not implemented");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void createLink(Path link, Path existing) throws IOException {
|
public void createLink(Path link, Path existing) throws IOException {
|
||||||
throw new ReadOnlyFileSystemException();
|
throw new RuntimeException("not implemented");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -136,14 +137,14 @@ public class TestProvider extends FileSystemProvider {
|
|||||||
public void copy(Path source, Path target, CopyOption... options)
|
public void copy(Path source, Path target, CopyOption... options)
|
||||||
throws IOException
|
throws IOException
|
||||||
{
|
{
|
||||||
throw new ReadOnlyFileSystemException();
|
throw new RuntimeException("not implemented");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void move(Path source, Path target, CopyOption... options)
|
public void move(Path source, Path target, CopyOption... options)
|
||||||
throws IOException
|
throws IOException
|
||||||
{
|
{
|
||||||
throw new ReadOnlyFileSystemException();
|
throw new RuntimeException("not implemented");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -158,7 +159,8 @@ public class TestProvider extends FileSystemProvider {
|
|||||||
public void createDirectory(Path dir, FileAttribute<?>... attrs)
|
public void createDirectory(Path dir, FileAttribute<?>... attrs)
|
||||||
throws IOException
|
throws IOException
|
||||||
{
|
{
|
||||||
throw new ReadOnlyFileSystemException();
|
Path delegate = theFileSystem.unwrap(dir);
|
||||||
|
defaultProvider.createDirectory(delegate, attrs);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -167,13 +169,8 @@ public class TestProvider extends FileSystemProvider {
|
|||||||
FileAttribute<?>... attrs)
|
FileAttribute<?>... attrs)
|
||||||
throws IOException
|
throws IOException
|
||||||
{
|
{
|
||||||
if (options.contains(StandardOpenOption.READ) && options.size() == 1) {
|
Path delegate = theFileSystem.unwrap(file);
|
||||||
Path delegate = theFileSystem.unwrap(file);
|
return defaultProvider.newByteChannel(delegate, options, attrs);
|
||||||
options = Collections.singleton(StandardOpenOption.READ);
|
|
||||||
return defaultProvider.newByteChannel(delegate, options, attrs);
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new RuntimeException("not implemented");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -236,7 +233,7 @@ public class TestProvider extends FileSystemProvider {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isReadOnly() {
|
public boolean isReadOnly() {
|
||||||
return true;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -419,7 +416,7 @@ public class TestProvider extends FileSystemProvider {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public File toFile() {
|
public File toFile() {
|
||||||
return delegate.toFile();
|
return new File(toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
24
jdk/test/java/nio/file/spi/m/module-info.java
Normal file
24
jdk/test/java/nio/file/spi/m/module-info.java
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
module m {
|
||||||
|
}
|
62
jdk/test/java/nio/file/spi/m/p/Main.java
Normal file
62
jdk/test/java/nio/file/spi/m/p/Main.java
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package p;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.nio.file.FileSystem;
|
||||||
|
import java.nio.file.FileSystems;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Launched by SetDefaultProvider to test startup with the default file system
|
||||||
|
* provider overridden.
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class Main {
|
||||||
|
public static void main(String[] args) throws Exception {
|
||||||
|
FileSystem fs = FileSystems.getDefault();
|
||||||
|
if (fs.getClass().getModule() == Object.class.getModule())
|
||||||
|
throw new RuntimeException("FileSystemProvider not overridden");
|
||||||
|
|
||||||
|
// exercise the file system
|
||||||
|
Path dir = Files.createTempDirectory("tmp");
|
||||||
|
if (dir.getFileSystem() != fs)
|
||||||
|
throw new RuntimeException("'dir' not in default file system");
|
||||||
|
System.out.println("created: " + dir);
|
||||||
|
|
||||||
|
Path foo = Files.createFile(dir.resolve("foo"));
|
||||||
|
if (foo.getFileSystem() != fs)
|
||||||
|
throw new RuntimeException("'foo' not in default file system");
|
||||||
|
System.out.println("created: " + foo);
|
||||||
|
|
||||||
|
// exercise interop with java.io.File
|
||||||
|
File file = foo.toFile();
|
||||||
|
Path path = file.toPath();
|
||||||
|
if (path.getFileSystem() != fs)
|
||||||
|
throw new RuntimeException("'path' not in default file system");
|
||||||
|
if (!path.equals(foo))
|
||||||
|
throw new RuntimeException(path + " not equal to " + foo);
|
||||||
|
}
|
||||||
|
}
|
@ -41,8 +41,8 @@ import sun.tools.attach.HotSpotVirtualMachine;
|
|||||||
* @modules jdk.attach/sun.tools.attach
|
* @modules jdk.attach/sun.tools.attach
|
||||||
* java.logging
|
* java.logging
|
||||||
* @build jdk.testlibrary.ProcessTools
|
* @build jdk.testlibrary.ProcessTools
|
||||||
* @run main/othervm TestLoggerWeakRefLeak Logger
|
* @run main/othervm -Djdk.attach.allowAttachSelf TestLoggerWeakRefLeak Logger
|
||||||
* @run main/othervm TestLoggerWeakRefLeak AnonymousLogger
|
* @run main/othervm -Djdk.attach.allowAttachSelf TestLoggerWeakRefLeak AnonymousLogger
|
||||||
*/
|
*/
|
||||||
public class TestLoggerWeakRefLeak {
|
public class TestLoggerWeakRefLeak {
|
||||||
|
|
||||||
|
@ -41,19 +41,14 @@ public class ModuleTargetHelper {
|
|||||||
private ModuleTargetHelper() {}
|
private ModuleTargetHelper() {}
|
||||||
|
|
||||||
public static final class ModuleTarget {
|
public static final class ModuleTarget {
|
||||||
private String osName, osArch;
|
private String targetPlatform;
|
||||||
|
|
||||||
public ModuleTarget(String osName, String osArch) {
|
public ModuleTarget(String targetPlatform) {
|
||||||
this.osName = osName;
|
this.targetPlatform = targetPlatform;
|
||||||
this.osArch = osArch;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public String osName() {
|
public String targetPlatform() {
|
||||||
return osName;
|
return targetPlatform;
|
||||||
}
|
|
||||||
|
|
||||||
public String osArch() {
|
|
||||||
return osArch;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -84,7 +79,7 @@ public class ModuleTargetHelper {
|
|||||||
ClassReader cr = new ClassReader(in);
|
ClassReader cr = new ClassReader(in);
|
||||||
cr.accept(cv, attrs, 0);
|
cr.accept(cv, attrs, 0);
|
||||||
if (modTargets[0] != null) {
|
if (modTargets[0] != null) {
|
||||||
return new ModuleTarget(modTargets[0].osName(), modTargets[0].osArch());
|
return new ModuleTarget(modTargets[0].targetPlatform());
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
@ -37,7 +37,7 @@
|
|||||||
* @run main/othervm/timeout=600 -XX:+UsePerfData JvmstatCountersTest 1
|
* @run main/othervm/timeout=600 -XX:+UsePerfData JvmstatCountersTest 1
|
||||||
* @run main/othervm/timeout=600 -XX:+UsePerfData -Dcom.sun.management.jmxremote JvmstatCountersTest 2
|
* @run main/othervm/timeout=600 -XX:+UsePerfData -Dcom.sun.management.jmxremote JvmstatCountersTest 2
|
||||||
* @run main/othervm/timeout=600 -XX:+UsePerfData -Dcom.sun.management.jmxremote.port=0 -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false JvmstatCountersTest 3
|
* @run main/othervm/timeout=600 -XX:+UsePerfData -Dcom.sun.management.jmxremote.port=0 -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false JvmstatCountersTest 3
|
||||||
* @run main/othervm/timeout=600 -XX:+UsePerfData JvmstatCountersTest 4
|
* @run main/othervm/timeout=600 -XX:+UsePerfData -Djdk.attach.allowAttachSelf JvmstatCountersTest 4
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
|
@ -221,7 +221,8 @@ public class Basic {
|
|||||||
Assert.assertEquals(actual, expected);
|
Assert.assertEquals(actual, expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
// jar tool does two updates, no exported packages, all concealed
|
// jar tool does two updates, no exported packages, all concealed.
|
||||||
|
// Along with various --describe-module variants
|
||||||
@Test
|
@Test
|
||||||
public void test5() throws IOException {
|
public void test5() throws IOException {
|
||||||
// compile the mr10 directory
|
// compile the mr10 directory
|
||||||
@ -266,10 +267,13 @@ public class Basic {
|
|||||||
|
|
||||||
jar("-d --file mr.jar");
|
jar("-d --file mr.jar");
|
||||||
|
|
||||||
|
String uri = (Paths.get("mr.jar")).toUri().toString();
|
||||||
|
uri = "jar:" + uri + "/!module-info.class";
|
||||||
|
|
||||||
actual = lines(outbytes);
|
actual = lines(outbytes);
|
||||||
expected = Set.of(
|
expected = Set.of(
|
||||||
"module hi (module-info.class)",
|
"hi " + uri,
|
||||||
"requires mandated java.base",
|
"requires java.base mandated",
|
||||||
"contains p",
|
"contains p",
|
||||||
"contains p.internal"
|
"contains p.internal"
|
||||||
);
|
);
|
||||||
@ -304,13 +308,19 @@ public class Basic {
|
|||||||
|
|
||||||
actual = lines(outbytes);
|
actual = lines(outbytes);
|
||||||
expected = Set.of(
|
expected = Set.of(
|
||||||
"module hi (module-info.class)",
|
"hi " + uri,
|
||||||
"requires mandated java.base",
|
"requires java.base mandated",
|
||||||
"contains p",
|
"contains p",
|
||||||
"contains p.internal",
|
"contains p.internal",
|
||||||
"contains p.internal.bar"
|
"contains p.internal.bar"
|
||||||
);
|
);
|
||||||
Assert.assertEquals(actual, expected);
|
Assert.assertEquals(actual, expected);
|
||||||
|
|
||||||
|
for (String release : new String[] {"9" , "10", "100", "1000"}) {
|
||||||
|
jar("-d --file mr.jar --release " + release);
|
||||||
|
actual = lines(outbytes);
|
||||||
|
Assert.assertEquals(actual, expected);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// root and versioned module-info entries have different main-class, version
|
// root and versioned module-info entries have different main-class, version
|
||||||
@ -399,15 +409,42 @@ public class Basic {
|
|||||||
Assert.assertEquals(rc, 0);
|
Assert.assertEquals(rc, 0);
|
||||||
|
|
||||||
jar("-d --file=mmr.jar");
|
jar("-d --file=mmr.jar");
|
||||||
System.out.println("-----------------------");
|
Set<String> actual = lines(outbytes);
|
||||||
System.out.println( new String(outbytes.toByteArray()));
|
Set<String> expected = Set.of(
|
||||||
Assert.assertEquals(lines(outbytes),
|
"releases: 9 10",
|
||||||
Set.of(
|
"No root module descriptor, specify --release"
|
||||||
"module m1 (META-INF/versions/9/module-info.class)",
|
);
|
||||||
"module m1 (META-INF/versions/10/module-info.class)",
|
Assert.assertEquals(actual, expected);
|
||||||
"requires mandated java.base",
|
|
||||||
"exports p",
|
String uriPrefix = "jar:" + (Paths.get("mmr.jar")).toUri().toString();
|
||||||
"main-class p.Main"));
|
|
||||||
|
jar("-d --file=mmr.jar --release 9");
|
||||||
|
actual = lines(outbytes);
|
||||||
|
expected = Set.of(
|
||||||
|
"releases: 9 10",
|
||||||
|
"m1 " + uriPrefix + "/!META-INF/versions/9/module-info.class",
|
||||||
|
"requires java.base mandated",
|
||||||
|
"exports p",
|
||||||
|
"main-class p.Main"
|
||||||
|
);
|
||||||
|
Assert.assertEquals(actual, expected);
|
||||||
|
|
||||||
|
jar("-d --file=mmr.jar --release 10");
|
||||||
|
actual = lines(outbytes);
|
||||||
|
expected = Set.of(
|
||||||
|
"releases: 9 10",
|
||||||
|
"m1 " + uriPrefix + "/!META-INF/versions/10/module-info.class",
|
||||||
|
"requires java.base mandated",
|
||||||
|
"exports p",
|
||||||
|
"main-class p.Main"
|
||||||
|
);
|
||||||
|
Assert.assertEquals(actual, expected);
|
||||||
|
|
||||||
|
for (String release : new String[] {"11", "12", "15", "100"}) {
|
||||||
|
jar("-d --file mmr.jar --release " + release);
|
||||||
|
actual = lines(outbytes);
|
||||||
|
Assert.assertEquals(actual, expected);
|
||||||
|
}
|
||||||
|
|
||||||
Optional<String> exp = Optional.of("p.Main");
|
Optional<String> exp = Optional.of("p.Main");
|
||||||
try (ZipFile zf = new ZipFile("mmr.jar")) {
|
try (ZipFile zf = new ZipFile("mmr.jar")) {
|
||||||
|
@ -478,13 +478,13 @@ public class Basic {
|
|||||||
"--file=" + modularJar.toString())
|
"--file=" + modularJar.toString())
|
||||||
.assertSuccess()
|
.assertSuccess()
|
||||||
.resultChecker(r -> {
|
.resultChecker(r -> {
|
||||||
// Expect similar output: "bar, requires mandated foo, ...
|
// Expect "bar jar:file:/.../!module-info.class"
|
||||||
// conceals jdk.test.foo, conceals jdk.test.foo.internal"
|
// conceals jdk.test.foo, conceals jdk.test.foo.internal"
|
||||||
Pattern p = Pattern.compile("module bar \\(module-info.class\\)\\s+requires\\s++foo");
|
String uri = "jar:" + modularJar.toUri().toString() + "/!module-info.class";
|
||||||
assertTrue(p.matcher(r.output).find(),
|
assertTrue(r.output.contains("bar " + uri),
|
||||||
"Expecting to find \"bar, requires foo,...\"",
|
"Expecting to find \"bar " + uri + "\"",
|
||||||
"in output, but did not: [" + r.output + "]");
|
"in output, but did not: [" + r.output + "]");
|
||||||
p = Pattern.compile(
|
Pattern p = Pattern.compile(
|
||||||
"contains\\s+jdk.test.foo\\s+contains\\s+jdk.test.foo.internal");
|
"contains\\s+jdk.test.foo\\s+contains\\s+jdk.test.foo.internal");
|
||||||
assertTrue(p.matcher(r.output).find(),
|
assertTrue(p.matcher(r.output).find(),
|
||||||
"Expecting to find \"contains jdk.test.foo,...\"",
|
"Expecting to find \"contains jdk.test.foo,...\"",
|
||||||
@ -758,14 +758,15 @@ public class Basic {
|
|||||||
for (String option : new String[] {"--describe-module", "-d" }) {
|
for (String option : new String[] {"--describe-module", "-d" }) {
|
||||||
|
|
||||||
jar(option,
|
jar(option,
|
||||||
"--file=" + modularJar.toString())
|
"--file=" + modularJar.toString(),
|
||||||
|
"--release", "9")
|
||||||
.assertSuccess()
|
.assertSuccess()
|
||||||
.resultChecker(r ->
|
.resultChecker(r ->
|
||||||
assertTrue(r.output.contains("main-class jdk.test.baz.Baz"),
|
assertTrue(r.output.contains("main-class jdk.test.baz.Baz"),
|
||||||
"Expected to find ", "main-class jdk.test.baz.Baz",
|
"Expected to find ", "main-class jdk.test.baz.Baz",
|
||||||
" in [", r.output, "]"));
|
" in [", r.output, "]"));
|
||||||
|
|
||||||
jarWithStdin(modularJar.toFile(), option)
|
jarWithStdin(modularJar.toFile(), option, "--release", "9")
|
||||||
.assertSuccess()
|
.assertSuccess()
|
||||||
.resultChecker(r ->
|
.resultChecker(r ->
|
||||||
assertTrue(r.output.contains("main-class jdk.test.baz.Baz"),
|
assertTrue(r.output.contains("main-class jdk.test.baz.Baz"),
|
||||||
@ -773,7 +774,7 @@ public class Basic {
|
|||||||
" in [", r.output, "]"));
|
" in [", r.output, "]"));
|
||||||
|
|
||||||
}
|
}
|
||||||
// run module maain class
|
// run module main class
|
||||||
java(mp, "baz/jdk.test.baz.Baz")
|
java(mp, "baz/jdk.test.baz.Baz")
|
||||||
.assertSuccess()
|
.assertSuccess()
|
||||||
.resultChecker(r ->
|
.resultChecker(r ->
|
||||||
@ -900,7 +901,7 @@ public class Basic {
|
|||||||
.resultChecker(r -> {
|
.resultChecker(r -> {
|
||||||
assertTrue(r.output.contains("No module descriptor found"));
|
assertTrue(r.output.contains("No module descriptor found"));
|
||||||
assertTrue(r.output.contains("Derived automatic module"));
|
assertTrue(r.output.contains("Derived automatic module"));
|
||||||
assertTrue(r.output.contains("module " + mid),
|
assertTrue(r.output.contains(mid + " automatic"),
|
||||||
"Expected [", "module " + mid,"] in [", r.output, "]");
|
"Expected [", "module " + mid,"] in [", r.output, "]");
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
28
jdk/test/tools/jar/multiRelease/whitebox/Driver.java
Normal file
28
jdk/test/tools/jar/multiRelease/whitebox/Driver.java
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
/*
|
||||||
|
* 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 jdk.jartool/sun.tools.jar
|
||||||
|
* @run testng/othervm jdk.jartool/sun.tools.jar.ValidatorComparatorTest
|
||||||
|
*/
|
@ -0,0 +1,101 @@
|
|||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @summary White-box test for Validator.ENTRYNAME_COMPARATOR ( currently just
|
||||||
|
* checks module descriptors ).
|
||||||
|
*/
|
||||||
|
package sun.tools.jar;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import static java.util.stream.Collectors.toList;
|
||||||
|
import static sun.tools.jar.Validator.ENTRYNAME_COMPARATOR;
|
||||||
|
|
||||||
|
import org.testng.Assert;
|
||||||
|
import org.testng.annotations.Test;
|
||||||
|
|
||||||
|
public class ValidatorComparatorTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testModuleInfo() throws Throwable {
|
||||||
|
List<String> list =
|
||||||
|
List.of("module-info.class",
|
||||||
|
"META-INF/versions/9/module-info.class",
|
||||||
|
"META-INF/versions/10/module-info.class");
|
||||||
|
List<String> sorted = list.stream()
|
||||||
|
.sorted(ENTRYNAME_COMPARATOR)
|
||||||
|
.collect(toList());
|
||||||
|
List<String> expected = list;
|
||||||
|
Assert.assertEquals(sorted, expected);
|
||||||
|
|
||||||
|
|
||||||
|
list = List.of("META-INF/versions/10/module-info.class",
|
||||||
|
"META-INF/versions/9/module-info.class",
|
||||||
|
"module-info.class");
|
||||||
|
sorted = list.stream().sorted(ENTRYNAME_COMPARATOR).collect(toList());
|
||||||
|
expected =
|
||||||
|
List.of("module-info.class",
|
||||||
|
"META-INF/versions/9/module-info.class",
|
||||||
|
"META-INF/versions/10/module-info.class");
|
||||||
|
Assert.assertEquals(sorted, expected);
|
||||||
|
|
||||||
|
|
||||||
|
list = List.of("META-INF/versions/1001/module-info.class",
|
||||||
|
"META-INF/versions/1000/module-info.class",
|
||||||
|
"META-INF/versions/999/module-info.class",
|
||||||
|
"META-INF/versions/101/module-info.class",
|
||||||
|
"META-INF/versions/100/module-info.class",
|
||||||
|
"META-INF/versions/99/module-info.class",
|
||||||
|
"META-INF/versions/31/module-info.class",
|
||||||
|
"META-INF/versions/30/module-info.class",
|
||||||
|
"META-INF/versions/29/module-info.class",
|
||||||
|
"META-INF/versions/21/module-info.class",
|
||||||
|
"META-INF/versions/20/module-info.class",
|
||||||
|
"META-INF/versions/13/module-info.class",
|
||||||
|
"META-INF/versions/12/module-info.class",
|
||||||
|
"META-INF/versions/11/module-info.class",
|
||||||
|
"META-INF/versions/10/module-info.class",
|
||||||
|
"META-INF/versions/9/module-info.class",
|
||||||
|
"module-info.class");
|
||||||
|
sorted = list.stream().sorted(ENTRYNAME_COMPARATOR).collect(toList());
|
||||||
|
expected =
|
||||||
|
List.of("module-info.class",
|
||||||
|
"META-INF/versions/9/module-info.class",
|
||||||
|
"META-INF/versions/10/module-info.class",
|
||||||
|
"META-INF/versions/11/module-info.class",
|
||||||
|
"META-INF/versions/12/module-info.class",
|
||||||
|
"META-INF/versions/13/module-info.class",
|
||||||
|
"META-INF/versions/20/module-info.class",
|
||||||
|
"META-INF/versions/21/module-info.class",
|
||||||
|
"META-INF/versions/29/module-info.class",
|
||||||
|
"META-INF/versions/30/module-info.class",
|
||||||
|
"META-INF/versions/31/module-info.class",
|
||||||
|
"META-INF/versions/99/module-info.class",
|
||||||
|
"META-INF/versions/100/module-info.class",
|
||||||
|
"META-INF/versions/101/module-info.class",
|
||||||
|
"META-INF/versions/999/module-info.class",
|
||||||
|
"META-INF/versions/1000/module-info.class",
|
||||||
|
"META-INF/versions/1001/module-info.class");
|
||||||
|
Assert.assertEquals(sorted, expected);
|
||||||
|
}
|
||||||
|
}
|
@ -207,11 +207,6 @@ public class IntegrationTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
checkReleaseProperty(props, "JAVA_VERSION");
|
checkReleaseProperty(props, "JAVA_VERSION");
|
||||||
checkReleaseProperty(props, "JAVA_FULL_VERSION");
|
|
||||||
checkReleaseProperty(props, "OS_NAME");
|
|
||||||
checkReleaseProperty(props, "OS_ARCH");
|
|
||||||
// OS_VERSION is added from makefile. We're testing API-way to create image here!
|
|
||||||
// checkReleaseProperty(props, "OS_VERSION");
|
|
||||||
|
|
||||||
if (!Files.exists(output.resolve("toto.txt"))) {
|
if (!Files.exists(output.resolve("toto.txt"))) {
|
||||||
throw new AssertionError("Post processing not called");
|
throw new AssertionError("Post processing not called");
|
||||||
|
@ -178,7 +178,7 @@ public class JLinkNegativeTest {
|
|||||||
.output(imageFile)
|
.output(imageFile)
|
||||||
.addMods("not_zip")
|
.addMods("not_zip")
|
||||||
.modulePath(helper.defaultModulePath())
|
.modulePath(helper.defaultModulePath())
|
||||||
.call().assertFailure("Error: java.util.zip.ZipException: zip file is empty");
|
.call().assertFailure("Error: Error reading");
|
||||||
} finally {
|
} finally {
|
||||||
deleteDirectory(jar);
|
deleteDirectory(jar);
|
||||||
}
|
}
|
||||||
|
@ -113,12 +113,13 @@ public class SystemModulesTest {
|
|||||||
try {
|
try {
|
||||||
if (modRef.descriptor().name().equals("java.base")) {
|
if (modRef.descriptor().name().equals("java.base")) {
|
||||||
ModuleTargetHelper.ModuleTarget mt = ModuleTargetHelper.read(modRef);
|
ModuleTargetHelper.ModuleTarget mt = ModuleTargetHelper.read(modRef);
|
||||||
assertTrue(checkOSName(mt.osName()));
|
String[] values = mt.targetPlatform().split("-");
|
||||||
assertTrue(checkOSArch(mt.osArch()));
|
assertTrue(checkOSName(values[0]));
|
||||||
|
assertTrue(checkOSArch(values[1]));
|
||||||
} else {
|
} else {
|
||||||
// target platform attribute is dropped by jlink plugin for other modules
|
// target platform attribute is dropped by jlink plugin for other modules
|
||||||
ModuleTargetHelper.ModuleTarget mt = ModuleTargetHelper.read(modRef);
|
ModuleTargetHelper.ModuleTarget mt = ModuleTargetHelper.read(modRef);
|
||||||
assertTrue(mt == null || (mt.osName() == null && mt.osArch() == null));
|
assertTrue(mt == null || mt.targetPlatform() == null);
|
||||||
}
|
}
|
||||||
} catch (IOException exp) {
|
} catch (IOException exp) {
|
||||||
throw new UncheckedIOException(exp);
|
throw new UncheckedIOException(exp);
|
||||||
|
@ -220,16 +220,16 @@ public class UserModuleTest {
|
|||||||
throw new RuntimeException("ModuleTarget is missing for java.base");
|
throw new RuntimeException("ModuleTarget is missing for java.base");
|
||||||
}
|
}
|
||||||
|
|
||||||
String osName = mt.osName();
|
String[] values = mt.targetPlatform().split("-");
|
||||||
String osArch = mt.osArch();
|
String osName = values[0];
|
||||||
|
String osArch = values[1];
|
||||||
|
|
||||||
// create JMOD files
|
// create JMOD files
|
||||||
Files.createDirectories(JMODS_DIR);
|
Files.createDirectories(JMODS_DIR);
|
||||||
Stream.of(modules).forEach(mn ->
|
Stream.of(modules).forEach(mn ->
|
||||||
assertTrue(jmod("create",
|
assertTrue(jmod("create",
|
||||||
"--class-path", MODS_DIR.resolve(mn).toString(),
|
"--class-path", MODS_DIR.resolve(mn).toString(),
|
||||||
"--os-name", osName,
|
"--target-platform", mt.targetPlatform(),
|
||||||
"--os-arch", osArch,
|
|
||||||
"--main-class", mn.replace('m', 'p') + ".Main",
|
"--main-class", mn.replace('m', 'p') + ".Main",
|
||||||
JMODS_DIR.resolve(mn + ".jmod").toString()) == 0)
|
JMODS_DIR.resolve(mn + ".jmod").toString()) == 0)
|
||||||
);
|
);
|
||||||
|
@ -62,8 +62,7 @@ public class Main {
|
|||||||
// parse module-info.class
|
// parse module-info.class
|
||||||
ClassReader cr = new ClassReader(in);
|
ClassReader cr = new ClassReader(in);
|
||||||
cr.accept(cv, attrs, 0);
|
cr.accept(cv, attrs, 0);
|
||||||
return modTargets[0] != null &&
|
return modTargets[0] != null && modTargets[0].targetPlatform() != null;
|
||||||
(modTargets[0].osName() != null || modTargets[0].osArch() != null);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void main(String... args) throws Exception {
|
public static void main(String... args) throws Exception {
|
||||||
|
@ -63,8 +63,7 @@ public class Main {
|
|||||||
// parse module-info.class
|
// parse module-info.class
|
||||||
ClassReader cr = new ClassReader(in);
|
ClassReader cr = new ClassReader(in);
|
||||||
cr.accept(cv, attrs, 0);
|
cr.accept(cv, attrs, 0);
|
||||||
return modTargets[0] != null &&
|
return modTargets[0] != null && modTargets[0].targetPlatform() != null;
|
||||||
(modTargets[0].osName() != null || modTargets[0].osArch() != null);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean hasModuleTarget(String modName) throws IOException {
|
private static boolean hasModuleTarget(String modName) throws IOException {
|
||||||
|
@ -393,16 +393,17 @@ public class JmodTest {
|
|||||||
MODS_DIR.resolve("describeFoo.jmod").toString())
|
MODS_DIR.resolve("describeFoo.jmod").toString())
|
||||||
.assertSuccess()
|
.assertSuccess()
|
||||||
.resultChecker(r -> {
|
.resultChecker(r -> {
|
||||||
// Expect similar output: "foo, requires mandated java.base
|
// Expect similar output: "foo... exports jdk.test.foo ...
|
||||||
// exports jdk.test.foo, contains jdk.test.foo.internal"
|
// ... requires java.base mandated... contains jdk.test.foo.internal"
|
||||||
Pattern p = Pattern.compile("\\s+foo\\s+requires\\s+mandated\\s+java.base");
|
Pattern p = Pattern.compile("foo\\s+exports\\s+jdk.test.foo");
|
||||||
assertTrue(p.matcher(r.output).find(),
|
assertTrue(p.matcher(r.output).find(),
|
||||||
"Expecting to find \"foo, requires java.base\"" +
|
"Expecting to find \"foo... exports jdk.test.foo\"" +
|
||||||
"in output, but did not: [" + r.output + "]");
|
"in output, but did not: [" + r.output + "]");
|
||||||
p = Pattern.compile(
|
p = Pattern.compile(
|
||||||
"exports\\s+jdk.test.foo\\s+contains\\s+jdk.test.foo.internal");
|
"requires\\s+java.base\\s+mandated\\s+contains\\s+jdk.test.foo.internal");
|
||||||
assertTrue(p.matcher(r.output).find(),
|
assertTrue(p.matcher(r.output).find(),
|
||||||
"Expecting to find \"exports ..., contains ...\"" +
|
"Expecting to find \"requires java.base mandated..., " +
|
||||||
|
"contains jdk.test.foo.internal ...\"" +
|
||||||
"in output, but did not: [" + r.output + "]");
|
"in output, but did not: [" + r.output + "]");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
103
jdk/test/tools/launcher/modules/describe/DescribeModuleTest.java
Normal file
103
jdk/test/tools/launcher/modules/describe/DescribeModuleTest.java
Normal file
@ -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.xml
|
||||||
|
* @library /lib/testlibrary
|
||||||
|
* @build DescribeModuleTest jdk.testlibrary.*
|
||||||
|
* @run testng DescribeModuleTest
|
||||||
|
* @summary Basic test for java --describe-module
|
||||||
|
*/
|
||||||
|
|
||||||
|
import jdk.testlibrary.ProcessTools;
|
||||||
|
|
||||||
|
import org.testng.annotations.Test;
|
||||||
|
import static org.testng.Assert.*;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public class DescribeModuleTest {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test that the output describes java.base
|
||||||
|
*/
|
||||||
|
private void expectJavaBase(String... args) throws Exception {
|
||||||
|
int exitValue = ProcessTools.executeTestJava(args)
|
||||||
|
.outputTo(System.out)
|
||||||
|
.errorTo(System.out)
|
||||||
|
.stdoutShouldContain("java.base")
|
||||||
|
.stdoutShouldContain("exports java.lang")
|
||||||
|
.stdoutShouldContain("uses java.nio.file.spi.FileSystemProvider")
|
||||||
|
.stdoutShouldContain("contains sun.launcher")
|
||||||
|
.stdoutShouldNotContain("requires ")
|
||||||
|
.getExitValue();
|
||||||
|
assertTrue(exitValue == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test that the output describes java.xml
|
||||||
|
*/
|
||||||
|
private void expectJavaXml(String... args) throws Exception {
|
||||||
|
int exitValue = ProcessTools.executeTestJava(args)
|
||||||
|
.outputTo(System.out)
|
||||||
|
.errorTo(System.out)
|
||||||
|
.stdoutShouldContain("java.xml")
|
||||||
|
.stdoutShouldContain("exports javax.xml")
|
||||||
|
.stdoutShouldContain("requires java.base")
|
||||||
|
.stdoutShouldContain("uses javax.xml.stream.XMLInputFactory")
|
||||||
|
.getExitValue();
|
||||||
|
assertTrue(exitValue == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test output/exitValue when describing an unknown module
|
||||||
|
*/
|
||||||
|
private void expectUnknownModule(String... args) throws Exception {
|
||||||
|
int exitValue = ProcessTools.executeTestJava(args)
|
||||||
|
.outputTo(System.out)
|
||||||
|
.errorTo(System.out)
|
||||||
|
.stdoutShouldNotContain("requires java.base")
|
||||||
|
.getExitValue();
|
||||||
|
assertTrue(exitValue != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void testDescribeJavaBase() throws Exception {
|
||||||
|
expectJavaBase("--describe-module", "java.base");
|
||||||
|
expectJavaBase("--describe-module=java.base");
|
||||||
|
expectJavaBase("-d", "java.base");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testDescribeJavaXml() throws Exception {
|
||||||
|
expectJavaXml("--describe-module", "java.xml");
|
||||||
|
expectJavaXml("--describe-module=java.xml");
|
||||||
|
expectJavaXml("-d", "java.xml");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testDescribeUnknownModule() throws Exception {
|
||||||
|
expectUnknownModule("--describe-module", "jdk.rhubarb");
|
||||||
|
expectUnknownModule("--describe-module=jdk.rhubarb");
|
||||||
|
expectUnknownModule("-d", "jdk.rhubarb");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -33,7 +33,7 @@
|
|||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
|
|
||||||
import static jdk.testlibrary.ProcessTools.*;
|
import jdk.testlibrary.ProcessTools;
|
||||||
import jdk.testlibrary.OutputAnalyzer;
|
import jdk.testlibrary.OutputAnalyzer;
|
||||||
|
|
||||||
import org.testng.annotations.BeforeTest;
|
import org.testng.annotations.BeforeTest;
|
||||||
@ -66,138 +66,80 @@ public class ListModsTest {
|
|||||||
SRC_DIR.resolve("java.transaction"),
|
SRC_DIR.resolve("java.transaction"),
|
||||||
UPGRADEMODS_DIR.resolve("java.transaction"));
|
UPGRADEMODS_DIR.resolve("java.transaction"));
|
||||||
assertTrue(compiled);
|
assertTrue(compiled);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testListAll() throws Exception {
|
public void testListAll() throws Exception {
|
||||||
OutputAnalyzer output
|
exec("--list-modules")
|
||||||
= executeTestJava("--list-modules")
|
.shouldContain("java.base")
|
||||||
.outputTo(System.out)
|
.shouldContain("java.xml")
|
||||||
.errorTo(System.out);
|
.shouldHaveExitValue(0);
|
||||||
output.shouldContain("java.base");
|
|
||||||
output.shouldContain("java.xml");
|
|
||||||
assertTrue(output.getExitValue() == 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testListOneModule() throws Exception {
|
|
||||||
OutputAnalyzer output
|
|
||||||
= executeTestJava("--list-modules=java.base")
|
|
||||||
.outputTo(System.out)
|
|
||||||
.errorTo(System.out);
|
|
||||||
output.shouldContain("java.base");
|
|
||||||
output.shouldContain("exports java.lang");
|
|
||||||
assertTrue(output.getExitValue() == 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testListTwoModules() throws Exception {
|
|
||||||
OutputAnalyzer output
|
|
||||||
= executeTestJava("--list-modules", "java.base,java.xml")
|
|
||||||
.outputTo(System.out)
|
|
||||||
.errorTo(System.out);
|
|
||||||
output.shouldContain("java.base");
|
|
||||||
output.shouldContain("exports java.lang");
|
|
||||||
output.shouldContain("java.xml");
|
|
||||||
output.shouldContain("exports javax.xml");
|
|
||||||
assertTrue(output.getExitValue() == 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testListUnknownModule() throws Exception {
|
|
||||||
OutputAnalyzer output
|
|
||||||
= executeTestJava("--list-modules", "java.rhubarb")
|
|
||||||
.outputTo(System.out)
|
|
||||||
.errorTo(System.out);
|
|
||||||
output.shouldNotContain("java.base");
|
|
||||||
output.shouldContain("java.rhubarb not found");
|
|
||||||
assertTrue(output.getExitValue() == 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testListWithModulePath() throws Exception {
|
public void testListWithModulePath() throws Exception {
|
||||||
OutputAnalyzer output
|
exec("--list-modules", "--module-path", MODS_DIR.toString())
|
||||||
= executeTestJava("--module-path", MODS_DIR.toString(), "--list-modules")
|
.shouldContain("java.base")
|
||||||
.outputTo(System.out)
|
.shouldContain("m1")
|
||||||
.errorTo(System.out);
|
.shouldHaveExitValue(0);
|
||||||
output.shouldContain("java.base");
|
|
||||||
output.shouldContain("m1");
|
|
||||||
assertTrue(output.getExitValue() == 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testListWithUpgradeModulePath() throws Exception {
|
public void testListWithUpgradeModulePath() throws Exception {
|
||||||
OutputAnalyzer output
|
String dir = UPGRADEMODS_DIR.toString();
|
||||||
= executeTestJava("--upgrade-module-path", UPGRADEMODS_DIR.toString(),
|
exec("--list-modules", "--upgrade-module-path", dir)
|
||||||
"--list-modules", "java.transaction")
|
.shouldContain(UPGRADEMODS_DIR.toString())
|
||||||
.outputTo(System.out)
|
.shouldHaveExitValue(0);
|
||||||
.errorTo(System.out);
|
|
||||||
output.shouldContain("exports javax.transaction.atomic");
|
|
||||||
assertTrue(output.getExitValue() == 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testListWithLimitMods1() throws Exception {
|
public void testListWithLimitMods1() throws Exception {
|
||||||
OutputAnalyzer output
|
exec("--limit-modules", "java.management.rmi", "--list-modules")
|
||||||
= executeTestJava("--limit-modules", "java.management.rmi", "--list-modules")
|
.shouldContain("java.rmi")
|
||||||
.outputTo(System.out)
|
.shouldContain("java.base")
|
||||||
.errorTo(System.out);
|
.shouldNotContain("java.scripting")
|
||||||
output.shouldContain("java.rmi");
|
.shouldHaveExitValue(0);
|
||||||
output.shouldContain("java.base");
|
|
||||||
output.shouldNotContain("java.scripting");
|
|
||||||
assertTrue(output.getExitValue() == 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testListWithLimitMods2() throws Exception {
|
public void testListWithLimitMods2() throws Exception {
|
||||||
OutputAnalyzer output
|
exec("--list-modules",
|
||||||
= executeTestJava("--module-path", MODS_DIR.toString(),
|
"--module-path", MODS_DIR.toString(),
|
||||||
"--limit-modules", "java.management",
|
"--limit-modules", "java.management")
|
||||||
"--list-modules")
|
.shouldContain("java.base")
|
||||||
.outputTo(System.out)
|
.shouldNotContain("m1")
|
||||||
.errorTo(System.out);
|
.shouldHaveExitValue(0);
|
||||||
output.shouldContain("java.base");
|
|
||||||
output.shouldNotContain("m1");
|
|
||||||
assertTrue(output.getExitValue() == 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* java -version --list-modules => should print version and exit
|
* java -version --list-modules => should print version and exit
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void testListWithPrintVersion1() throws Exception {
|
public void testListWithPrintVersion1() throws Exception {
|
||||||
OutputAnalyzer output
|
exec("-version", "--list-modules")
|
||||||
= executeTestJava("-version", "--list-modules")
|
.shouldNotContain("java.base")
|
||||||
.outputTo(System.out)
|
.shouldContain("Runtime Environment")
|
||||||
.errorTo(System.out);
|
.shouldHaveExitValue(0);
|
||||||
output.shouldNotContain("java.base");
|
|
||||||
output.shouldContain("Runtime Environment");
|
|
||||||
assertTrue(output.getExitValue() == 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* java --list-modules -version => should list modules and exit
|
* java --list-modules -version => should list modules and exit
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void testListWithPrintVersion2() throws Exception {
|
public void testListWithPrintVersion2() throws Exception {
|
||||||
OutputAnalyzer output
|
exec("--list-modules", "-version")
|
||||||
= executeTestJava("--list-modules", "-version")
|
.shouldContain("java.base")
|
||||||
|
.shouldNotContain("Runtime Environment")
|
||||||
|
.shouldHaveExitValue(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* java args... returning the OutputAnalyzer to analyzer the output
|
||||||
|
*/
|
||||||
|
private OutputAnalyzer exec(String... args) throws Exception {
|
||||||
|
return ProcessTools.executeTestJava(args)
|
||||||
.outputTo(System.out)
|
.outputTo(System.out)
|
||||||
.errorTo(System.out);
|
.errorTo(System.out);
|
||||||
output.shouldContain("java.base");
|
|
||||||
output.shouldNotContain("Runtime Environment");
|
|
||||||
assertTrue(output.getExitValue() == 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -23,5 +23,4 @@
|
|||||||
|
|
||||||
module java.transaction {
|
module java.transaction {
|
||||||
exports javax.transaction;
|
exports javax.transaction;
|
||||||
exports javax.transaction.atomic;
|
|
||||||
}
|
}
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user