Merge
This commit is contained in:
commit
853c626781
@ -39,6 +39,7 @@ SUNWprivate_1.1 {
|
||||
Java_sun_instrument_InstrumentationImpl_getObjectSize0;
|
||||
Java_sun_instrument_InstrumentationImpl_appendToClassLoaderSearch0;
|
||||
Java_sun_instrument_InstrumentationImpl_setNativeMethodPrefixes;
|
||||
Java_sun_instrument_InstrumentationImpl_loadAgent0;
|
||||
local:
|
||||
*;
|
||||
};
|
||||
|
@ -119,18 +119,24 @@ import sun.security.util.SecurityConstants;
|
||||
* The Java run-time has the following built-in class loaders:
|
||||
*
|
||||
* <ul>
|
||||
* <li>Bootstrap class loader.
|
||||
* <li><p>Bootstrap class loader.
|
||||
* It is the virtual machine's built-in class loader, typically represented
|
||||
* 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
|
||||
* that can be used as the parent of a {@code ClassLoader} instance.
|
||||
* Platform classes include Java SE platform APIs, their implementation
|
||||
* classes and JDK-specific run-time classes that are defined by the
|
||||
* platform class loader or its ancestors.</li>
|
||||
* <li>{@linkplain #getSystemClassLoader() System class loader}.
|
||||
* It is also known as <em>application class
|
||||
* loader</em> and is distinct from the platform class loader.
|
||||
* platform class loader or its ancestors.
|
||||
* <p> To allow for upgrading/overriding of modules defined to the platform
|
||||
* class loader, and where classes in the upgraded version link to
|
||||
* 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
|
||||
* application class path, module path, and JDK-specific tools.
|
||||
* 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
|
||||
* 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 parent the parent class loader
|
||||
*
|
||||
@ -390,9 +400,12 @@ public abstract class ClassLoader {
|
||||
* delegation.
|
||||
*
|
||||
* <p> If there is a security manager, its {@link
|
||||
* SecurityManager#checkCreateClassLoader()
|
||||
* checkCreateClassLoader} method is invoked. This may result in
|
||||
* a security exception. </p>
|
||||
* SecurityManager#checkCreateClassLoader() checkCreateClassLoader} method
|
||||
* is invoked. This may result in 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
|
||||
* The parent class loader
|
||||
@ -2206,6 +2219,12 @@ public abstract class ClassLoader {
|
||||
* this class loader are searched recursively (parent by parent)
|
||||
* 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
|
||||
* 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
|
||||
* 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
|
||||
* class loader and its ancestors
|
||||
*
|
||||
|
@ -57,6 +57,7 @@ import jdk.internal.loader.BuiltinClassLoader;
|
||||
import jdk.internal.loader.BootLoader;
|
||||
import jdk.internal.misc.JavaLangAccess;
|
||||
import jdk.internal.misc.SharedSecrets;
|
||||
import jdk.internal.module.ModuleLoaderMap;
|
||||
import jdk.internal.module.ServicesCatalog;
|
||||
import jdk.internal.module.Resources;
|
||||
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
|
||||
* module is not in a layer.
|
||||
* Returns the module layer that contains this module or {@code null} if
|
||||
* this module is not in a module layer.
|
||||
*
|
||||
* A module layer contains named modules and therefore this method always
|
||||
* 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>
|
||||
* 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
|
||||
* The package name
|
||||
* @param other
|
||||
@ -1077,7 +1085,7 @@ public final class Module implements AnnotatedElement {
|
||||
if (loader != null) {
|
||||
moduleToLoader.put(name, loader);
|
||||
loaders.add(loader);
|
||||
} else if (!isBootLayer) {
|
||||
} else if (!(clf instanceof ModuleLoaderMap.Mapper)) {
|
||||
throw new IllegalArgumentException("loader can't be 'null'");
|
||||
}
|
||||
}
|
||||
@ -1458,11 +1466,11 @@ public final class Module implements AnnotatedElement {
|
||||
* encapsulated. </li>
|
||||
*
|
||||
* <li> A <em>package name</em> is derived from the resource name. If
|
||||
* the package name is a {@link #getPackages() package} in the module
|
||||
* then the resource can only be located by the caller of this method
|
||||
* when the package is {@link #isOpen(String,Module) open} to at least
|
||||
* the caller's module. If the resource is not in a package in the module
|
||||
* then the resource is not encapsulated. </li>
|
||||
* the package name is a {@linkplain #getPackages() package} in the
|
||||
* module then the resource can only be located by the caller of this
|
||||
* method when the package is {@linkplain #isOpen(String,Module) open}
|
||||
* to at least the caller's module. If the resource is not in a
|
||||
* package in the module then the resource is not encapsulated. </li>
|
||||
* </ul>
|
||||
*
|
||||
* <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
|
||||
JavaLangAccess jla = SharedSecrets.getJavaLangAccess();
|
||||
URL url = jla.findResource(loader, mn, name);
|
||||
URL url = loader.findResource(mn, name);
|
||||
if (url != null) {
|
||||
try {
|
||||
return url.openStream();
|
||||
|
@ -25,10 +25,10 @@
|
||||
|
||||
package java.lang;
|
||||
|
||||
import java.lang.RuntimePermission;
|
||||
import java.lang.module.ModuleDescriptor;
|
||||
import java.lang.module.ModuleDescriptor.Exports;
|
||||
import java.lang.module.ModuleDescriptor.Opens;
|
||||
import java.lang.module.ModuleReference;
|
||||
import java.lang.reflect.Member;
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.File;
|
||||
@ -42,12 +42,15 @@ import java.security.PrivilegedAction;
|
||||
import java.security.Security;
|
||||
import java.security.SecurityPermission;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.PropertyPermission;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
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 sun.security.util.SecurityConstants;
|
||||
|
||||
@ -1431,30 +1434,30 @@ class SecurityManager {
|
||||
return packages;
|
||||
}
|
||||
|
||||
// The non-exported packages of the modules in the boot layer that are
|
||||
// loaded by the platform class loader or its ancestors. A non-exported
|
||||
// package is a package that either is not exported at all by its containing
|
||||
// module or is exported in a qualified fashion by its containing module.
|
||||
private static final Set<String> nonExportedPkgs;
|
||||
|
||||
// The non-exported packages in modules defined to the boot or platform
|
||||
// class loaders. A non-exported package is a package that is not exported
|
||||
// or is only exported to specific modules.
|
||||
private static final Map<String, Boolean> nonExportedPkgs = new ConcurrentHashMap<>();
|
||||
static {
|
||||
// Get the modules in the boot layer
|
||||
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());
|
||||
addNonExportedPackages(ModuleLayer.boot());
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
@ -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.
|
||||
*/
|
||||
@ -1535,7 +1530,7 @@ class SecurityManager {
|
||||
Objects.requireNonNull(pkg, "package name can't be null");
|
||||
|
||||
// check if pkg is not exported to all modules
|
||||
if (nonExportedPkgs.contains(pkg)) {
|
||||
if (nonExportedPkgs.containsKey(pkg)) {
|
||||
checkPermission(
|
||||
new RuntimePermission("accessClassInPackage." + pkg));
|
||||
return;
|
||||
@ -1634,7 +1629,7 @@ class SecurityManager {
|
||||
Objects.requireNonNull(pkg, "package name can't be null");
|
||||
|
||||
// check if pkg is not exported to all modules
|
||||
if (nonExportedPkgs.contains(pkg)) {
|
||||
if (nonExportedPkgs.containsKey(pkg)) {
|
||||
checkPermission(
|
||||
new RuntimePermission("defineClassInPackage." + pkg));
|
||||
return;
|
||||
|
@ -41,7 +41,6 @@ import java.lang.reflect.Executable;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.net.URI;
|
||||
import java.net.URL;
|
||||
import java.security.AccessControlContext;
|
||||
import java.security.ProtectionDomain;
|
||||
import java.security.AccessController;
|
||||
@ -2111,9 +2110,6 @@ public final class System {
|
||||
public Class<?> findBootstrapClassOrNull(ClassLoader cl, String 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) {
|
||||
return cl.packages();
|
||||
}
|
||||
@ -2123,6 +2119,9 @@ public final class System {
|
||||
public String fastUUID(long lsb, long msb) {
|
||||
return Long.fastUUID(lsb, msb);
|
||||
}
|
||||
public void addNonExportedPackages(ModuleLayer layer) {
|
||||
SecurityManager.addNonExportedPackages(layer);
|
||||
}
|
||||
public void invalidatePackageAccessCache() {
|
||||
SecurityManager.invalidatePackageAccessCache();
|
||||
}
|
||||
|
@ -876,9 +876,7 @@ public class MethodHandles {
|
||||
* 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
|
||||
* 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}
|
||||
* access. A lookup with {@code PRIVATE} access can be downgraded to drop this lookup
|
||||
* mode with the {@linkplain #dropLookupMode(int) dropLookupMode} method. </p>
|
||||
* the runtime package). </p>
|
||||
*
|
||||
* <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
|
||||
@ -896,7 +894,6 @@ public class MethodHandles {
|
||||
* @throws IllegalArgumentException the bytes are for a class in a different package
|
||||
* to the lookup class
|
||||
* @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
|
||||
* verified ({@code VerifyError}), is already defined, or another linkage error occurs
|
||||
* @throws SecurityException if denied by the security manager
|
||||
@ -911,8 +908,6 @@ public class MethodHandles {
|
||||
SecurityManager sm = System.getSecurityManager();
|
||||
if (sm != null)
|
||||
sm.checkPermission(new RuntimePermission("defineClass"));
|
||||
if (hasPrivateAccess())
|
||||
throw new UnsupportedOperationException("PRIVATE access not supported");
|
||||
if ((lookupModes() & PACKAGE) == 0)
|
||||
throw new IllegalAccessException("Lookup does not have PACKAGE access");
|
||||
assert (lookupModes() & (MODULE|PUBLIC)) != 0;
|
||||
|
@ -109,20 +109,17 @@ public final class Configuration {
|
||||
private final Set<ResolvedModule> modules;
|
||||
private final Map<String, ResolvedModule> nameToModule;
|
||||
|
||||
// module constraints on target
|
||||
private final String osName;
|
||||
private final String osArch;
|
||||
// constraint on target platform
|
||||
private final String targetPlatform;
|
||||
|
||||
String osName() { return osName; }
|
||||
String osArch() { return osArch; }
|
||||
String targetPlatform() { return targetPlatform; }
|
||||
|
||||
private Configuration() {
|
||||
this.parents = Collections.emptyList();
|
||||
this.graph = Collections.emptyMap();
|
||||
this.modules = Collections.emptySet();
|
||||
this.nameToModule = Collections.emptyMap();
|
||||
this.osName = null;
|
||||
this.osArch = null;
|
||||
this.targetPlatform = null;
|
||||
}
|
||||
|
||||
private Configuration(List<Configuration> parents,
|
||||
@ -147,8 +144,7 @@ public final class Configuration {
|
||||
this.modules = Set.of(moduleArray);
|
||||
this.nameToModule = Map.ofEntries(nameEntries);
|
||||
|
||||
this.osName = resolver.osName();
|
||||
this.osArch = resolver.osArch();
|
||||
this.targetPlatform = resolver.targetPlatform();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -99,6 +99,7 @@ public class ModuleDescriptor
|
||||
*
|
||||
* @see ModuleDescriptor#modifiers()
|
||||
* @since 9
|
||||
* @spec JPMS
|
||||
*/
|
||||
public static enum Modifier {
|
||||
/**
|
||||
|
@ -286,8 +286,9 @@ public interface ModuleFinder {
|
||||
* class names of provider classes. </p></li>
|
||||
*
|
||||
* <li><p> If the JAR file has a {@code Main-Class} attribute in its
|
||||
* main manifest then its value is the module {@link
|
||||
* ModuleDescriptor#mainClass() main class}. </p></li>
|
||||
* main manifest, its value is a legal class name, and its package is
|
||||
* in the set of packages derived for the module, then the value is the
|
||||
* module {@linkplain ModuleDescriptor#mainClass() main class}. </p></li>
|
||||
*
|
||||
* </ul>
|
||||
*
|
||||
@ -298,8 +299,7 @@ public interface ModuleFinder {
|
||||
* 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
|
||||
* 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
|
||||
* a legal class name or its package is not in the module. </p>
|
||||
* packages derived for the module. </p>
|
||||
*
|
||||
* <p> In addition to JAR files, an implementation may also support modules
|
||||
* that are packaged in other implementation specific module formats. If
|
||||
|
@ -28,6 +28,7 @@ package java.lang.module;
|
||||
import java.io.PrintStream;
|
||||
import java.lang.module.ModuleDescriptor.Provides;
|
||||
import java.lang.module.ModuleDescriptor.Requires.Modifier;
|
||||
import java.net.URI;
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
@ -38,10 +39,8 @@ import java.util.HashSet;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.StringJoiner;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import jdk.internal.module.ModuleHashes;
|
||||
@ -69,12 +68,10 @@ final class Resolver {
|
||||
// true if all automatic modules have been found
|
||||
private boolean haveAllAutomaticModules;
|
||||
|
||||
// module constraints on target platform
|
||||
private String osName;
|
||||
private String osArch;
|
||||
// constraint on target platform
|
||||
private String targetPlatform;
|
||||
|
||||
String osName() { return osName; }
|
||||
String osArch() { return osArch; }
|
||||
String targetPlatform() { return targetPlatform; }
|
||||
|
||||
/**
|
||||
* @throws IllegalArgumentException if there are more than one parent and
|
||||
@ -89,37 +86,23 @@ final class Resolver {
|
||||
this.afterFinder = afterFinder;
|
||||
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) {
|
||||
String value = parent.osName();
|
||||
String value = parent.targetPlatform();
|
||||
if (value != null) {
|
||||
if (osName == null) {
|
||||
osName = value;
|
||||
if (targetPlatform == null) {
|
||||
targetPlatform = value;
|
||||
} else {
|
||||
if (!value.equals(osName)) {
|
||||
failParentConflict("Operating System", osName, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
value = parent.osArch();
|
||||
if (value != null) {
|
||||
if (osArch == null) {
|
||||
osArch = value;
|
||||
} else {
|
||||
if (!value.equals(osArch)) {
|
||||
failParentConflict("OS architecture", osArch, value);
|
||||
if (!value.equals(targetPlatform)) {
|
||||
String msg = "Parents have conflicting constraints on target" +
|
||||
" platform: " + targetPlatform + ", " + value;
|
||||
throw new IllegalArgumentException(msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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.
|
||||
*
|
||||
@ -147,8 +130,7 @@ final class Resolver {
|
||||
}
|
||||
|
||||
if (isTracing()) {
|
||||
trace("Root module %s located", root);
|
||||
mref.location().ifPresent(uri -> trace(" (%s)", uri));
|
||||
trace("root %s", nameAndInfo(mref));
|
||||
}
|
||||
|
||||
addFoundModule(mref);
|
||||
@ -180,9 +162,7 @@ final class Resolver {
|
||||
ModuleDescriptor other = mref.descriptor();
|
||||
q.offer(other);
|
||||
if (isTracing()) {
|
||||
trace("Automatic module %s located, required by %s",
|
||||
other.name(), descriptor.name());
|
||||
mref.location().ifPresent(uri -> trace(" (%s)", uri));
|
||||
trace("%s requires %s", descriptor.name(), nameAndInfo(mref));
|
||||
}
|
||||
});
|
||||
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)) {
|
||||
addFoundModule(mref);
|
||||
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 {
|
||||
for (ModuleDescriptor descriptor : candidateConsumers) {
|
||||
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()) {
|
||||
Set<ModuleReference> mrefs = availableProviders.get(service);
|
||||
if (mrefs != null) {
|
||||
@ -298,15 +277,13 @@ final class Resolver {
|
||||
ModuleDescriptor provider = mref.descriptor();
|
||||
if (!provider.equals(descriptor)) {
|
||||
|
||||
trace("Module %s provides %s, used by %s",
|
||||
provider.name(), service, descriptor.name());
|
||||
if (isTracing() && modulesToBind.add(provider)) {
|
||||
trace("%s binds %s", descriptor.name(),
|
||||
nameAndInfo(mref));
|
||||
}
|
||||
|
||||
String pn = provider.name();
|
||||
if (!nameToReference.containsKey(pn)) {
|
||||
if (isTracing()) {
|
||||
mref.location()
|
||||
.ifPresent(uri -> trace(" (%s)", uri));
|
||||
}
|
||||
addFoundModule(mref);
|
||||
q.push(provider);
|
||||
}
|
||||
@ -349,59 +326,31 @@ final class Resolver {
|
||||
if (mref instanceof ModuleReferenceImpl) {
|
||||
ModuleTarget target = ((ModuleReferenceImpl)mref).moduleTarget();
|
||||
if (target != null)
|
||||
checkTargetConstraints(mn, target);
|
||||
checkTargetPlatform(mn, target);
|
||||
}
|
||||
|
||||
nameToReference.put(mn, mref);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check that the module's constraints on the target platform do not
|
||||
* conflict with the constraints of other modules resolved so far or
|
||||
* modules in parent configurations.
|
||||
* Check that the module's constraints on the target platform does
|
||||
* conflict with the constraint of other modules resolved so far.
|
||||
*/
|
||||
private void checkTargetConstraints(String mn, ModuleTarget target) {
|
||||
String value = target.osName();
|
||||
private void checkTargetPlatform(String mn, ModuleTarget target) {
|
||||
String value = target.targetPlatform();
|
||||
if (value != null) {
|
||||
if (osName == null) {
|
||||
osName = value;
|
||||
if (targetPlatform == null) {
|
||||
targetPlatform = value;
|
||||
} else {
|
||||
if (!value.equals(osName)) {
|
||||
failTargetConstraint(mn, target);
|
||||
}
|
||||
}
|
||||
}
|
||||
value = target.osArch();
|
||||
if (value != null) {
|
||||
if (osArch == null) {
|
||||
osArch = value;
|
||||
} else {
|
||||
if (!value.equals(osArch)) {
|
||||
failTargetConstraint(mn, target);
|
||||
if (!value.equals(targetPlatform)) {
|
||||
findFail("Module %s has constraints on target platform (%s)"
|
||||
+ " that conflict with other modules: %s", mn,
|
||||
value, targetPlatform);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
* 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,
|
||||
boolean check)
|
||||
{
|
||||
if (isTracing()) {
|
||||
trace("Result:");
|
||||
Set<String> names = nameToReference.keySet();
|
||||
names.stream().sorted().forEach(name -> trace(" %s", name));
|
||||
}
|
||||
|
||||
if (check) {
|
||||
detectCycles();
|
||||
checkHashes();
|
||||
@ -520,9 +463,8 @@ final class Resolver {
|
||||
findFail("Unable to compute the hash of module %s", dn);
|
||||
}
|
||||
|
||||
// skip checking the hash if the module has been patched
|
||||
ModuleReferenceImpl other = (ModuleReferenceImpl)mref2;
|
||||
if (other != null && !other.isPatched()) {
|
||||
if (other != null) {
|
||||
byte[] recordedHash = hashes.hashFor(dn);
|
||||
byte[] actualHash = other.computeHash(algorithm);
|
||||
if (actualHash == null)
|
||||
@ -965,9 +907,17 @@ final class Resolver {
|
||||
|
||||
private void trace(String fmt, Object ... args) {
|
||||
if (traceOutput != null) {
|
||||
traceOutput.format("[Resolver] " + fmt, args);
|
||||
traceOutput.format(fmt, args);
|
||||
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.
|
||||
*
|
||||
* 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.ServiceLoader;
|
||||
|
||||
import jdk.internal.misc.VM;
|
||||
|
||||
/**
|
||||
* Factory methods for file systems. This class defines the {@link #getDefault
|
||||
* 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
|
||||
// set then its value is the name of the default provider (or a list)
|
||||
String propValue = System
|
||||
.getProperty("java.nio.file.spi.DefaultFileSystemProvider");
|
||||
String prop = "java.nio.file.spi.DefaultFileSystemProvider";
|
||||
String propValue = System.getProperty(prop);
|
||||
if (propValue != null) {
|
||||
for (String cn: propValue.split(",")) {
|
||||
try {
|
||||
@ -184,7 +186,7 @@ public final class FileSystems {
|
||||
* @return the default file system
|
||||
*/
|
||||
public static FileSystem getDefault() {
|
||||
if (jdk.internal.misc.VM.isBooted()) {
|
||||
if (VM.isModuleSystemInited()) {
|
||||
return DefaultFileSystemHolder.defaultFileSystem;
|
||||
} else {
|
||||
return BuiltinFileSystemHolder.builtinFileSystem;
|
||||
|
@ -172,12 +172,10 @@ public class BuiltinClassLoader
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a module this this class loader. This has the effect of making
|
||||
* the types in the module visible.
|
||||
* Register a module this class loader. This has the effect of making the
|
||||
* types in the module visible.
|
||||
*/
|
||||
public void loadModule(ModuleReference mref) {
|
||||
assert !VM.isModuleSystemInited();
|
||||
|
||||
String mn = mref.descriptor().name();
|
||||
if (nameToModule.putIfAbsent(mn, mref) != null) {
|
||||
throw new InternalError(mn + " already defined to this loader");
|
||||
@ -191,6 +189,11 @@ public class BuiltinClassLoader
|
||||
+ 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 {
|
||||
SoftReference<Map<String, List<URL>>> ref = this.resourceCache;
|
||||
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);
|
||||
if (urls != null)
|
||||
return urls;
|
||||
@ -381,23 +387,18 @@ public class BuiltinClassLoader
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
return (result != null) ? result : Collections.emptyList();
|
||||
}
|
||||
});
|
||||
} catch (PrivilegedActionException pae) {
|
||||
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 (map == null) {
|
||||
map = new ConcurrentHashMap<>();
|
||||
this.resourceCache = new SoftReference<>(map);
|
||||
}
|
||||
if (urls == null)
|
||||
urls = Collections.emptyList();
|
||||
map.putIfAbsent(name, urls);
|
||||
}
|
||||
|
||||
return urls;
|
||||
}
|
||||
|
||||
|
@ -25,13 +25,11 @@
|
||||
|
||||
package jdk.internal.misc;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.module.ModuleDescriptor;
|
||||
import java.lang.reflect.Executable;
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.URI;
|
||||
import java.net.URL;
|
||||
import java.security.AccessControlContext;
|
||||
import java.security.ProtectionDomain;
|
||||
import java.util.Map;
|
||||
@ -156,12 +154,6 @@ public interface JavaLangAccess {
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
@ -177,6 +169,11 @@ public interface JavaLangAccess {
|
||||
*/
|
||||
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
|
||||
*/
|
||||
|
@ -25,6 +25,8 @@
|
||||
|
||||
package jdk.internal.module;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Utility class for checking module, package, and class names.
|
||||
*/
|
||||
@ -45,18 +47,17 @@ public final class Checks {
|
||||
int next;
|
||||
int off = 0;
|
||||
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"
|
||||
+ ": '" + id + "' is not a Java identifier");
|
||||
}
|
||||
off = next+1;
|
||||
}
|
||||
int last = isJavaIdentifier(name, off, name.length() - off);
|
||||
if (last == -1) {
|
||||
String id = name.substring(off);
|
||||
String last = name.substring(off);
|
||||
if (!isJavaIdentifier(last)) {
|
||||
throw new IllegalArgumentException(name + ": Invalid module name"
|
||||
+ ": '" + id + "' is not a Java identifier");
|
||||
+ ": '" + last + "' is not a Java identifier");
|
||||
}
|
||||
return name;
|
||||
}
|
||||
@ -68,14 +69,13 @@ public final class Checks {
|
||||
int next;
|
||||
int off = 0;
|
||||
while ((next = name.indexOf('.', off)) != -1) {
|
||||
if (isJavaIdentifier(name, off, (next - off)) == -1)
|
||||
String id = name.substring(off, next);
|
||||
if (!isJavaIdentifier(id))
|
||||
return false;
|
||||
off = next+1;
|
||||
}
|
||||
int last = isJavaIdentifier(name, off, name.length() - off);
|
||||
if (last == -1)
|
||||
return false;
|
||||
return true;
|
||||
String last = name.substring(off);
|
||||
return isJavaIdentifier(last);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -144,12 +144,13 @@ public final class Checks {
|
||||
int next;
|
||||
int off = 0;
|
||||
while ((next = name.indexOf('.', off)) != -1) {
|
||||
if (isJavaIdentifier(name, off, (next - off)) == -1)
|
||||
String id = name.substring(off, next);
|
||||
if (!isJavaIdentifier(id))
|
||||
return false;
|
||||
off = next+1;
|
||||
}
|
||||
int count = name.length() - off;
|
||||
return (isJavaIdentifier(name, off, count) != -1);
|
||||
String last = name.substring(off);
|
||||
return isJavaIdentifier(last);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -164,76 +165,99 @@ public final class Checks {
|
||||
int next;
|
||||
int off = 0;
|
||||
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
|
||||
+ ": '" + id + "' is not a Java identifier");
|
||||
}
|
||||
off = next + 1;
|
||||
}
|
||||
if (isJavaIdentifier(name, off, name.length() - off) == -1) {
|
||||
String id = name.substring(off, name.length());
|
||||
String last = name.substring(off);
|
||||
if (!isJavaIdentifier(last)) {
|
||||
throw new IllegalArgumentException(name + ": Invalid " + what
|
||||
+ ": '" + id + "' is not a Java identifier");
|
||||
+ ": '" + last + "' is not a Java identifier");
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if a given legal module name contains an identifier
|
||||
* that doesn't end with a Java letter.
|
||||
* Returns true if the given char sequence is a legal Java identifier,
|
||||
* otherwise false.
|
||||
*/
|
||||
public static boolean hasJavaIdentifierWithTrailingDigit(String name) {
|
||||
// quick scan to allow names that are just ASCII without digits
|
||||
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)
|
||||
private static boolean isJavaIdentifier(CharSequence cs) {
|
||||
if (cs.length() == 0 || RESERVED.contains(cs))
|
||||
return false;
|
||||
|
||||
// slow path
|
||||
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);
|
||||
int first = Character.codePointAt(cs, 0);
|
||||
if (!Character.isJavaIdentifierStart(first))
|
||||
return -1;
|
||||
return false;
|
||||
|
||||
int cp = first;
|
||||
int i = Character.charCount(first);
|
||||
while (i < count) {
|
||||
cp = Character.codePointAt(cs, offset+i);
|
||||
while (i < cs.length()) {
|
||||
int cp = Character.codePointAt(cs, i);
|
||||
if (!Character.isJavaIdentifierPart(cp))
|
||||
return -1;
|
||||
return false;
|
||||
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;
|
||||
* u4 attribute_length;
|
||||
*
|
||||
* // index to CONSTANT_utf8_info structure with the OS name
|
||||
* u2 os_name_index;
|
||||
* // index to CONSTANT_utf8_info structure with the OS arch
|
||||
* u2 os_arch_index
|
||||
* // index to CONSTANT_utf8_info structure with the target platform
|
||||
* u2 target_platform_index;
|
||||
* }
|
||||
*
|
||||
* } </pre>
|
||||
*/
|
||||
public static class ModuleTargetAttribute extends Attribute {
|
||||
private final String osName;
|
||||
private final String osArch;
|
||||
private final String targetPlatform;
|
||||
|
||||
public ModuleTargetAttribute(String osName, String osArch) {
|
||||
public ModuleTargetAttribute(String targetPlatform) {
|
||||
super(MODULE_TARGET);
|
||||
this.osName = osName;
|
||||
this.osArch = osArch;
|
||||
this.targetPlatform = targetPlatform;
|
||||
}
|
||||
|
||||
public ModuleTargetAttribute() {
|
||||
this(null, null);
|
||||
this(null);
|
||||
}
|
||||
|
||||
public String osName() {
|
||||
return osName;
|
||||
}
|
||||
|
||||
public String osArch() {
|
||||
return osArch;
|
||||
public String targetPlatform() {
|
||||
return targetPlatform;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -588,20 +580,14 @@ public final class ClassFileAttributes {
|
||||
Label[] labels)
|
||||
{
|
||||
|
||||
String osName = null;
|
||||
String osArch = null;
|
||||
String targetPlatform = null;
|
||||
|
||||
int name_index = cr.readUnsignedShort(off);
|
||||
if (name_index != 0)
|
||||
osName = cr.readUTF8(off, buf);
|
||||
int target_platform_index = cr.readUnsignedShort(off);
|
||||
if (target_platform_index != 0)
|
||||
targetPlatform = cr.readUTF8(off, buf);
|
||||
off += 2;
|
||||
|
||||
int arch_index = cr.readUnsignedShort(off);
|
||||
if (arch_index != 0)
|
||||
osArch = cr.readUTF8(off, buf);
|
||||
off += 2;
|
||||
|
||||
return new ModuleTargetAttribute(osName, osArch);
|
||||
return new ModuleTargetAttribute(targetPlatform);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -613,15 +599,10 @@ public final class ClassFileAttributes {
|
||||
{
|
||||
ByteVector attr = new ByteVector();
|
||||
|
||||
int name_index = 0;
|
||||
if (osName != null && osName.length() > 0)
|
||||
name_index = cw.newUTF8(osName);
|
||||
attr.putShort(name_index);
|
||||
|
||||
int arch_index = 0;
|
||||
if (osArch != null && osArch.length() > 0)
|
||||
arch_index = cw.newUTF8(osArch);
|
||||
attr.putShort(arch_index);
|
||||
int target_platform_index = 0;
|
||||
if (targetPlatform != null && targetPlatform.length() > 0)
|
||||
target_platform_index = cw.newUTF8(targetPlatform);
|
||||
attr.putShort(target_platform_index);
|
||||
|
||||
return attr;
|
||||
}
|
||||
|
@ -84,8 +84,9 @@ public final class ModuleBootstrap {
|
||||
// The ModulePatcher for the initial configuration
|
||||
private static final ModulePatcher patcher = initModulePatcher();
|
||||
|
||||
// ModuleFinder for the initial configuration
|
||||
private static ModuleFinder initialFinder;
|
||||
// ModuleFinders for the initial configuration
|
||||
private static ModuleFinder unlimitedFinder;
|
||||
private static ModuleFinder limitedFinder;
|
||||
|
||||
/**
|
||||
* 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() {
|
||||
assert initialFinder != null;
|
||||
return initialFinder;
|
||||
public static ModuleFinder unlimitedFinder() {
|
||||
assert unlimitedFinder != null;
|
||||
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);
|
||||
|
||||
// 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();
|
||||
|
||||
@ -180,7 +195,8 @@ public final class ModuleBootstrap {
|
||||
}
|
||||
|
||||
// --limit-modules
|
||||
String propValue = getAndRemoveProperty("jdk.module.limitmods");
|
||||
unlimitedFinder = finder;
|
||||
propValue = getAndRemoveProperty("jdk.module.limitmods");
|
||||
if (propValue != null) {
|
||||
Set<String> mods = new HashSet<>();
|
||||
for (String mod: propValue.split(",")) {
|
||||
@ -188,6 +204,7 @@ public final class ModuleBootstrap {
|
||||
}
|
||||
finder = limitFinder(finder, mods, roots);
|
||||
}
|
||||
limitedFinder = finder;
|
||||
|
||||
// If there is no initial module specified then assume that the initial
|
||||
// module is the unnamed module of the application class loader. This
|
||||
@ -267,7 +284,8 @@ public final class ModuleBootstrap {
|
||||
}
|
||||
|
||||
PrintStream traceOutput = null;
|
||||
if (Boolean.getBoolean("jdk.launcher.traceResolver"))
|
||||
propValue = getAndRemoveProperty("jdk.module.showModuleResolution");
|
||||
if (propValue != null && Boolean.parseBoolean(propValue))
|
||||
traceOutput = System.out;
|
||||
|
||||
// run the resolver to create the configuration
|
||||
@ -362,12 +380,23 @@ public final class ModuleBootstrap {
|
||||
// total time to initialize
|
||||
PerfCounters.bootstrapTime.addElapsedTimeFrom(t0);
|
||||
|
||||
// remember the ModuleFinder
|
||||
initialFinder = finder;
|
||||
|
||||
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
|
||||
* 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> {
|
||||
private final Set<T> nodes;
|
||||
|
@ -546,21 +546,15 @@ public final class ModuleInfo {
|
||||
private ModuleTarget readModuleTargetAttribute(DataInput in, ConstantPool cpool)
|
||||
throws IOException
|
||||
{
|
||||
String osName = null;
|
||||
String osArch = null;
|
||||
String targetPlatform = null;
|
||||
|
||||
int name_index = in.readUnsignedShort();
|
||||
if (name_index != 0)
|
||||
osName = cpool.getUtf8(name_index);
|
||||
int index = in.readUnsignedShort();
|
||||
if (index != 0)
|
||||
targetPlatform = cpool.getUtf8(index);
|
||||
|
||||
int arch_index = in.readUnsignedShort();
|
||||
if (arch_index != 0)
|
||||
osArch = cpool.getUtf8(arch_index);
|
||||
|
||||
return new ModuleTarget(osName, osArch);
|
||||
return new ModuleTarget(targetPlatform);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Reads the ModuleHashes attribute
|
||||
*/
|
||||
@ -612,7 +606,6 @@ public final class ModuleInfo {
|
||||
return new ModuleResolution(flags);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns true if the given attribute can be present at most once
|
||||
* in the class file. Returns false otherwise.
|
||||
|
@ -62,9 +62,8 @@ public final class ModuleInfoExtender {
|
||||
// the value of the ModuleMainClass attribute
|
||||
private String mainClass;
|
||||
|
||||
// the values for the ModuleTarget attribute
|
||||
private String osName;
|
||||
private String osArch;
|
||||
// the value for the ModuleTarget attribute
|
||||
private String targetPlatform;
|
||||
|
||||
// the hashes for the ModuleHashes attribute
|
||||
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) {
|
||||
this.osName = osName;
|
||||
this.osArch = osArch;
|
||||
public ModuleInfoExtender targetPlatform(String targetPlatform) {
|
||||
this.targetPlatform = targetPlatform;
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -199,8 +197,8 @@ public final class ModuleInfoExtender {
|
||||
cv.addAttribute(new ModulePackagesAttribute(packages));
|
||||
if (mainClass != null)
|
||||
cv.addAttribute(new ModuleMainClassAttribute(mainClass));
|
||||
if (osName != null || osArch != null)
|
||||
cv.addAttribute(new ModuleTargetAttribute(osName, osArch));
|
||||
if (targetPlatform != null)
|
||||
cv.addAttribute(new ModuleTargetAttribute(targetPlatform));
|
||||
if (hashes != null)
|
||||
cv.addAttribute(new ModuleHashesAttribute(hashes));
|
||||
if (moduleResolution != null)
|
||||
|
@ -66,10 +66,9 @@ public final class ModuleInfoWriter {
|
||||
// write ModuleMainClass if the module has a main class
|
||||
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) {
|
||||
cw.visitAttribute(new ModuleTargetAttribute(target.osName(),
|
||||
target.osArch()));
|
||||
cw.visitAttribute(new ModuleTargetAttribute(target.targetPlatform()));
|
||||
}
|
||||
|
||||
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
|
||||
* are generated at build time.
|
||||
* Supports the mapping of modules to class loaders. The set of modules mapped
|
||||
* 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
|
||||
* built-in class loaders.
|
||||
*/
|
||||
static Function<String, ClassLoader> mappingFunction(Configuration cf) {
|
||||
|
||||
// The list of boot modules and platform modules are generated at build time.
|
||||
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);
|
||||
}
|
||||
Set<String> bootModules = bootModules();
|
||||
Set<String> platformModules = platformModules();
|
||||
|
||||
ClassLoader platformClassLoader = ClassLoaders.platformClassLoader();
|
||||
ClassLoader appClassLoader = ClassLoaders.appClassLoader();
|
||||
|
||||
Map<String, ClassLoader> map = new HashMap<>();
|
||||
|
||||
for (ResolvedModule resolvedModule : cf.modules()) {
|
||||
String mn = resolvedModule.name();
|
||||
if (!bootModules.contains(mn)) {
|
||||
@ -77,12 +107,6 @@ final class ModuleLoaderMap {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return new Function<String, ClassLoader> () {
|
||||
@Override
|
||||
public ClassLoader apply(String mn) {
|
||||
return map.get(mn);
|
||||
}
|
||||
};
|
||||
return new Mapper(map);
|
||||
}
|
||||
}
|
||||
|
@ -120,7 +120,7 @@ public final class ModulePatcher {
|
||||
|
||||
// JAR file - do not open as a multi-release JAR as this
|
||||
// is not supported by the boot class loader
|
||||
try (JarFile jf = new JarFile(file.toFile())) {
|
||||
try (JarFile jf = new JarFile(file.toString())) {
|
||||
jf.stream()
|
||||
.filter(e -> !e.isDirectory()
|
||||
&& (!isAutomatic || e.getName().endsWith(".class")))
|
||||
@ -431,7 +431,7 @@ public final class ModulePatcher {
|
||||
private final URL csURL;
|
||||
|
||||
JarResourceFinder(Path path) throws IOException {
|
||||
this.jf = new JarFile(path.toFile());
|
||||
this.jf = new JarFile(path.toString());
|
||||
this.csURL = path.toUri().toURL();
|
||||
}
|
||||
|
||||
@ -505,7 +505,7 @@ public final class ModulePatcher {
|
||||
public Resource find(String name) throws IOException {
|
||||
Path file = Resources.toFilePath(dir, name);
|
||||
if (file != null) {
|
||||
return newResource(name, dir, file);
|
||||
return newResource(name, dir, file);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
|
@ -59,6 +59,7 @@ import java.util.jar.Manifest;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.zip.ZipException;
|
||||
import java.util.zip.ZipFile;
|
||||
|
||||
import jdk.internal.jmod.JmodFile;
|
||||
@ -315,26 +316,42 @@ public class ModulePath implements ModuleFinder {
|
||||
{
|
||||
try {
|
||||
|
||||
// exploded module
|
||||
if (attrs.isDirectory()) {
|
||||
return readExplodedModule(entry); // may return null
|
||||
} else {
|
||||
}
|
||||
|
||||
// JAR or JMOD file
|
||||
if (attrs.isRegularFile()) {
|
||||
String fn = entry.getFileName().toString();
|
||||
if (attrs.isRegularFile()) {
|
||||
if (fn.endsWith(".jar")) {
|
||||
boolean isDefaultFileSystem = isDefaultFileSystem(entry);
|
||||
|
||||
// JAR file
|
||||
if (fn.endsWith(".jar")) {
|
||||
if (isDefaultFileSystem) {
|
||||
return readJar(entry);
|
||||
} else if (isLinkPhase && fn.endsWith(".jmod")) {
|
||||
return readJMod(entry);
|
||||
} else {
|
||||
// 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) {
|
||||
throw new FindException("Error reading module: " + entry, e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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
|
||||
@ -434,7 +451,7 @@ public class ModulePath implements ModuleFinder {
|
||||
* 3. The contents of any META-INF/services configuration files are mapped
|
||||
* to "provides" declarations
|
||||
* 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)
|
||||
throws IOException
|
||||
@ -530,12 +547,12 @@ public class ModulePath implements ModuleFinder {
|
||||
String mainClass = attrs.getValue(Attributes.Name.MAIN_CLASS);
|
||||
if (mainClass != null) {
|
||||
mainClass = mainClass.replace("/", ".");
|
||||
String pn = packageName(mainClass);
|
||||
if (!packages.contains(pn)) {
|
||||
String msg = "Main-Class " + mainClass + " not in module";
|
||||
throw new InvalidModuleDescriptorException(msg);
|
||||
if (Checks.isClassName(mainClass)) {
|
||||
String pn = packageName(mainClass);
|
||||
if (packages.contains(pn)) {
|
||||
builder.mainClass(mainClass);
|
||||
}
|
||||
}
|
||||
builder.mainClass(mainClass);
|
||||
}
|
||||
}
|
||||
|
||||
@ -617,6 +634,8 @@ public class ModulePath implements ModuleFinder {
|
||||
}
|
||||
|
||||
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
|
||||
= PerfCounter.newPerfCounter("jdk.module.finder.modulepath.scanTime");
|
||||
private static final PerfCounter moduleCount
|
||||
|
@ -25,6 +25,7 @@
|
||||
|
||||
package jdk.internal.module;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOError;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
@ -226,8 +227,8 @@ class ModuleReferences {
|
||||
|
||||
static JarFile newJarFile(Path path) {
|
||||
try {
|
||||
return new JarFile(path.toFile(),
|
||||
true, // verify
|
||||
return new JarFile(new File(path.toString()),
|
||||
true, // verify
|
||||
ZipFile.OPEN_READ,
|
||||
JarFile.runtimeVersion());
|
||||
} catch (IOException ioe) {
|
||||
|
@ -39,6 +39,10 @@ public final class ModuleResolution {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public int value() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public static ModuleResolution empty() {
|
||||
return new ModuleResolution(0);
|
||||
}
|
||||
@ -74,35 +78,30 @@ public final class ModuleResolution {
|
||||
throw new InternalError("cannot add deprecated for removal to " + value);
|
||||
return new ModuleResolution(value | WARN_DEPRECATED_FOR_REMOVAL);
|
||||
}
|
||||
|
||||
public ModuleResolution withIncubating() {
|
||||
if ((value & (WARN_DEPRECATED | WARN_DEPRECATED_FOR_REMOVAL)) != 0)
|
||||
throw new InternalError("cannot add incubating to " + value);
|
||||
return new ModuleResolution(value | WARN_INCUBATING);
|
||||
}
|
||||
|
||||
public int value() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public static boolean doNotResolveByDefault(ModuleReference mref) {
|
||||
// get the DO_NOT_RESOLVE_BY_DEFAULT flag, if any
|
||||
if (!(mref instanceof ModuleReferenceImpl))
|
||||
return false;
|
||||
|
||||
ModuleResolution mres = ((ModuleReferenceImpl)mref).moduleResolution();
|
||||
if (mres != null)
|
||||
return mres.doNotResolveByDefault();
|
||||
if (mref instanceof ModuleReferenceImpl) {
|
||||
ModuleResolution mres = ((ModuleReferenceImpl) mref).moduleResolution();
|
||||
if (mres != null)
|
||||
return mres.doNotResolveByDefault();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean hasIncubatingWarning(ModuleReference mref) {
|
||||
if (!(mref instanceof ModuleReferenceImpl))
|
||||
return false;
|
||||
|
||||
ModuleResolution mres = ((ModuleReferenceImpl)mref).moduleResolution();
|
||||
if (mres != null)
|
||||
return mres.hasIncubatingWarning();
|
||||
if (mref instanceof ModuleReferenceImpl) {
|
||||
ModuleResolution mres = ((ModuleReferenceImpl) mref).moduleResolution();
|
||||
if (mres != null)
|
||||
return mres.hasIncubatingWarning();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
@ -25,22 +25,21 @@
|
||||
|
||||
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 {
|
||||
|
||||
private final String osName;
|
||||
private final String osArch;
|
||||
private final String targetPlatform;
|
||||
|
||||
public ModuleTarget(String osName, String osArch) {
|
||||
this.osName = osName;
|
||||
this.osArch = osArch;
|
||||
public ModuleTarget(String targetPlatform) {
|
||||
this.targetPlatform = targetPlatform;
|
||||
}
|
||||
|
||||
public String osName() {
|
||||
return osName;
|
||||
}
|
||||
|
||||
public String osArch() {
|
||||
return osArch;
|
||||
public String targetPlatform() {
|
||||
return targetPlatform;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -25,12 +25,22 @@
|
||||
|
||||
package jdk.internal.module;
|
||||
|
||||
import java.lang.module.Configuration;
|
||||
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.security.AccessController;
|
||||
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.BuiltinClassLoader;
|
||||
import jdk.internal.loader.ClassLoaders;
|
||||
import jdk.internal.misc.JavaLangAccess;
|
||||
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
|
||||
* 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
|
||||
* need to link to supporting classes.
|
||||
* used by the VM to load modules or add read edges when agents are instrumenting
|
||||
* code that need to link to supporting classes.
|
||||
*
|
||||
* 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™
|
||||
@ -154,4 +164,90 @@ public class Modules {
|
||||
addReads(m, BootLoader.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.IOException;
|
||||
import java.nio.file.FileSystem;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.NoSuchFileException;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.nio.file.attribute.BasicFileAttributes;
|
||||
|
||||
/**
|
||||
@ -94,7 +94,7 @@ public final class Resources {
|
||||
if (expectDirectory) {
|
||||
name = name.substring(0, name.length() - 1); // drop trailing "/"
|
||||
}
|
||||
Path path = toSafeFilePath(name);
|
||||
Path path = toSafeFilePath(dir.getFileSystem(), name);
|
||||
if (path != null) {
|
||||
Path file = dir.resolve(path);
|
||||
try {
|
||||
@ -116,7 +116,7 @@ public final class Resources {
|
||||
* are rejected, as are resource names that translates to a file path
|
||||
* with a root component.
|
||||
*/
|
||||
private static Path toSafeFilePath(String name) {
|
||||
private static Path toSafeFilePath(FileSystem fs, String name) {
|
||||
// scan elements of resource name
|
||||
int next;
|
||||
int off = 0;
|
||||
@ -135,12 +135,12 @@ public final class Resources {
|
||||
// convert to file path
|
||||
Path path;
|
||||
if (File.separatorChar == '/') {
|
||||
path = Paths.get(name);
|
||||
path = fs.getPath(name);
|
||||
} else {
|
||||
// not allowed to embed file separators
|
||||
if (name.contains(File.separator))
|
||||
return null;
|
||||
path = Paths.get(name.replace('/', File.separatorChar));
|
||||
path = fs.getPath(name.replace('/', File.separatorChar));
|
||||
}
|
||||
|
||||
// file path not allowed to have root component
|
||||
|
@ -161,6 +161,7 @@ module java.base {
|
||||
java.security.jgss,
|
||||
java.sql,
|
||||
java.xml,
|
||||
jdk.attach,
|
||||
jdk.charsets,
|
||||
jdk.compiler, // reflective dependency
|
||||
jdk.incubator.httpclient,
|
||||
|
@ -43,13 +43,17 @@ import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintStream;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.lang.module.ModuleFinder;
|
||||
import java.lang.module.ModuleReference;
|
||||
import java.lang.module.Configuration;
|
||||
import java.lang.module.FindException;
|
||||
import java.lang.module.ModuleDescriptor;
|
||||
import java.lang.module.ModuleDescriptor.Requires;
|
||||
import java.lang.module.ModuleDescriptor.Exports;
|
||||
import java.lang.module.ModuleDescriptor.Opens;
|
||||
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.Modifier;
|
||||
import java.math.BigDecimal;
|
||||
@ -58,14 +62,16 @@ import java.net.URI;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.file.DirectoryStream;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.NoSuchFileException;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.nio.file.attribute.BasicFileAttributes;
|
||||
import java.text.Normalizer;
|
||||
import java.text.MessageFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashSet;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
@ -83,6 +89,7 @@ import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import jdk.internal.misc.VM;
|
||||
import jdk.internal.module.ModuleBootstrap;
|
||||
import jdk.internal.module.Modules;
|
||||
|
||||
|
||||
@ -98,6 +105,7 @@ public final class LauncherHelper {
|
||||
"javafx.application.Application";
|
||||
private static final String JAVAFX_FXHELPER_CLASS_NAME_SUFFIX =
|
||||
"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 ADD_EXPORTS = "Add-Exports";
|
||||
private static final String ADD_OPENS = "Add-Opens";
|
||||
@ -408,8 +416,12 @@ public final class LauncherHelper {
|
||||
ostream = (printToStderr) ? System.err : System.out;
|
||||
}
|
||||
|
||||
static void initOutput(PrintStream ps) {
|
||||
ostream = ps;
|
||||
}
|
||||
|
||||
static String getMainClassFromJar(String jarname) {
|
||||
String mainValue = null;
|
||||
String mainValue;
|
||||
try (JarFile jarFile = new JarFile(jarname)) {
|
||||
Manifest manifest = jarFile.getManifest();
|
||||
if (manifest == null) {
|
||||
@ -426,6 +438,22 @@ public final class LauncherHelper {
|
||||
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
|
||||
String exports = mainAttrs.getValue(ADD_EXPORTS);
|
||||
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.
|
||||
* 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)
|
||||
throws IOException, ClassNotFoundException
|
||||
{
|
||||
initOutput(printToStderr);
|
||||
static void listModules() {
|
||||
initOutput(System.out);
|
||||
|
||||
ModuleFinder finder = jdk.internal.module.ModuleBootstrap.finder();
|
||||
int colon = optionFlag.indexOf('=');
|
||||
if (colon == -1) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
ModuleBootstrap.limitedFinder().findAll().stream()
|
||||
.sorted(new JrtFirstComparator())
|
||||
.forEach(LauncherHelper::showModule);
|
||||
}
|
||||
|
||||
/**
|
||||
* Describes the given module.
|
||||
* Called by the launcher to show the resolved modules
|
||||
*/
|
||||
static void describeModule(ModuleFinder finder,
|
||||
ModuleReference mref,
|
||||
boolean verbose)
|
||||
{
|
||||
ModuleDescriptor md = mref.descriptor();
|
||||
ostream.print("module " + midAndLocation(md, mref.location()));
|
||||
if (md.isAutomatic())
|
||||
ostream.print(" automatic");
|
||||
ostream.println();
|
||||
static void showResolvedModules() {
|
||||
initOutput(System.out);
|
||||
|
||||
if (!verbose)
|
||||
return;
|
||||
ModuleLayer bootLayer = ModuleLayer.boot();
|
||||
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)
|
||||
Set<Exports> exports = new TreeSet<>(Comparator.comparing(Exports::source));
|
||||
md.exports().stream().filter(e -> !e.isQualified()).forEach(exports::add);
|
||||
for (Exports e : exports) {
|
||||
String modsAndSource = Stream.concat(toStringStream(e.modifiers()),
|
||||
Stream.of(e.source()))
|
||||
md.exports().stream()
|
||||
.filter(e -> !e.isQualified())
|
||||
.sorted(Comparator.comparing(Exports::source))
|
||||
.map(e -> Stream.concat(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(" "));
|
||||
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()) {
|
||||
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);
|
||||
}
|
||||
// service use and provides
|
||||
for (String s : md.uses()) {
|
||||
ostream.format(" uses %s%n", s);
|
||||
ostream.format("uses %s%n", s);
|
||||
}
|
||||
|
||||
for (Provides ps : md.provides()) {
|
||||
ostream.format(" provides %s with %s%n", ps.service(),
|
||||
ps.providers().stream().collect(Collectors.joining(", ")));
|
||||
String names = ps.providers().stream().collect(Collectors.joining(" "));
|
||||
ostream.format("provides %s with %s%n", ps.service(), names);
|
||||
|
||||
}
|
||||
|
||||
// qualified exports
|
||||
for (Exports e : md.exports()) {
|
||||
if (e.isQualified()) {
|
||||
String modsAndSource = Stream.concat(toStringStream(e.modifiers()),
|
||||
Stream.of(e.source()))
|
||||
.collect(Collectors.joining(" "));
|
||||
ostream.format(" exports %s", modsAndSource);
|
||||
formatCommaList(ostream, " to", e.targets());
|
||||
String who = e.targets().stream().collect(Collectors.joining(" "));
|
||||
ostream.format("qualified exports %s to %s%n", e.source(), who);
|
||||
}
|
||||
}
|
||||
|
||||
// open packages
|
||||
for (Opens obj: md.opens()) {
|
||||
String modsAndSource = Stream.concat(toStringStream(obj.modifiers()),
|
||||
Stream.of(obj.source()))
|
||||
for (Opens opens: md.opens()) {
|
||||
if (opens.isQualified())
|
||||
ostream.print("qualified ");
|
||||
String sourceAndMods = Stream.concat(Stream.of(opens.source()),
|
||||
toStringStream(opens.modifiers()))
|
||||
.collect(Collectors.joining(" "));
|
||||
ostream.format(" opens %s", modsAndSource);
|
||||
if (obj.isQualified())
|
||||
formatCommaList(ostream, " to", obj.targets());
|
||||
else
|
||||
ostream.println();
|
||||
ostream.format("opens %s", sourceAndMods);
|
||||
if (opens.isQualified()) {
|
||||
String who = opens.targets().stream().collect(Collectors.joining(" "));
|
||||
ostream.format(" to %s", who);
|
||||
}
|
||||
ostream.println();
|
||||
}
|
||||
|
||||
// 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 -> 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());
|
||||
}
|
||||
|
||||
static String midAndLocation(ModuleDescriptor md, Optional<URI> location ) {
|
||||
URI loc = location.orElse(null);
|
||||
if (loc == null || loc.getScheme().equalsIgnoreCase("jrt"))
|
||||
return md.toNameAndVersion();
|
||||
else
|
||||
return md.toNameAndVersion() + " (" + loc + ")";
|
||||
private static boolean isJrt(ModuleReference mref) {
|
||||
return isJrt(mref.location().orElse(null));
|
||||
}
|
||||
|
||||
private static boolean isJrt(URI uri) {
|
||||
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\
|
||||
\ is a directory of modules that replace upgradeable\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\
|
||||
\ <modulename> can also be ALL-DEFAULT, ALL-SYSTEM,\n\
|
||||
\ <module name> can also be ALL-DEFAULT, ALL-SYSTEM,\n\
|
||||
\ ALL-MODULE-PATH.\n\
|
||||
\ --limit-modules <modulename>[,<modulename>...]\n\
|
||||
\ limit the universe of observable modules\n\
|
||||
\ --list-modules [<modulename>[,<modulename>...]]\n\
|
||||
\ list the observable modules and exit\n\
|
||||
\ --dry-run create VM but do not execute main method.\n\
|
||||
\ This --dry-run option may be useful for validating the\n\
|
||||
\ --list-modules\n\
|
||||
\ list observable modules and exit\n\
|
||||
\ --d <module name>\n\
|
||||
\ --describe-module <module name>\n\
|
||||
\ describe a module and exit\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\
|
||||
\ --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\
|
||||
\ set a system property\n\
|
||||
\ -verbose:[class|gc|jni]\n\
|
||||
\ -verbose:[class|module|gc|jni]\n\
|
||||
\ enable verbose output\n\
|
||||
\ -version print product version to the error 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\
|
||||
\ --show-version\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\
|
||||
\ print this help message to the error 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\
|
||||
\ -Xdebug provided for backward compatibility\n\
|
||||
\ -Xdiag show additional diagnostic messages\n\
|
||||
\ -Xdiag:resolver show resolver diagnostic messages\n\
|
||||
\ -Xfuture enable strictest checks, anticipating future default\n\
|
||||
\ -Xint interpreted mode execution only\n\
|
||||
\ -Xinternalversion\n\
|
||||
@ -164,10 +170,12 @@ java.launcher.X.usage=\n\
|
||||
\ permit illegal access to members of types in named modules\n\
|
||||
\ by code in unnamed modules. This compatibility option will\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\
|
||||
\ Override or augment a module with classes and resources\n\
|
||||
\ in JAR files or directories.\n\n\
|
||||
\ override or augment a module with classes and resources\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
|
||||
|
||||
# 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}
|
||||
java.launcher.jar.error2=manifest not found 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.javafx.error1=\
|
||||
Error: The JavaFX launchApplication method has the wrong signature, it\n\
|
||||
@ -215,4 +224,5 @@ java.launcher.module.error2=\
|
||||
java.launcher.module.error3=\
|
||||
Error: Unable to load main class {0} from module {1}\n\
|
||||
\t{2}
|
||||
|
||||
java.launcher.module.error4=\
|
||||
{0} not found
|
||||
|
@ -43,13 +43,14 @@
|
||||
#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_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_ERROR7 "Error: %s can only be specified once"
|
||||
#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_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_ERROR12 "Error: %s requires module name"
|
||||
|
||||
#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
|
||||
|
@ -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.
|
||||
*
|
||||
* 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 dryRun = JNI_FALSE; /* initialize VM and exit */
|
||||
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 *_launcher_name;
|
||||
@ -118,7 +121,10 @@ static void SetApplicationClassPath(const char**);
|
||||
static void PrintJavaVersion(JNIEnv *env, jboolean extraLF);
|
||||
static void PrintUsage(JNIEnv* env, jboolean doXUsage);
|
||||
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);
|
||||
|
||||
@ -409,9 +415,31 @@ JavaMain(void * _args)
|
||||
CHECK_EXCEPTION_LEAVE(1);
|
||||
}
|
||||
|
||||
if (listModules != NULL) {
|
||||
ListModules(env, listModules);
|
||||
// show resolved modules and continue
|
||||
if (showResolvedModules) {
|
||||
ShowResolvedModules(env);
|
||||
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();
|
||||
}
|
||||
|
||||
@ -552,7 +580,8 @@ static jboolean
|
||||
IsLauncherOption(const char* name) {
|
||||
return IsClassPathOption(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) {
|
||||
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, "--class-path=") == 0) {
|
||||
kind = LAUNCHER_OPTION_WITH_ARGUMENT;
|
||||
@ -1263,18 +1292,18 @@ ParseArguments(int *pargc, char ***pargv,
|
||||
REPORT_ERROR (has_arg_any_len, ARG_ERROR1, arg);
|
||||
SetClassPath(value);
|
||||
mode = LM_CLASS;
|
||||
} else if (JLI_StrCmp(arg, "--list-modules") == 0 ||
|
||||
JLI_StrCCmp(arg, "--list-modules=") == 0) {
|
||||
listModules = arg;
|
||||
|
||||
// set listModules to --list-modules=<module-names> if argument is specified
|
||||
if (JLI_StrCmp(arg, "--list-modules") == 0 && has_arg) {
|
||||
static const char format[] = "%s=%s";
|
||||
size_t buflen = JLI_StrLen(option) + 2 + JLI_StrLen(value);
|
||||
listModules = JLI_MemAlloc(buflen);
|
||||
JLI_Snprintf(listModules, buflen, format, option, value);
|
||||
}
|
||||
return JNI_TRUE;
|
||||
} else if (JLI_StrCmp(arg, "--list-modules") == 0) {
|
||||
listModules = JNI_TRUE;
|
||||
} else if (JLI_StrCmp(arg, "--show-resolved-modules") == 0) {
|
||||
showResolvedModules = JNI_TRUE;
|
||||
} else if (JLI_StrCmp(arg, "--validate-modules") == 0) {
|
||||
AddOption("-Djdk.module.minimumBoot=true", NULL);
|
||||
validateModules = JNI_TRUE;
|
||||
} else if (JLI_StrCmp(arg, "--describe-module") == 0 ||
|
||||
JLI_StrCCmp(arg, "--describe-module=") == 0 ||
|
||||
JLI_StrCmp(arg, "-d") == 0) {
|
||||
REPORT_ERROR (has_arg_any_len, ARG_ERROR12, arg);
|
||||
describeModule = value;
|
||||
/*
|
||||
* Parse white-space options
|
||||
*/
|
||||
@ -1336,9 +1365,8 @@ ParseArguments(int *pargc, char ***pargv,
|
||||
showSettings = arg;
|
||||
} else if (JLI_StrCmp(arg, "-Xdiag") == 0) {
|
||||
AddOption("-Dsun.java.launcher.diag=true", NULL);
|
||||
AddOption("-Djdk.launcher.traceResolver=true", NULL);
|
||||
} else if (JLI_StrCmp(arg, "-Xdiag:resolver") == 0) {
|
||||
AddOption("-Djdk.launcher.traceResolver=true", NULL);
|
||||
} else if (JLI_StrCmp(arg, "--show-module-resolution") == 0) {
|
||||
AddOption("-Djdk.module.showModuleResolution=true", NULL);
|
||||
/*
|
||||
* The following case provide backward compatibility with old-style
|
||||
* command line options.
|
||||
@ -1399,7 +1427,10 @@ ParseArguments(int *pargc, char ***pargv,
|
||||
}
|
||||
|
||||
if (*pwhat == NULL) {
|
||||
*pret = 1;
|
||||
/* LM_UNKNOWN okay for options that exit */
|
||||
if (!listModules && !describeModule && !validateModules) {
|
||||
*pret = 1;
|
||||
}
|
||||
} else if (mode == LM_UNKNOWN) {
|
||||
/* default to LM_CLASS if -m, -jar and -cp options are
|
||||
* not specified */
|
||||
@ -1828,21 +1859,61 @@ ShowSettings(JNIEnv *env, char *optString)
|
||||
}
|
||||
|
||||
/**
|
||||
* List modules supported by the runtime
|
||||
* Show resolved modules
|
||||
*/
|
||||
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;
|
||||
jstring joptString = NULL;
|
||||
jclass cls = GetLauncherHelperClass(env);
|
||||
NULL_CHECK(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));
|
||||
(*env)->CallStaticVoidMethod(env, cls, listModulesID,
|
||||
USE_STDOUT,
|
||||
joptString);
|
||||
(*env)->CallStaticVoidMethod(env, cls, describeModuleID, 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
|
||||
* redefineModule}. If a module is 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
|
||||
* @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.
|
||||
|
||||
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
|
||||
rules as the application <code>main</code> method.
|
||||
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>
|
||||
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.
|
||||
|
||||
|
||||
|
||||
<h3>Starting Agents After VM Startup</h3>
|
||||
|
||||
<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.
|
||||
|
||||
|
||||
<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>
|
||||
|
||||
The following manifest attributes are defined for an agent JAR file:
|
||||
<blockquote>
|
||||
<dl>
|
||||
<dt><code>Premain-Class</code></dt>
|
||||
<dd>
|
||||
When an agent is specified at JVM launch time this attribute
|
||||
specifies the agent class.
|
||||
That is, the class containing the <code>premain</code> method.
|
||||
When an agent is specified at JVM launch time this attribute
|
||||
is required. If the attribute is not present the JVM will abort.
|
||||
Note: this is a class name, not a file name or path.
|
||||
When an agent is specified at JVM launch time this attribute
|
||||
specifies the agent class.
|
||||
That is, the class containing the <code>premain</code> method.
|
||||
When an agent is specified at JVM launch time this attribute
|
||||
is required. If the attribute is not present the JVM will abort.
|
||||
Note: this is a class name, not a file name or path.
|
||||
</dd>
|
||||
|
||||
<dt><code>Agent-Class</code></dt>
|
||||
<dd>
|
||||
If an implementation supports a mechanism to start agents
|
||||
sometime after the VM has started then this attribute specifies
|
||||
the agent class.
|
||||
That is, the class containing the <code>agentmain</code> method.
|
||||
This attribute is required, if it is not present the agent
|
||||
will not be started.
|
||||
Note: this is a class name, not a file name or path.
|
||||
</dd>
|
||||
|
||||
If an implementation supports a mechanism to start agents
|
||||
sometime after the VM has started then this attribute specifies
|
||||
the agent class.
|
||||
That is, the class containing the <code>agentmain</code> method.
|
||||
This attribute is required, if it is not present the agent
|
||||
will not be started.
|
||||
Note: this is a class name, not a file name or path.
|
||||
</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>
|
||||
<dd>
|
||||
A list of paths to be searched by the bootstrap class
|
||||
loader. Paths represent directories or libraries
|
||||
(commonly referred to as JAR or zip libraries on
|
||||
many platforms).
|
||||
These paths are searched by the
|
||||
bootstrap class loader after the platform specific
|
||||
mechanisms of locating a class have failed.
|
||||
Paths are searched in the order listed.
|
||||
Paths in the list are separated by one or more spaces.
|
||||
A path takes the syntax of the path component of a
|
||||
hierarchical URI. The path is
|
||||
absolute if it begins with a slash character ('/'),
|
||||
otherwise it is relative. A relative path is resolved
|
||||
against the absolute path of the agent JAR file.
|
||||
Malformed and non-existent paths are ignored.
|
||||
When an agent is started sometime after the VM has
|
||||
started then paths that do not represent a JAR file
|
||||
are ignored.
|
||||
This attribute is optional.
|
||||
A list of paths to be searched by the bootstrap class
|
||||
loader. Paths represent directories or libraries
|
||||
(commonly referred to as JAR or zip libraries on
|
||||
many platforms).
|
||||
These paths are searched by the
|
||||
bootstrap class loader after the platform specific
|
||||
mechanisms of locating a class have failed.
|
||||
Paths are searched in the order listed.
|
||||
Paths in the list are separated by one or more spaces.
|
||||
A path takes the syntax of the path component of a
|
||||
hierarchical URI. The path is
|
||||
absolute if it begins with a slash character ('/'),
|
||||
otherwise it is relative. A relative path is resolved
|
||||
against the absolute path of the agent JAR file.
|
||||
Malformed and non-existent paths are ignored.
|
||||
When an agent is started sometime after the VM has
|
||||
started then paths that do not represent a JAR file
|
||||
are ignored.
|
||||
This attribute is optional.
|
||||
</dd>
|
||||
<dt><code>Can-Redefine-Classes</code></dt>
|
||||
<dd>
|
||||
Boolean (<code>true</code> or <code>false</code>, case irrelevant).
|
||||
Is the ability to redefine classes
|
||||
needed by this agent.
|
||||
Values other than <code>true</code> are considered <code>false</code>.
|
||||
This attribute is optional, the default is <code>false</code>.
|
||||
Boolean (<code>true</code> or <code>false</code>, case irrelevant).
|
||||
Is the ability to redefine classes
|
||||
needed by this agent.
|
||||
Values other than <code>true</code> are considered <code>false</code>.
|
||||
This attribute is optional, the default is <code>false</code>.
|
||||
</dd>
|
||||
<dt><code>Can-Retransform-Classes</code></dt>
|
||||
<dd>
|
||||
Boolean (<code>true</code> or <code>false</code>, case irrelevant).
|
||||
Is the ability to retransform classes
|
||||
needed by this agent.
|
||||
Values other than <code>true</code> are considered <code>false</code>.
|
||||
This attribute is optional, the default is <code>false</code>.
|
||||
Boolean (<code>true</code> or <code>false</code>, case irrelevant).
|
||||
Is the ability to retransform classes
|
||||
needed by this agent.
|
||||
Values other than <code>true</code> are considered <code>false</code>.
|
||||
This attribute is optional, the default is <code>false</code>.
|
||||
</dd>
|
||||
<dt><code>Can-Set-Native-Method-Prefix</code></dt>
|
||||
<dd>
|
||||
Boolean (<code>true</code> or <code>false</code>, case irrelevant).
|
||||
Is the ability to set native method prefix needed by this agent.
|
||||
Values other than <code>true</code> are considered <code>false</code>.
|
||||
This attribute is optional, the default is <code>false</code>.
|
||||
Boolean (<code>true</code> or <code>false</code>, case irrelevant).
|
||||
Is the ability to set native method prefix needed by this agent.
|
||||
Values other than <code>true</code> are considered <code>false</code>.
|
||||
This attribute is optional, the default is <code>false</code>.
|
||||
</dd>
|
||||
</dl>
|
||||
</blockquote>
|
||||
|
@ -32,5 +32,8 @@
|
||||
*/
|
||||
module java.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.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -555,4 +555,15 @@ public class InstrumentationImpl implements Instrumentation {
|
||||
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) {
|
||||
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.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
void
|
||||
convertCapabilityAtrributes(const jarAttribute* attributes, JPLISAgent* agent) {
|
||||
convertCapabilityAttributes(const jarAttribute* attributes, JPLISAgent* agent) {
|
||||
/* set redefineClasses capability */
|
||||
if (getBooleanAttribute(attributes, "Can-Redefine-Classes")) {
|
||||
addRedefineClassesCapability(agent);
|
||||
@ -229,7 +229,7 @@ DEF_Agent_OnLoad(JavaVM *vm, char *tail, void * reserved) {
|
||||
/*
|
||||
* Convert JAR attributes into agent capabilities
|
||||
*/
|
||||
convertCapabilityAtrributes(attributes, agent);
|
||||
convertCapabilityAttributes(attributes, agent);
|
||||
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
convertCapabilityAtrributes(attributes, agent);
|
||||
convertCapabilityAttributes(attributes, agent);
|
||||
|
||||
/*
|
||||
* Create the java.lang.instrument.Instrumentation instance
|
||||
@ -435,6 +435,109 @@ JNIEXPORT void JNICALL
|
||||
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
|
||||
|
@ -843,6 +843,9 @@ public class ThreadInfo {
|
||||
* @return a {@code ThreadInfo} object represented
|
||||
* by {@code cd} if {@code cd} is not {@code null};
|
||||
* {@code null} otherwise.
|
||||
*
|
||||
* @revised 9
|
||||
* @spec JPMS
|
||||
*/
|
||||
public static ThreadInfo from(CompositeData cd) {
|
||||
if (cd == null) {
|
||||
|
@ -214,13 +214,14 @@ public class VirtualMachineImpl extends HotSpotVirtualMachine {
|
||||
// Special-case the "load" command so that the right exception is
|
||||
// thrown.
|
||||
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 {
|
||||
if (message == null) {
|
||||
throw new AttachOperationFailedException("Command failed in target VM");
|
||||
} else {
|
||||
throw new AttachOperationFailedException(message);
|
||||
}
|
||||
if (message.isEmpty())
|
||||
message = "Command failed in target VM";
|
||||
throw new AttachOperationFailedException(message);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -211,13 +211,14 @@ public class VirtualMachineImpl extends HotSpotVirtualMachine {
|
||||
// Special-case the "load" command so that the right exception is
|
||||
// thrown.
|
||||
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 {
|
||||
if (message == null) {
|
||||
throw new AttachOperationFailedException("Command failed in target VM");
|
||||
} else {
|
||||
throw new AttachOperationFailedException(message);
|
||||
}
|
||||
if (message.isEmpty())
|
||||
message = "Command failed in target VM";
|
||||
throw new AttachOperationFailedException(message);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -213,13 +213,14 @@ public class VirtualMachineImpl extends HotSpotVirtualMachine {
|
||||
// Special-case the "load" command so that the right exception is
|
||||
// thrown.
|
||||
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 {
|
||||
if (message == null) {
|
||||
throw new AttachOperationFailedException("Command failed in target VM");
|
||||
} else {
|
||||
throw new AttachOperationFailedException(message);
|
||||
}
|
||||
if (message.isEmpty())
|
||||
message = "Command failed in target VM";
|
||||
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.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -25,15 +25,19 @@
|
||||
|
||||
package sun.tools.attach;
|
||||
|
||||
import com.sun.tools.attach.AttachNotSupportedException;
|
||||
import com.sun.tools.attach.VirtualMachine;
|
||||
import com.sun.tools.attach.AgentLoadException;
|
||||
import com.sun.tools.attach.AgentInitializationException;
|
||||
import com.sun.tools.attach.spi.AttachProvider;
|
||||
import jdk.internal.misc.VM;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.InputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.util.Properties;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@ -43,8 +47,33 @@ import java.util.stream.Collectors;
|
||||
|
||||
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);
|
||||
|
||||
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 {
|
||||
loadAgentLibrary("instrument", args);
|
||||
} catch (AgentLoadException x) {
|
||||
throw new InternalError("instrument library is missing in target VM", x);
|
||||
} catch (AgentInitializationException x) {
|
||||
/*
|
||||
* Translate interesting errors into the right exception and
|
||||
@ -116,13 +143,17 @@ public abstract class HotSpotVirtualMachine extends VirtualMachine {
|
||||
case JNI_ENOMEM:
|
||||
throw new AgentLoadException("Insuffient memory");
|
||||
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:
|
||||
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:
|
||||
throw new AgentInitializationException("Agent JAR loaded but agent failed to initialize");
|
||||
throw new AgentInitializationException(
|
||||
"Agent JAR loaded but agent failed to initialize");
|
||||
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;
|
||||
}
|
||||
|
||||
private static final String MANAGMENT_PREFIX = "com.sun.management.";
|
||||
private static final String MANAGEMENT_PREFIX = "com.sun.management.";
|
||||
|
||||
private static boolean checkedKeyName(Object key) {
|
||||
if (!(key instanceof String)) {
|
||||
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);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static String stripKeyName(Object key) {
|
||||
return ((String)key).substring(MANAGMENT_PREFIX.length());
|
||||
return ((String)key).substring(MANAGEMENT_PREFIX.length());
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -204,9 +235,11 @@ public abstract class HotSpotVirtualMachine extends VirtualMachine {
|
||||
@Override
|
||||
public String startLocalManagementAgent() throws IOException {
|
||||
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 ---
|
||||
|
||||
// same as SIGQUIT
|
||||
@ -245,8 +278,8 @@ public abstract class HotSpotVirtualMachine extends VirtualMachine {
|
||||
return executeCommand("jcmd", command);
|
||||
}
|
||||
|
||||
// -- Supporting methods
|
||||
|
||||
// -- Supporting methods
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
String readErrorMessage(InputStream sis) throws IOException {
|
||||
String readErrorMessage(InputStream in) throws IOException {
|
||||
String s;
|
||||
StringBuilder message = new StringBuilder();
|
||||
BufferedReader br = new BufferedReader(new InputStreamReader(sis));
|
||||
BufferedReader br = new BufferedReader(new InputStreamReader(in));
|
||||
while ((s = br.readLine()) != null) {
|
||||
message.append(s);
|
||||
}
|
||||
|
@ -160,13 +160,14 @@ public class VirtualMachineImpl extends HotSpotVirtualMachine {
|
||||
String message = readErrorMessage(sis);
|
||||
sis.close();
|
||||
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 {
|
||||
if (message == null) {
|
||||
throw new AttachOperationFailedException("Command failed in target VM");
|
||||
} else {
|
||||
throw new AttachOperationFailedException(message);
|
||||
}
|
||||
if (message.isEmpty())
|
||||
message = "Command failed in target VM";
|
||||
throw new AttachOperationFailedException(message);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -100,28 +100,29 @@ public class VirtualMachineImpl extends HotSpotVirtualMachine {
|
||||
connectPipe(hPipe);
|
||||
|
||||
// create an input stream for the pipe
|
||||
PipedInputStream is = new PipedInputStream(hPipe);
|
||||
PipedInputStream in = new PipedInputStream(hPipe);
|
||||
|
||||
// read completion status
|
||||
int status = readInt(is);
|
||||
int status = readInt(in);
|
||||
if (status != 0) {
|
||||
// read from the stream and use that as the error message
|
||||
String message = readErrorMessage(is);
|
||||
is.close();
|
||||
String message = readErrorMessage(in);
|
||||
in.close();
|
||||
// special case the load command so that the right exception is thrown
|
||||
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 {
|
||||
if (message == null) {
|
||||
throw new AttachOperationFailedException("Command failed in target VM");
|
||||
} else {
|
||||
throw new AttachOperationFailedException(message);
|
||||
}
|
||||
if (message.isEmpty())
|
||||
message = "Command failed in target VM";
|
||||
throw new AttachOperationFailedException(message);
|
||||
}
|
||||
}
|
||||
|
||||
// return the input stream
|
||||
return is;
|
||||
return in;
|
||||
|
||||
} catch (IOException ioe) {
|
||||
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.stream.Collectors.joining;
|
||||
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
|
||||
@ -132,6 +133,10 @@ public class Main {
|
||||
// if --release option found followed by at least file
|
||||
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
|
||||
* uflag: update
|
||||
@ -413,7 +418,7 @@ public class Main {
|
||||
}
|
||||
} else {
|
||||
try (FileInputStream fin = new FileInputStream(FileDescriptor.in)) {
|
||||
found = describeModule(fin);
|
||||
found = describeModuleFromStream(fin);
|
||||
}
|
||||
}
|
||||
if (!found)
|
||||
@ -604,11 +609,6 @@ public class Main {
|
||||
/* parse file arguments */
|
||||
int n = args.length - count;
|
||||
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 k = 0;
|
||||
String[] nameBuf = new String[n];
|
||||
@ -616,6 +616,12 @@ public class Main {
|
||||
try {
|
||||
for (int i = count; i < args.length; i++) {
|
||||
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 */
|
||||
String dir = args[++i];
|
||||
dir = (dir.endsWith(File.separator) ?
|
||||
@ -649,8 +655,15 @@ public class Main {
|
||||
k = 0;
|
||||
nameBuf = new String[n];
|
||||
version = v;
|
||||
releaseValue = version;
|
||||
pathsMap.put(version, new HashSet<>());
|
||||
} 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];
|
||||
}
|
||||
}
|
||||
@ -756,7 +769,7 @@ public class Main {
|
||||
* can be found by recursively descending directories.
|
||||
*
|
||||
* @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
|
||||
* @throws IOException if an I/O error occurs
|
||||
*/
|
||||
@ -1721,23 +1734,62 @@ public class Main {
|
||||
|
||||
// Modular jar support
|
||||
|
||||
static <T> String toString(Collection<T> c,
|
||||
CharSequence prefix,
|
||||
CharSequence suffix ) {
|
||||
if (c.isEmpty())
|
||||
return "";
|
||||
return c.stream().map(e -> e.toString())
|
||||
.collect(joining(", ", prefix, suffix));
|
||||
/**
|
||||
* Associates a module descriptor's zip entry name along with its
|
||||
* bytes and an optional URI. Used when describing modules.
|
||||
*/
|
||||
interface ModuleInfoEntry {
|
||||
String name();
|
||||
Optional<String> uriString();
|
||||
InputStream bytes() throws IOException;
|
||||
}
|
||||
|
||||
private boolean describeModule(ZipFile zipFile) throws IOException {
|
||||
ZipEntry[] zes = zipFile.stream()
|
||||
.filter(e -> isModuleInfoEntry(e.getName()))
|
||||
.sorted(Validator.ENTRY_COMPARATOR)
|
||||
.toArray(ZipEntry[]::new);
|
||||
static class ZipFileModuleInfoEntry implements ModuleInfoEntry {
|
||||
private final ZipFile zipFile;
|
||||
private final ZipEntry entry;
|
||||
ZipFileModuleInfoEntry(ZipFile zipFile, ZipEntry entry) {
|
||||
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) {
|
||||
// No module descriptor found, derive the automatic module name
|
||||
static class StreamedModuleInfoEntry implements ModuleInfoEntry {
|
||||
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();
|
||||
ModuleFinder mf = ModuleFinder.of(Paths.get(fn));
|
||||
try {
|
||||
@ -1747,8 +1799,8 @@ public class Main {
|
||||
return true;
|
||||
}
|
||||
ModuleDescriptor md = mref.iterator().next().descriptor();
|
||||
output(getMsg("out.automodule"));
|
||||
describeModule(md, null, null, "automatic");
|
||||
output(getMsg("out.automodule") + "\n");
|
||||
describeModule(md, null, null, "");
|
||||
} catch (FindException e) {
|
||||
String msg = formatMsg("error.unable.derive.automodule", fn);
|
||||
Throwable t = e.getCause();
|
||||
@ -1757,46 +1809,117 @@ public class Main {
|
||||
output(msg);
|
||||
}
|
||||
} else {
|
||||
for (ZipEntry ze : zes) {
|
||||
try (InputStream is = zipFile.getInputStream(ze)) {
|
||||
describeModule(is, ze.getName());
|
||||
}
|
||||
}
|
||||
return describeModuleFromEntries(infos);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean describeModule(FileInputStream fis)
|
||||
private boolean describeModuleFromStream(FileInputStream fis)
|
||||
throws IOException
|
||||
{
|
||||
List<ModuleInfoEntry> infos = new LinkedList<>();
|
||||
|
||||
try (BufferedInputStream bis = new BufferedInputStream(fis);
|
||||
ZipInputStream zis = new ZipInputStream(bis)) {
|
||||
ZipEntry e;
|
||||
while ((e = zis.getNextEntry()) != null) {
|
||||
String ename = e.getName();
|
||||
if (isModuleInfoEntry(ename)){
|
||||
moduleInfos.put(ename, zis.readAllBytes());
|
||||
if (isModuleInfoEntry(ename)) {
|
||||
infos.add(new StreamedModuleInfoEntry(ename, zis.readAllBytes()));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (moduleInfos.size() == 0)
|
||||
|
||||
if (infos.size() == 0)
|
||||
return false;
|
||||
String[] names = moduleInfos.keySet().stream()
|
||||
.sorted(Validator.ENTRYNAME_COMPARATOR)
|
||||
.toArray(String[]::new);
|
||||
for (String name : names) {
|
||||
describeModule(new ByteArrayInputStream(moduleInfos.get(name)), name);
|
||||
|
||||
ModuleInfoEntry[] sorted = infos.stream()
|
||||
.sorted(Comparator.comparing(ModuleInfoEntry::name, ENTRYNAME_COMPARATOR))
|
||||
.toArray(ModuleInfoEntry[]::new);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
static <T> String toString(Collection<T> set) {
|
||||
if (set.isEmpty()) { return ""; }
|
||||
return set.stream().map(e -> e.toString().toLowerCase(Locale.ROOT))
|
||||
.collect(joining(" "));
|
||||
return " " + set.stream().map(e -> e.toString().toLowerCase(Locale.ROOT))
|
||||
.sorted().collect(joining(" "));
|
||||
}
|
||||
|
||||
private void describeModule(InputStream entryInputStream, String ename)
|
||||
|
||||
private void describeModule(InputStream entryInputStream, String uriString)
|
||||
throws IOException
|
||||
{
|
||||
ModuleInfo.Attributes attrs = ModuleInfo.read(entryInputStream, null);
|
||||
@ -1804,71 +1927,94 @@ public class Main {
|
||||
ModuleTarget target = attrs.target();
|
||||
ModuleHashes hashes = attrs.recordedHashes();
|
||||
|
||||
describeModule(md, target, hashes, ename);
|
||||
describeModule(md, target, hashes, uriString);
|
||||
}
|
||||
|
||||
private void describeModule(ModuleDescriptor md,
|
||||
ModuleTarget target,
|
||||
ModuleHashes hashes,
|
||||
String ename)
|
||||
String uriString)
|
||||
throws IOException
|
||||
{
|
||||
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())
|
||||
sb.append("\n open ");
|
||||
|
||||
md.requires().stream()
|
||||
.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()
|
||||
.forEach(p -> sb.append("\n uses ").append(p));
|
||||
sb.append(" open");
|
||||
if (md.isAutomatic())
|
||||
sb.append(" automatic");
|
||||
sb.append("\n");
|
||||
|
||||
// unqualified exports (sorted by package)
|
||||
md.exports().stream()
|
||||
.sorted(Comparator.comparing(Exports::source))
|
||||
.forEach(p -> sb.append("\n exports ").append(p));
|
||||
.sorted(Comparator.comparing(Exports::source))
|
||||
.filter(e -> !e.isQualified())
|
||||
.forEach(e -> sb.append("exports ").append(e.source())
|
||||
.append(toString(e.modifiers())).append("\n"));
|
||||
|
||||
md.opens().stream()
|
||||
.sorted(Comparator.comparing(Opens::source))
|
||||
.forEach(p -> sb.append("\n opens ").append(p));
|
||||
// dependences
|
||||
md.requires().stream().sorted()
|
||||
.forEach(r -> sb.append("requires ").append(r.name())
|
||||
.append(toString(r.modifiers())).append("\n"));
|
||||
|
||||
Set<String> concealed = new HashSet<>(md.packages());
|
||||
md.exports().stream().map(Exports::source).forEach(concealed::remove);
|
||||
md.opens().stream().map(Opens::source).forEach(concealed::remove);
|
||||
concealed.stream().sorted()
|
||||
.forEach(p -> sb.append("\n contains ").append(p));
|
||||
// service use and provides
|
||||
md.uses().stream().sorted()
|
||||
.forEach(s -> sb.append("uses ").append(s).append("\n"));
|
||||
|
||||
md.provides().stream()
|
||||
.sorted(Comparator.comparing(Provides::service))
|
||||
.forEach(p -> sb.append("\n provides ").append(p.service())
|
||||
.append(" with ")
|
||||
.append(toString(p.providers())));
|
||||
.sorted(Comparator.comparing(Provides::service))
|
||||
.forEach(p -> sb.append("provides ").append(p.service())
|
||||
.append(" with")
|
||||
.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) {
|
||||
String osName = target.osName();
|
||||
if (osName != null)
|
||||
sb.append("\n operating-system-name " + osName);
|
||||
String osArch = target.osArch();
|
||||
if (osArch != null)
|
||||
sb.append("\n operating-system-architecture " + osArch);
|
||||
String targetPlatform = target.targetPlatform();
|
||||
if (!targetPlatform.isEmpty())
|
||||
sb.append("platform ").append(targetPlatform).append("\n");
|
||||
}
|
||||
|
||||
if (hashes != null) {
|
||||
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(toHex(hashes.hashFor(mod))));
|
||||
.append(toHex(hashes.hashFor(mod)))
|
||||
.append("\n"));
|
||||
}
|
||||
|
||||
output(sb.toString());
|
||||
|
@ -116,7 +116,7 @@ final class Validator {
|
||||
// version number strings need to be sorted numerically
|
||||
n = VERSIONS_DIR.length(); // skip the common prefix
|
||||
int i1 = s1.indexOf('/', n);
|
||||
int i2 = s1.indexOf('/', n);
|
||||
int i2 = s2.indexOf('/', n);
|
||||
if (i1 == -1) throw new InvalidJarException(s1);
|
||||
if (i2 == -1) throw new InvalidJarException(s2);
|
||||
// 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\
|
||||
together!
|
||||
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=\
|
||||
bad reason: {0}, must be one of deprecated, deprecated-for-removal, or incubating
|
||||
error.nosuch.fileordir=\
|
||||
@ -62,6 +62,10 @@ error.hash.dep=\
|
||||
Hashing module {0} dependences, unable to find module {1} on module path
|
||||
error.module.options.without.info=\
|
||||
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=\
|
||||
Unable to derive module descriptor for: {0}
|
||||
error.unexpected.module-info=\
|
||||
|
@ -152,14 +152,14 @@ public final class DefaultImageBuilder implements ImageBuilder {
|
||||
@Override
|
||||
public void storeFiles(ResourcePool files) {
|
||||
try {
|
||||
String targetOsName = files.moduleView()
|
||||
.findModule("java.base")
|
||||
.map(ResourcePoolModule::osName)
|
||||
.orElse(null);
|
||||
if (targetOsName == null) {
|
||||
String value = files.moduleView()
|
||||
.findModule("java.base")
|
||||
.map(ResourcePoolModule::targetPlatform)
|
||||
.orElse(null);
|
||||
if (value == null) {
|
||||
throw new PluginException("ModuleTarget attribute is missing for java.base module");
|
||||
}
|
||||
this.targetPlatform = Platform.toPlatform(targetOsName);
|
||||
this.targetPlatform = Platform.toPlatform(value);
|
||||
|
||||
checkResourcePool(files);
|
||||
|
||||
|
@ -324,15 +324,9 @@ public final class ImagePluginStack {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String osName() {
|
||||
public String targetPlatform() {
|
||||
initModuleAttributes();
|
||||
return target != null? target.osName() : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String osArch() {
|
||||
initModuleAttributes();
|
||||
return target != null? target.osArch() : null;
|
||||
return target != null? target.targetPlatform() : null;
|
||||
}
|
||||
|
||||
private void initModuleAttributes() {
|
||||
|
@ -40,12 +40,17 @@ public enum Platform {
|
||||
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.
|
||||
*
|
||||
* @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 {
|
||||
return Platform.valueOf(osName.toUpperCase(Locale.ENGLISH));
|
||||
} catch (IllegalArgumentException e) {
|
||||
@ -57,9 +62,9 @@ public enum Platform {
|
||||
* Returns the {@code Platform} to which the given module is target to.
|
||||
*/
|
||||
public static Platform getTargetPlatform(ResourcePoolModule module) {
|
||||
String osName = module.osName();
|
||||
if (osName != null) {
|
||||
return toPlatform(osName);
|
||||
String targetPlatform = module.targetPlatform();
|
||||
if (targetPlatform != null) {
|
||||
return toPlatform(targetPlatform);
|
||||
} else {
|
||||
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.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -110,15 +110,9 @@ public class ResourcePoolManager {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String osName() {
|
||||
public String targetPlatform() {
|
||||
initModuleAttributes();
|
||||
return target != null? target.osName() : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String osArch() {
|
||||
initModuleAttributes();
|
||||
return target != null? target.osArch() : null;
|
||||
return target != null? target.targetPlatform() : null;
|
||||
}
|
||||
|
||||
private void initModuleAttributes() {
|
||||
|
@ -33,13 +33,13 @@ import java.lang.module.ModuleDescriptor;
|
||||
import java.util.EnumSet;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
import jdk.tools.jlink.internal.ModuleSorter;
|
||||
import jdk.tools.jlink.internal.Utils;
|
||||
import jdk.tools.jlink.plugin.PluginException;
|
||||
import jdk.tools.jlink.plugin.ResourcePool;
|
||||
import jdk.tools.jlink.plugin.ResourcePoolBuilder;
|
||||
import jdk.tools.jlink.plugin.ResourcePoolEntry;
|
||||
@ -132,18 +132,16 @@ public final class ReleaseInfoPlugin implements Plugin {
|
||||
public ResourcePool transform(ResourcePool in, ResourcePoolBuilder out) {
|
||||
in.transformAndCopy(Function.identity(), out);
|
||||
|
||||
Optional<ResourcePoolModule> javaBase = in.moduleView().findModule("java.base");
|
||||
javaBase.ifPresent(mod -> {
|
||||
// fill release information available from transformed "java.base" module!
|
||||
ModuleDescriptor desc = mod.descriptor();
|
||||
desc.version().ifPresent(s -> release.put("JAVA_VERSION",
|
||||
quote(parseVersion(s.toString()))));
|
||||
desc.version().ifPresent(s -> release.put("JAVA_FULL_VERSION",
|
||||
quote(s.toString())));
|
||||
ResourcePoolModule javaBase = in.moduleView().findModule("java.base")
|
||||
.orElse(null);
|
||||
if (javaBase == null || javaBase.targetPlatform() == null) {
|
||||
throw new PluginException("ModuleTarget attribute is missing for java.base module");
|
||||
}
|
||||
|
||||
release.put("OS_NAME", quote(mod.osName()));
|
||||
release.put("OS_ARCH", quote(mod.osArch()));
|
||||
});
|
||||
// fill release information available from transformed "java.base" module!
|
||||
ModuleDescriptor desc = javaBase.descriptor();
|
||||
desc.version().ifPresent(v -> release.put("JAVA_VERSION",
|
||||
quote(parseVersion(v))));
|
||||
|
||||
// put topological sorted module names separated by space
|
||||
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.
|
||||
out.add(ResourcePoolEntry.create("/java.base/release",
|
||||
ResourcePoolEntry.Type.TOP, releaseFileContent()));
|
||||
ResourcePoolEntry.Type.TOP,
|
||||
releaseFileContent()));
|
||||
return out.build();
|
||||
}
|
||||
|
||||
// Parse version string and return a string that includes only version part
|
||||
// leaving "pre", "build" information. See also: java.lang.Runtime.Version.
|
||||
private static String parseVersion(String str) {
|
||||
return Runtime.Version.parse(str)
|
||||
private static String parseVersion(ModuleDescriptor.Version v) {
|
||||
return Runtime.Version.parse(v.toString())
|
||||
.version()
|
||||
.stream()
|
||||
.map(Object::toString)
|
||||
|
@ -211,8 +211,7 @@ public final class SystemModulesPlugin implements Plugin {
|
||||
// drop target attribute only if any OS property is present
|
||||
ModuleTarget target = attrs.target();
|
||||
if (dropModuleTarget && target != null) {
|
||||
this.dropModuleTarget = (target.osName() != null)
|
||||
|| (target.osArch() != null);
|
||||
this.dropModuleTarget = (target.targetPlatform() != null);
|
||||
} else {
|
||||
this.dropModuleTarget = false;
|
||||
}
|
||||
@ -377,7 +376,7 @@ public final class SystemModulesPlugin implements Plugin {
|
||||
}
|
||||
|
||||
void dropModuleTarget() {
|
||||
extender.targetPlatform("", "");
|
||||
extender.targetPlatform("");
|
||||
}
|
||||
|
||||
byte[] getBytes() throws IOException {
|
||||
@ -527,8 +526,7 @@ public final class SystemModulesPlugin implements Plugin {
|
||||
ModuleDescriptor md = moduleInfo.descriptor;
|
||||
// drop ModuleTarget attribute if java.base has all OS properties
|
||||
ModuleTarget target = moduleInfo.target();
|
||||
if (dropModuleTarget
|
||||
&& (target.osName() != null) && (target.osArch() != null)) {
|
||||
if (dropModuleTarget && target.targetPlatform() != null) {
|
||||
dropModuleTarget = true;
|
||||
} else {
|
||||
dropModuleTarget = false;
|
||||
@ -543,7 +541,7 @@ public final class SystemModulesPlugin implements Plugin {
|
||||
moduleInfo.validatePackages();
|
||||
|
||||
// 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
|
||||
if (moduleInfo.shouldRewrite()) {
|
||||
entry = entry.copyWithContent(moduleInfo.getBytes());
|
||||
@ -655,10 +653,9 @@ public final class SystemModulesPlugin implements Plugin {
|
||||
// new ModuleTarget(String, String)
|
||||
mv.visitTypeInsn(NEW, MODULE_TARGET_CLASSNAME);
|
||||
mv.visitInsn(DUP);
|
||||
mv.visitLdcInsn(minfo.target().osName());
|
||||
mv.visitLdcInsn(minfo.target().osArch());
|
||||
mv.visitLdcInsn(minfo.target().targetPlatform());
|
||||
mv.visitMethodInsn(INVOKESPECIAL, MODULE_TARGET_CLASSNAME,
|
||||
"<init>", "(Ljava/lang/String;Ljava/lang/String;)V", false);
|
||||
"<init>", "(Ljava/lang/String;)V", false);
|
||||
|
||||
mv.visitInsn(AASTORE);
|
||||
}
|
||||
|
@ -58,18 +58,11 @@ public interface ResourcePoolModule {
|
||||
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();
|
||||
|
||||
/**
|
||||
* The module target OS arch for this module.
|
||||
*
|
||||
* @return The module target OS arch
|
||||
*/
|
||||
public String osArch();
|
||||
public String targetPlatform();
|
||||
|
||||
/**
|
||||
* Retrieves all the packages located in this module.
|
||||
|
@ -177,8 +177,7 @@ public class JmodTask {
|
||||
ModuleFinder moduleFinder;
|
||||
Version moduleVersion;
|
||||
String mainClass;
|
||||
String osName;
|
||||
String osArch;
|
||||
String targetPlatform;
|
||||
Pattern modulesToHash;
|
||||
ModuleResolution moduleResolution;
|
||||
boolean dryrun;
|
||||
@ -311,9 +310,9 @@ public class JmodTask {
|
||||
try (JmodFile jf = new JmodFile(options.jmodFile)) {
|
||||
try (InputStream in = jf.getInputStream(Section.CLASSES, MODULE_INFO)) {
|
||||
ModuleInfo.Attributes attrs = ModuleInfo.read(in, null);
|
||||
printModuleDescriptor(attrs.descriptor(),
|
||||
attrs.target(),
|
||||
attrs.recordedHashes());
|
||||
describeModule(attrs.descriptor(),
|
||||
attrs.target(),
|
||||
attrs.recordedHashes());
|
||||
return true;
|
||||
} catch (IOException e) {
|
||||
throw new CommandException("err.module.descriptor.not.found");
|
||||
@ -323,66 +322,92 @@ public class JmodTask {
|
||||
|
||||
static <T> String toString(Collection<T> c) {
|
||||
if (c.isEmpty()) { return ""; }
|
||||
return c.stream().map(e -> e.toString().toLowerCase(Locale.ROOT))
|
||||
.collect(joining(" "));
|
||||
return " " + c.stream().map(e -> e.toString().toLowerCase(Locale.ROOT))
|
||||
.sorted().collect(joining(" "));
|
||||
}
|
||||
|
||||
private void printModuleDescriptor(ModuleDescriptor md,
|
||||
ModuleTarget target,
|
||||
ModuleHashes hashes)
|
||||
private void describeModule(ModuleDescriptor md,
|
||||
ModuleTarget target,
|
||||
ModuleHashes hashes)
|
||||
throws IOException
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("\n").append(md.toNameAndVersion());
|
||||
|
||||
md.requires().stream()
|
||||
.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());
|
||||
});
|
||||
sb.append(md.toNameAndVersion());
|
||||
|
||||
md.uses().stream().sorted()
|
||||
.forEach(s -> sb.append("\n uses ").append(s));
|
||||
if (md.isOpen())
|
||||
sb.append(" open");
|
||||
if (md.isAutomatic())
|
||||
sb.append(" automatic");
|
||||
sb.append("\n");
|
||||
|
||||
// unqualified exports (sorted by package)
|
||||
md.exports().stream()
|
||||
.sorted(Comparator.comparing(Exports::source))
|
||||
.forEach(p -> sb.append("\n exports ").append(p));
|
||||
.sorted(Comparator.comparing(Exports::source))
|
||||
.filter(e -> !e.isQualified())
|
||||
.forEach(e -> sb.append("exports ").append(e.source())
|
||||
.append(toString(e.modifiers())).append("\n"));
|
||||
|
||||
md.opens().stream()
|
||||
.sorted(Comparator.comparing(Opens::source))
|
||||
.forEach(p -> sb.append("\n opens ").append(p));
|
||||
// dependences
|
||||
md.requires().stream().sorted()
|
||||
.forEach(r -> sb.append("requires ").append(r.name())
|
||||
.append(toString(r.modifiers())).append("\n"));
|
||||
|
||||
Set<String> concealed = new HashSet<>(md.packages());
|
||||
md.exports().stream().map(Exports::source).forEach(concealed::remove);
|
||||
md.opens().stream().map(Opens::source).forEach(concealed::remove);
|
||||
concealed.stream().sorted()
|
||||
.forEach(p -> sb.append("\n contains ").append(p));
|
||||
// service use and provides
|
||||
md.uses().stream().sorted()
|
||||
.forEach(s -> sb.append("uses ").append(s).append("\n"));
|
||||
|
||||
md.provides().stream()
|
||||
.sorted(Comparator.comparing(Provides::service))
|
||||
.forEach(p -> sb.append("\n provides ").append(p.service())
|
||||
.append(" with ")
|
||||
.append(toString(p.providers())));
|
||||
.sorted(Comparator.comparing(Provides::service))
|
||||
.forEach(p -> sb.append("provides ").append(p.service())
|
||||
.append(" with")
|
||||
.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) {
|
||||
String osName = target.osName();
|
||||
if (osName != null)
|
||||
sb.append("\n operating-system-name " + osName);
|
||||
String osArch = target.osArch();
|
||||
if (osArch != null)
|
||||
sb.append("\n operating-system-architecture " + osArch);
|
||||
}
|
||||
String targetPlatform = target.targetPlatform();
|
||||
if (!targetPlatform.isEmpty())
|
||||
sb.append("platform ").append(targetPlatform).append("\n");
|
||||
}
|
||||
|
||||
if (hashes != null) {
|
||||
hashes.names().stream().sorted().forEach(
|
||||
mod -> sb.append("\n hashes ").append(mod).append(" ")
|
||||
.append(hashes.algorithm()).append(" ")
|
||||
.append(toHex(hashes.hashFor(mod))));
|
||||
if (hashes != null) {
|
||||
hashes.names().stream().sorted().forEach(
|
||||
mod -> sb.append("hashes ").append(mod).append(" ")
|
||||
.append(hashes.algorithm()).append(" ")
|
||||
.append(toHex(hashes.hashFor(mod)))
|
||||
.append("\n"));
|
||||
}
|
||||
|
||||
out.println(sb.toString());
|
||||
@ -437,8 +462,7 @@ public class JmodTask {
|
||||
|
||||
final Version moduleVersion = options.moduleVersion;
|
||||
final String mainClass = options.mainClass;
|
||||
final String osName = options.osName;
|
||||
final String osArch = options.osArch;
|
||||
final String targetPlatform = options.targetPlatform;
|
||||
final List<PathMatcher> excludes = options.excludes;
|
||||
final ModuleResolution moduleResolution = options.moduleResolution;
|
||||
|
||||
@ -534,9 +558,10 @@ public class JmodTask {
|
||||
if (mainClass != null)
|
||||
extender.mainClass(mainClass);
|
||||
|
||||
// --os-name, --os-arch
|
||||
if (osName != null || osArch != null)
|
||||
extender.targetPlatform(osName, osArch);
|
||||
// --target-platform
|
||||
if (targetPlatform != null) {
|
||||
extender.targetPlatform(targetPlatform);
|
||||
}
|
||||
|
||||
// --module-version
|
||||
if (moduleVersion != null)
|
||||
@ -1327,15 +1352,10 @@ public class JmodTask {
|
||||
.withRequiredArg()
|
||||
.withValuesConvertedBy(new ModuleVersionConverter());
|
||||
|
||||
OptionSpec<String> osName
|
||||
= parser.accepts("os-name", getMessage("main.opt.os-name"))
|
||||
OptionSpec<String> targetPlatform
|
||||
= parser.accepts("target-platform", getMessage("main.opt.target-platform"))
|
||||
.withRequiredArg()
|
||||
.describedAs(getMessage("main.opt.os-name.arg"));
|
||||
|
||||
OptionSpec<String> osArch
|
||||
= parser.accepts("os-arch", getMessage("main.opt.os-arch"))
|
||||
.withRequiredArg()
|
||||
.describedAs(getMessage("main.opt.os-arch.arg"));
|
||||
.describedAs(getMessage("main.opt.target-platform.arg"));
|
||||
|
||||
OptionSpec<Void> doNotResolveByDefault
|
||||
= parser.accepts("do-not-resolve-by-default",
|
||||
@ -1400,10 +1420,8 @@ public class JmodTask {
|
||||
options.moduleVersion = getLastElement(opts.valuesOf(moduleVersion));
|
||||
if (opts.has(mainClass))
|
||||
options.mainClass = getLastElement(opts.valuesOf(mainClass));
|
||||
if (opts.has(osName))
|
||||
options.osName = getLastElement(opts.valuesOf(osName));
|
||||
if (opts.has(osArch))
|
||||
options.osArch = getLastElement(opts.valuesOf(osArch));
|
||||
if (opts.has(targetPlatform))
|
||||
options.targetPlatform = getLastElement(opts.valuesOf(targetPlatform));
|
||||
if (opts.has(warnIfResolved))
|
||||
options.moduleResolution = getLastElement(opts.valuesOf(warnIfResolved));
|
||||
if (opts.has(doNotResolveByDefault)) {
|
||||
|
@ -64,10 +64,8 @@ main.opt.module-version= Module version
|
||||
main.opt.main-class=Main class
|
||||
main.opt.main-class.arg=class-name
|
||||
main.opt.man-pages=Location of man pages
|
||||
main.opt.os-name=Operating system name
|
||||
main.opt.os-name.arg=os-name
|
||||
main.opt.os-arch=Operating system architecture
|
||||
main.opt.os-arch.arg=os-arch
|
||||
main.opt.target-platform=Target platform
|
||||
main.opt.target-platform.arg=target-platform
|
||||
main.opt.module-path=Module path
|
||||
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\
|
||||
|
@ -66,6 +66,7 @@ public class CheckOrigin {
|
||||
"-XX:+UseCodeAging",
|
||||
"-XX:+UseCerealGC", // Should be ignored.
|
||||
"-XX:Flags=" + flagsFile.getAbsolutePath(),
|
||||
"-Djdk.attach.allowAttachSelf",
|
||||
"-cp", System.getProperty("test.class.path"),
|
||||
"CheckOrigin",
|
||||
"-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 {
|
||||
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);
|
||||
ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(args);
|
||||
ProcessThread pt = new ProcessThread("runApplication", (line) -> line.equals(Application.READY_MSG), pb);
|
||||
|
@ -8,7 +8,8 @@ grant {
|
||||
permission com.sun.tools.attach.AttachPermission "createAttachProvider";
|
||||
|
||||
/* 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.jvmstat.monitor";
|
||||
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.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -21,8 +21,7 @@
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package javax.transaction.atomic;
|
||||
|
||||
public interface Atomic {
|
||||
|
||||
module m {
|
||||
exports p;
|
||||
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
|
||||
public void testDefineClass() throws Exception {
|
||||
final String CLASS_NAME = THIS_PACKAGE + ".Foo";
|
||||
Lookup lookup = lookup().dropLookupMode(PRIVATE);
|
||||
Lookup lookup = lookup();
|
||||
Class<?> clazz = lookup.defineClass(generateClass(CLASS_NAME));
|
||||
|
||||
// test name
|
||||
@ -101,7 +101,7 @@ public class DefineClassTest {
|
||||
public void testAccess() throws Exception {
|
||||
final String THIS_CLASS = this.getClass().getName();
|
||||
final String CLASS_NAME = THIS_PACKAGE + ".Runner";
|
||||
Lookup lookup = lookup().dropLookupMode(PRIVATE);
|
||||
Lookup lookup = lookup();
|
||||
|
||||
// public
|
||||
byte[] classBytes = generateRunner(CLASS_NAME + nextNumber(), THIS_CLASS, "method1");
|
||||
@ -144,9 +144,8 @@ public class DefineClassTest {
|
||||
final String CLASS_NAME = THIS_PACKAGE + ".ClassWithClinit";
|
||||
|
||||
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
|
||||
try {
|
||||
clazz.newInstance();
|
||||
@ -186,14 +185,14 @@ public class DefineClassTest {
|
||||
assertNotEquals(target1.getProtectionDomain(), target2.getProtectionDomain());
|
||||
|
||||
// protection domain 1
|
||||
Lookup lookup1 = privateLookupIn(target1, lookup()).dropLookupMode(PRIVATE);
|
||||
Lookup lookup1 = privateLookupIn(target1, lookup());
|
||||
|
||||
Class<?> clazz = lookup1.defineClass(generateClass("p.Foo"));
|
||||
testSameAbode(clazz, lookup1.lookupClass());
|
||||
testDiscoverable(clazz, lookup1);
|
||||
|
||||
// protection domain 2
|
||||
Lookup lookup2 = privateLookupIn(target2, lookup()).dropLookupMode(PRIVATE);
|
||||
Lookup lookup2 = privateLookupIn(target2, lookup());
|
||||
|
||||
clazz = lookup2.defineClass(generateClass("p.Bar"));
|
||||
testSameAbode(clazz, lookup2.lookupClass());
|
||||
@ -205,7 +204,7 @@ public class DefineClassTest {
|
||||
*/
|
||||
@Test
|
||||
public void testBootLoader() throws Exception {
|
||||
Lookup lookup = privateLookupIn(Thread.class, lookup()).dropLookupMode(PRIVATE);
|
||||
Lookup lookup = privateLookupIn(Thread.class, lookup());
|
||||
assertTrue(lookup.getClass().getClassLoader() == null);
|
||||
|
||||
Class<?> clazz = lookup.defineClass(generateClass("java.lang.Foo"));
|
||||
@ -216,8 +215,7 @@ public class DefineClassTest {
|
||||
|
||||
@Test(expectedExceptions = { IllegalArgumentException.class })
|
||||
public void testWrongPackage() throws Exception {
|
||||
Lookup lookup = lookup().dropLookupMode(PRIVATE);
|
||||
lookup.defineClass(generateClass("other.C"));
|
||||
lookup().defineClass(generateClass("other.C"));
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = { IllegalAccessException.class })
|
||||
@ -226,23 +224,14 @@ public class DefineClassTest {
|
||||
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 })
|
||||
public void testTruncatedClassFile() throws Exception {
|
||||
Lookup lookup = lookup().dropLookupMode(PRIVATE);
|
||||
lookup.defineClass(new byte[0]);
|
||||
lookup().defineClass(new byte[0]);
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = { NullPointerException.class })
|
||||
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
|
||||
@DataProvider(name = "badmainclass")
|
||||
public Object[][] createBadMainClass() {
|
||||
return new Object[][]{
|
||||
|
||||
{ "Main", null },
|
||||
return new Object[][] {
|
||||
{ "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
|
||||
* type name.
|
||||
*/
|
||||
@Test(dataProvider = "badmainclass", expectedExceptions = FindException.class)
|
||||
@Test(dataProvider = "badmainclass")
|
||||
public void testBadMainClass(String mainClass, String ignore) throws IOException {
|
||||
Manifest man = new Manifest();
|
||||
Attributes attrs = man.getMainAttributes();
|
||||
@ -426,14 +424,16 @@ public class AutomaticModulesTest {
|
||||
String entry = mainClass.replace('.', '/') + ".class";
|
||||
createDummyJarFile(dir.resolve("m.jar"), man, entry);
|
||||
|
||||
// should throw FindException
|
||||
ModuleFinder.of(dir).findAll();
|
||||
// bad Main-Class value should be ignored
|
||||
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(expectedExceptions = FindException.class)
|
||||
public void testMissingMainClassPackage() throws IOException {
|
||||
Manifest man = new Manifest();
|
||||
Attributes attrs = man.getMainAttributes();
|
||||
@ -443,8 +443,11 @@ public class AutomaticModulesTest {
|
||||
Path dir = Files.createTempDirectory(USER_DIR, "mods");
|
||||
createDummyJarFile(dir.resolve("m.jar"), man);
|
||||
|
||||
// should throw FindException
|
||||
ModuleFinder.of(dir).findAll();
|
||||
// Main-Class should be ignored because package p is not in module
|
||||
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() {
|
||||
return new Object[][]{
|
||||
|
||||
{ "linux-arm", "*-*" },
|
||||
{ "linux-*", "*-*" },
|
||||
{ "*-arm", "*-*" },
|
||||
|
||||
{ "linux-*", "linux-*" },
|
||||
{ "linux-arm", "linux-*" },
|
||||
|
||||
{ "*-arm", "*-arm" },
|
||||
{ "linux-arm", "*-arm" },
|
||||
|
||||
{ "linux-arm", "linux-arm" },
|
||||
{ "", "" },
|
||||
{ "linux-arm", "" },
|
||||
{ "linux-arm", "linux-arm" },
|
||||
|
||||
};
|
||||
|
||||
@ -1863,9 +1855,8 @@ public class ConfigurationTest {
|
||||
public Object[][] createBad() {
|
||||
return new Object[][] {
|
||||
|
||||
{ "linux-*", "solaris-*" },
|
||||
{ "*-arm", "*-sparc" },
|
||||
{ "linux-x86", "solaris-sparc" },
|
||||
{ "linux-x64", "linux-arm" },
|
||||
{ "linux-x64", "windows-x64" },
|
||||
|
||||
};
|
||||
}
|
||||
@ -1877,7 +1868,7 @@ public class ConfigurationTest {
|
||||
public void testPlatformMatch(String s1, String s2) throws IOException {
|
||||
|
||||
ModuleDescriptor base = ModuleDescriptor.newModule("java.base").build();
|
||||
Path system = writeModule(base, "*-*");
|
||||
Path system = writeModule(base, null);
|
||||
|
||||
ModuleDescriptor descriptor1 = ModuleDescriptor.newModule("m1")
|
||||
.requires("m2")
|
||||
@ -1928,7 +1919,7 @@ public class ConfigurationTest {
|
||||
throws IOException
|
||||
{
|
||||
ModuleDescriptor base = ModuleDescriptor.newModule("java.base").build();
|
||||
Path system = writeModule(base, "*-*");
|
||||
Path system = writeModule(base, null);
|
||||
|
||||
ModuleDescriptor descriptor1 = ModuleDescriptor.newModule("m1").build();
|
||||
Path dir1 = writeModule(descriptor1, s1);
|
||||
@ -2113,17 +2104,18 @@ public class ConfigurationTest {
|
||||
|
||||
|
||||
/**
|
||||
* Decodes the platform string and calls the builder osName/osArch/osVersion
|
||||
* methods to set the platform constraints.
|
||||
* Writes a module-info.class. If {@code targetPlatform} is not null then
|
||||
* 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
|
||||
{
|
||||
String[] s = platformString.split("-");
|
||||
String osName = !s[0].equals("*") ? s[0] : null;
|
||||
String osArch = !s[1].equals("*") ? s[1] : null;
|
||||
ModuleTarget target = new ModuleTarget(osName, osArch);
|
||||
|
||||
ModuleTarget target;
|
||||
if (targetPlatform != null) {
|
||||
target = new ModuleTarget(targetPlatform);
|
||||
} else {
|
||||
target = null;
|
||||
}
|
||||
String name = descriptor.name();
|
||||
Path dir = Files.createTempDirectory(name);
|
||||
Path mi = dir.resolve("module-info.class");
|
||||
|
@ -65,8 +65,8 @@ import static org.testng.Assert.*;
|
||||
@Test
|
||||
public class ModuleDescriptorTest {
|
||||
|
||||
@DataProvider(name = "invalidjavaidentifiers")
|
||||
public Object[][] invalidJavaIdentifiers() {
|
||||
@DataProvider(name = "invalidNames")
|
||||
public Object[][] invalidNames() {
|
||||
return new Object[][]{
|
||||
|
||||
{ null, null },
|
||||
@ -84,6 +84,32 @@ public class ModuleDescriptorTest {
|
||||
{ "foo.bar.1gus", 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");
|
||||
}
|
||||
|
||||
@Test(dataProvider = "invalidjavaidentifiers",
|
||||
@Test(dataProvider = "invalidNames",
|
||||
expectedExceptions = IllegalArgumentException.class )
|
||||
public void testRequiresWithBadModuleName(String mn, String ignore) {
|
||||
requires(EnumSet.noneOf(Modifier.class), mn);
|
||||
@ -406,7 +432,7 @@ public class ModuleDescriptorTest {
|
||||
ModuleDescriptor.newModule("foo").exports("p", Collections.emptySet());
|
||||
}
|
||||
|
||||
@Test(dataProvider = "invalidjavaidentifiers",
|
||||
@Test(dataProvider = "invalidNames",
|
||||
expectedExceptions = IllegalArgumentException.class )
|
||||
public void testExportsWithBadName(String pn, String ignore) {
|
||||
ModuleDescriptor.newModule("foo").exports(pn);
|
||||
@ -568,7 +594,7 @@ public class ModuleDescriptorTest {
|
||||
ModuleDescriptor.newModule("foo").opens("p", Collections.emptySet());
|
||||
}
|
||||
|
||||
@Test(dataProvider = "invalidjavaidentifiers",
|
||||
@Test(dataProvider = "invalidNames",
|
||||
expectedExceptions = IllegalArgumentException.class )
|
||||
public void testOpensWithBadName(String pn, String ignore) {
|
||||
ModuleDescriptor.newModule("foo").opens(pn);
|
||||
@ -664,7 +690,7 @@ public class ModuleDescriptorTest {
|
||||
ModuleDescriptor.newModule("foo").uses("S");
|
||||
}
|
||||
|
||||
@Test(dataProvider = "invalidjavaidentifiers",
|
||||
@Test(dataProvider = "invalidNames",
|
||||
expectedExceptions = IllegalArgumentException.class )
|
||||
public void testUsesWithBadName(String service, String ignore) {
|
||||
ModuleDescriptor.newModule("foo").uses(service);
|
||||
@ -737,13 +763,13 @@ public class ModuleDescriptorTest {
|
||||
ModuleDescriptor.newModule("foo").provides("p.S", List.of("P"));
|
||||
}
|
||||
|
||||
@Test(dataProvider = "invalidjavaidentifiers",
|
||||
@Test(dataProvider = "invalidNames",
|
||||
expectedExceptions = IllegalArgumentException.class )
|
||||
public void testProvidesWithBadService(String service, String ignore) {
|
||||
ModuleDescriptor.newModule("foo").provides(service, List.of("p.Provider"));
|
||||
}
|
||||
|
||||
@Test(dataProvider = "invalidjavaidentifiers",
|
||||
@Test(dataProvider = "invalidNames",
|
||||
expectedExceptions = IllegalArgumentException.class )
|
||||
public void testProvidesWithBadProvider(String provider, String ignore) {
|
||||
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")));
|
||||
}
|
||||
|
||||
@Test(dataProvider = "invalidjavaidentifiers",
|
||||
@Test(dataProvider = "invalidNames",
|
||||
expectedExceptions = IllegalArgumentException.class )
|
||||
public void testPackagesWithBadName(String pn, String ignore) {
|
||||
Set<String> pkgs = new HashSet<>(); // allows nulls
|
||||
@ -943,7 +969,7 @@ public class ModuleDescriptorTest {
|
||||
assertEquals(mn, "foo");
|
||||
}
|
||||
|
||||
@Test(dataProvider = "invalidjavaidentifiers",
|
||||
@Test(dataProvider = "invalidNames",
|
||||
expectedExceptions = IllegalArgumentException.class )
|
||||
public void testBadModuleName(String mn, String ignore) {
|
||||
ModuleDescriptor.newModule(mn);
|
||||
@ -1264,7 +1290,7 @@ public class ModuleDescriptorTest {
|
||||
ModuleDescriptor.newModule("foo").mainClass("Main");
|
||||
}
|
||||
|
||||
@Test(dataProvider = "invalidjavaidentifiers",
|
||||
@Test(dataProvider = "invalidNames",
|
||||
expectedExceptions = IllegalArgumentException.class )
|
||||
public void testMainClassWithBadName(String mainClass, String ignore) {
|
||||
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.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -21,23 +21,141 @@
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/* @test
|
||||
* @bug 4313887 7006126
|
||||
* @summary Unit test for java.nio.file.spi.FileSystemProvider
|
||||
* @build TestProvider SetDefaultProvider
|
||||
* @run main/othervm -Djava.nio.file.spi.DefaultFileSystemProvider=TestProvider SetDefaultProvider
|
||||
/**
|
||||
* @test
|
||||
* @modules jdk.jartool
|
||||
* @library /lib/testlibrary
|
||||
* @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 static void main(String[] args) throws Exception {
|
||||
Class<?> c = FileSystems.getDefault().provider().getClass();
|
||||
|
||||
Class<?> expected = Class.forName("TestProvider", false,
|
||||
ClassLoader.getSystemClassLoader());
|
||||
private static String SET_DEFAULT_FSP =
|
||||
"-Djava.nio.file.spi.DefaultFileSystemProvider=TestProvider";
|
||||
|
||||
if (c != expected)
|
||||
throw new RuntimeException();
|
||||
private static final ToolProvider JAR_TOOL = ToolProvider.findFirst("jar")
|
||||
.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)
|
||||
throws IOException
|
||||
{
|
||||
throw new ReadOnlyFileSystemException();
|
||||
throw new RuntimeException("not implemented");
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -110,19 +110,20 @@ public class TestProvider extends FileSystemProvider {
|
||||
|
||||
@Override
|
||||
public void delete(Path file) throws IOException {
|
||||
throw new ReadOnlyFileSystemException();
|
||||
Path delegate = theFileSystem.unwrap(file);
|
||||
defaultProvider.delete(delegate);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createSymbolicLink(Path link, Path target, FileAttribute<?>... attrs)
|
||||
throws IOException
|
||||
{
|
||||
throw new ReadOnlyFileSystemException();
|
||||
throw new RuntimeException("not implemented");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createLink(Path link, Path existing) throws IOException {
|
||||
throw new ReadOnlyFileSystemException();
|
||||
throw new RuntimeException("not implemented");
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -136,14 +137,14 @@ public class TestProvider extends FileSystemProvider {
|
||||
public void copy(Path source, Path target, CopyOption... options)
|
||||
throws IOException
|
||||
{
|
||||
throw new ReadOnlyFileSystemException();
|
||||
throw new RuntimeException("not implemented");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void move(Path source, Path target, CopyOption... options)
|
||||
throws IOException
|
||||
{
|
||||
throw new ReadOnlyFileSystemException();
|
||||
throw new RuntimeException("not implemented");
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -158,7 +159,8 @@ public class TestProvider extends FileSystemProvider {
|
||||
public void createDirectory(Path dir, FileAttribute<?>... attrs)
|
||||
throws IOException
|
||||
{
|
||||
throw new ReadOnlyFileSystemException();
|
||||
Path delegate = theFileSystem.unwrap(dir);
|
||||
defaultProvider.createDirectory(delegate, attrs);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -167,13 +169,8 @@ public class TestProvider extends FileSystemProvider {
|
||||
FileAttribute<?>... attrs)
|
||||
throws IOException
|
||||
{
|
||||
if (options.contains(StandardOpenOption.READ) && options.size() == 1) {
|
||||
Path delegate = theFileSystem.unwrap(file);
|
||||
options = Collections.singleton(StandardOpenOption.READ);
|
||||
return defaultProvider.newByteChannel(delegate, options, attrs);
|
||||
}
|
||||
|
||||
throw new RuntimeException("not implemented");
|
||||
Path delegate = theFileSystem.unwrap(file);
|
||||
return defaultProvider.newByteChannel(delegate, options, attrs);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -236,7 +233,7 @@ public class TestProvider extends FileSystemProvider {
|
||||
|
||||
@Override
|
||||
public boolean isReadOnly() {
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -419,7 +416,7 @@ public class TestProvider extends FileSystemProvider {
|
||||
|
||||
@Override
|
||||
public File toFile() {
|
||||
return delegate.toFile();
|
||||
return new File(toString());
|
||||
}
|
||||
|
||||
@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
|
||||
* java.logging
|
||||
* @build jdk.testlibrary.ProcessTools
|
||||
* @run main/othervm TestLoggerWeakRefLeak Logger
|
||||
* @run main/othervm TestLoggerWeakRefLeak AnonymousLogger
|
||||
* @run main/othervm -Djdk.attach.allowAttachSelf TestLoggerWeakRefLeak Logger
|
||||
* @run main/othervm -Djdk.attach.allowAttachSelf TestLoggerWeakRefLeak AnonymousLogger
|
||||
*/
|
||||
public class TestLoggerWeakRefLeak {
|
||||
|
||||
|
@ -41,19 +41,14 @@ public class ModuleTargetHelper {
|
||||
private ModuleTargetHelper() {}
|
||||
|
||||
public static final class ModuleTarget {
|
||||
private String osName, osArch;
|
||||
private String targetPlatform;
|
||||
|
||||
public ModuleTarget(String osName, String osArch) {
|
||||
this.osName = osName;
|
||||
this.osArch = osArch;
|
||||
public ModuleTarget(String targetPlatform) {
|
||||
this.targetPlatform = targetPlatform;
|
||||
}
|
||||
|
||||
public String osName() {
|
||||
return osName;
|
||||
}
|
||||
|
||||
public String osArch() {
|
||||
return osArch;
|
||||
public String targetPlatform() {
|
||||
return targetPlatform;
|
||||
}
|
||||
}
|
||||
|
||||
@ -84,7 +79,7 @@ public class ModuleTargetHelper {
|
||||
ClassReader cr = new ClassReader(in);
|
||||
cr.accept(cv, attrs, 0);
|
||||
if (modTargets[0] != null) {
|
||||
return new ModuleTarget(modTargets[0].osName(), modTargets[0].osArch());
|
||||
return new ModuleTarget(modTargets[0].targetPlatform());
|
||||
}
|
||||
|
||||
return null;
|
||||
|
@ -37,7 +37,7 @@
|
||||
* @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.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.*;
|
||||
|
@ -221,7 +221,8 @@ public class Basic {
|
||||
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
|
||||
public void test5() throws IOException {
|
||||
// compile the mr10 directory
|
||||
@ -266,10 +267,13 @@ public class Basic {
|
||||
|
||||
jar("-d --file mr.jar");
|
||||
|
||||
String uri = (Paths.get("mr.jar")).toUri().toString();
|
||||
uri = "jar:" + uri + "/!module-info.class";
|
||||
|
||||
actual = lines(outbytes);
|
||||
expected = Set.of(
|
||||
"module hi (module-info.class)",
|
||||
"requires mandated java.base",
|
||||
"hi " + uri,
|
||||
"requires java.base mandated",
|
||||
"contains p",
|
||||
"contains p.internal"
|
||||
);
|
||||
@ -304,13 +308,19 @@ public class Basic {
|
||||
|
||||
actual = lines(outbytes);
|
||||
expected = Set.of(
|
||||
"module hi (module-info.class)",
|
||||
"requires mandated java.base",
|
||||
"hi " + uri,
|
||||
"requires java.base mandated",
|
||||
"contains p",
|
||||
"contains p.internal",
|
||||
"contains p.internal.bar"
|
||||
);
|
||||
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
|
||||
@ -399,15 +409,42 @@ public class Basic {
|
||||
Assert.assertEquals(rc, 0);
|
||||
|
||||
jar("-d --file=mmr.jar");
|
||||
System.out.println("-----------------------");
|
||||
System.out.println( new String(outbytes.toByteArray()));
|
||||
Assert.assertEquals(lines(outbytes),
|
||||
Set.of(
|
||||
"module m1 (META-INF/versions/9/module-info.class)",
|
||||
"module m1 (META-INF/versions/10/module-info.class)",
|
||||
"requires mandated java.base",
|
||||
"exports p",
|
||||
"main-class p.Main"));
|
||||
Set<String> actual = lines(outbytes);
|
||||
Set<String> expected = Set.of(
|
||||
"releases: 9 10",
|
||||
"No root module descriptor, specify --release"
|
||||
);
|
||||
Assert.assertEquals(actual, expected);
|
||||
|
||||
String uriPrefix = "jar:" + (Paths.get("mmr.jar")).toUri().toString();
|
||||
|
||||
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");
|
||||
try (ZipFile zf = new ZipFile("mmr.jar")) {
|
||||
|
@ -478,13 +478,13 @@ public class Basic {
|
||||
"--file=" + modularJar.toString())
|
||||
.assertSuccess()
|
||||
.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"
|
||||
Pattern p = Pattern.compile("module bar \\(module-info.class\\)\\s+requires\\s++foo");
|
||||
assertTrue(p.matcher(r.output).find(),
|
||||
"Expecting to find \"bar, requires foo,...\"",
|
||||
String uri = "jar:" + modularJar.toUri().toString() + "/!module-info.class";
|
||||
assertTrue(r.output.contains("bar " + uri),
|
||||
"Expecting to find \"bar " + uri + "\"",
|
||||
"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");
|
||||
assertTrue(p.matcher(r.output).find(),
|
||||
"Expecting to find \"contains jdk.test.foo,...\"",
|
||||
@ -758,14 +758,15 @@ public class Basic {
|
||||
for (String option : new String[] {"--describe-module", "-d" }) {
|
||||
|
||||
jar(option,
|
||||
"--file=" + modularJar.toString())
|
||||
"--file=" + modularJar.toString(),
|
||||
"--release", "9")
|
||||
.assertSuccess()
|
||||
.resultChecker(r ->
|
||||
assertTrue(r.output.contains("main-class jdk.test.baz.Baz"),
|
||||
"Expected to find ", "main-class jdk.test.baz.Baz",
|
||||
" in [", r.output, "]"));
|
||||
|
||||
jarWithStdin(modularJar.toFile(), option)
|
||||
jarWithStdin(modularJar.toFile(), option, "--release", "9")
|
||||
.assertSuccess()
|
||||
.resultChecker(r ->
|
||||
assertTrue(r.output.contains("main-class jdk.test.baz.Baz"),
|
||||
@ -773,7 +774,7 @@ public class Basic {
|
||||
" in [", r.output, "]"));
|
||||
|
||||
}
|
||||
// run module maain class
|
||||
// run module main class
|
||||
java(mp, "baz/jdk.test.baz.Baz")
|
||||
.assertSuccess()
|
||||
.resultChecker(r ->
|
||||
@ -900,7 +901,7 @@ public class Basic {
|
||||
.resultChecker(r -> {
|
||||
assertTrue(r.output.contains("No module descriptor found"));
|
||||
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, "]");
|
||||
}
|
||||
);
|
||||
|
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_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"))) {
|
||||
throw new AssertionError("Post processing not called");
|
||||
|
@ -178,7 +178,7 @@ public class JLinkNegativeTest {
|
||||
.output(imageFile)
|
||||
.addMods("not_zip")
|
||||
.modulePath(helper.defaultModulePath())
|
||||
.call().assertFailure("Error: java.util.zip.ZipException: zip file is empty");
|
||||
.call().assertFailure("Error: Error reading");
|
||||
} finally {
|
||||
deleteDirectory(jar);
|
||||
}
|
||||
|
@ -113,12 +113,13 @@ public class SystemModulesTest {
|
||||
try {
|
||||
if (modRef.descriptor().name().equals("java.base")) {
|
||||
ModuleTargetHelper.ModuleTarget mt = ModuleTargetHelper.read(modRef);
|
||||
assertTrue(checkOSName(mt.osName()));
|
||||
assertTrue(checkOSArch(mt.osArch()));
|
||||
String[] values = mt.targetPlatform().split("-");
|
||||
assertTrue(checkOSName(values[0]));
|
||||
assertTrue(checkOSArch(values[1]));
|
||||
} else {
|
||||
// target platform attribute is dropped by jlink plugin for other modules
|
||||
ModuleTargetHelper.ModuleTarget mt = ModuleTargetHelper.read(modRef);
|
||||
assertTrue(mt == null || (mt.osName() == null && mt.osArch() == null));
|
||||
assertTrue(mt == null || mt.targetPlatform() == null);
|
||||
}
|
||||
} catch (IOException exp) {
|
||||
throw new UncheckedIOException(exp);
|
||||
|
@ -220,16 +220,16 @@ public class UserModuleTest {
|
||||
throw new RuntimeException("ModuleTarget is missing for java.base");
|
||||
}
|
||||
|
||||
String osName = mt.osName();
|
||||
String osArch = mt.osArch();
|
||||
String[] values = mt.targetPlatform().split("-");
|
||||
String osName = values[0];
|
||||
String osArch = values[1];
|
||||
|
||||
// create JMOD files
|
||||
Files.createDirectories(JMODS_DIR);
|
||||
Stream.of(modules).forEach(mn ->
|
||||
assertTrue(jmod("create",
|
||||
"--class-path", MODS_DIR.resolve(mn).toString(),
|
||||
"--os-name", osName,
|
||||
"--os-arch", osArch,
|
||||
"--target-platform", mt.targetPlatform(),
|
||||
"--main-class", mn.replace('m', 'p') + ".Main",
|
||||
JMODS_DIR.resolve(mn + ".jmod").toString()) == 0)
|
||||
);
|
||||
|
@ -62,8 +62,7 @@ public class Main {
|
||||
// parse module-info.class
|
||||
ClassReader cr = new ClassReader(in);
|
||||
cr.accept(cv, attrs, 0);
|
||||
return modTargets[0] != null &&
|
||||
(modTargets[0].osName() != null || modTargets[0].osArch() != null);
|
||||
return modTargets[0] != null && modTargets[0].targetPlatform() != null;
|
||||
}
|
||||
|
||||
public static void main(String... args) throws Exception {
|
||||
|
@ -63,8 +63,7 @@ public class Main {
|
||||
// parse module-info.class
|
||||
ClassReader cr = new ClassReader(in);
|
||||
cr.accept(cv, attrs, 0);
|
||||
return modTargets[0] != null &&
|
||||
(modTargets[0].osName() != null || modTargets[0].osArch() != null);
|
||||
return modTargets[0] != null && modTargets[0].targetPlatform() != null;
|
||||
}
|
||||
|
||||
private static boolean hasModuleTarget(String modName) throws IOException {
|
||||
|
@ -393,16 +393,17 @@ public class JmodTest {
|
||||
MODS_DIR.resolve("describeFoo.jmod").toString())
|
||||
.assertSuccess()
|
||||
.resultChecker(r -> {
|
||||
// Expect similar output: "foo, requires mandated java.base
|
||||
// exports jdk.test.foo, contains jdk.test.foo.internal"
|
||||
Pattern p = Pattern.compile("\\s+foo\\s+requires\\s+mandated\\s+java.base");
|
||||
// Expect similar output: "foo... exports jdk.test.foo ...
|
||||
// ... requires java.base mandated... contains jdk.test.foo.internal"
|
||||
Pattern p = Pattern.compile("foo\\s+exports\\s+jdk.test.foo");
|
||||
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 + "]");
|
||||
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(),
|
||||
"Expecting to find \"exports ..., contains ...\"" +
|
||||
"Expecting to find \"requires java.base mandated..., " +
|
||||
"contains jdk.test.foo.internal ...\"" +
|
||||
"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.
|
||||
*
|
||||
* 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.Paths;
|
||||
|
||||
import static jdk.testlibrary.ProcessTools.*;
|
||||
import jdk.testlibrary.ProcessTools;
|
||||
import jdk.testlibrary.OutputAnalyzer;
|
||||
|
||||
import org.testng.annotations.BeforeTest;
|
||||
@ -66,138 +66,80 @@ public class ListModsTest {
|
||||
SRC_DIR.resolve("java.transaction"),
|
||||
UPGRADEMODS_DIR.resolve("java.transaction"));
|
||||
assertTrue(compiled);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testListAll() throws Exception {
|
||||
OutputAnalyzer output
|
||||
= executeTestJava("--list-modules")
|
||||
.outputTo(System.out)
|
||||
.errorTo(System.out);
|
||||
output.shouldContain("java.base");
|
||||
output.shouldContain("java.xml");
|
||||
assertTrue(output.getExitValue() == 0);
|
||||
exec("--list-modules")
|
||||
.shouldContain("java.base")
|
||||
.shouldContain("java.xml")
|
||||
.shouldHaveExitValue(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
|
||||
public void testListWithModulePath() throws Exception {
|
||||
OutputAnalyzer output
|
||||
= executeTestJava("--module-path", MODS_DIR.toString(), "--list-modules")
|
||||
.outputTo(System.out)
|
||||
.errorTo(System.out);
|
||||
output.shouldContain("java.base");
|
||||
output.shouldContain("m1");
|
||||
assertTrue(output.getExitValue() == 0);
|
||||
exec("--list-modules", "--module-path", MODS_DIR.toString())
|
||||
.shouldContain("java.base")
|
||||
.shouldContain("m1")
|
||||
.shouldHaveExitValue(0);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testListWithUpgradeModulePath() throws Exception {
|
||||
OutputAnalyzer output
|
||||
= executeTestJava("--upgrade-module-path", UPGRADEMODS_DIR.toString(),
|
||||
"--list-modules", "java.transaction")
|
||||
.outputTo(System.out)
|
||||
.errorTo(System.out);
|
||||
output.shouldContain("exports javax.transaction.atomic");
|
||||
assertTrue(output.getExitValue() == 0);
|
||||
String dir = UPGRADEMODS_DIR.toString();
|
||||
exec("--list-modules", "--upgrade-module-path", dir)
|
||||
.shouldContain(UPGRADEMODS_DIR.toString())
|
||||
.shouldHaveExitValue(0);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testListWithLimitMods1() throws Exception {
|
||||
OutputAnalyzer output
|
||||
= executeTestJava("--limit-modules", "java.management.rmi", "--list-modules")
|
||||
.outputTo(System.out)
|
||||
.errorTo(System.out);
|
||||
output.shouldContain("java.rmi");
|
||||
output.shouldContain("java.base");
|
||||
output.shouldNotContain("java.scripting");
|
||||
assertTrue(output.getExitValue() == 0);
|
||||
exec("--limit-modules", "java.management.rmi", "--list-modules")
|
||||
.shouldContain("java.rmi")
|
||||
.shouldContain("java.base")
|
||||
.shouldNotContain("java.scripting")
|
||||
.shouldHaveExitValue(0);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testListWithLimitMods2() throws Exception {
|
||||
OutputAnalyzer output
|
||||
= executeTestJava("--module-path", MODS_DIR.toString(),
|
||||
"--limit-modules", "java.management",
|
||||
"--list-modules")
|
||||
.outputTo(System.out)
|
||||
.errorTo(System.out);
|
||||
output.shouldContain("java.base");
|
||||
output.shouldNotContain("m1");
|
||||
assertTrue(output.getExitValue() == 0);
|
||||
exec("--list-modules",
|
||||
"--module-path", MODS_DIR.toString(),
|
||||
"--limit-modules", "java.management")
|
||||
.shouldContain("java.base")
|
||||
.shouldNotContain("m1")
|
||||
.shouldHaveExitValue(0);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* java -version --list-modules => should print version and exit
|
||||
*/
|
||||
@Test
|
||||
public void testListWithPrintVersion1() throws Exception {
|
||||
OutputAnalyzer output
|
||||
= executeTestJava("-version", "--list-modules")
|
||||
.outputTo(System.out)
|
||||
.errorTo(System.out);
|
||||
output.shouldNotContain("java.base");
|
||||
output.shouldContain("Runtime Environment");
|
||||
assertTrue(output.getExitValue() == 0);
|
||||
exec("-version", "--list-modules")
|
||||
.shouldNotContain("java.base")
|
||||
.shouldContain("Runtime Environment")
|
||||
.shouldHaveExitValue(0);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* java --list-modules -version => should list modules and exit
|
||||
*/
|
||||
@Test
|
||||
public void testListWithPrintVersion2() throws Exception {
|
||||
OutputAnalyzer output
|
||||
= executeTestJava("--list-modules", "-version")
|
||||
exec("--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)
|
||||
.errorTo(System.out);
|
||||
output.shouldContain("java.base");
|
||||
output.shouldNotContain("Runtime Environment");
|
||||
assertTrue(output.getExitValue() == 0);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -23,5 +23,4 @@
|
||||
|
||||
module java.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