This commit is contained in:
Alan Bateman 2017-05-04 09:43:09 +01:00
commit 853c626781
104 changed files with 3461 additions and 1162 deletions

View File

@ -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:
*;
};

View File

@ -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
*

View File

@ -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();

View File

@ -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;

View File

@ -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();
}

View File

@ -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;

View File

@ -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();
}
/**

View File

@ -99,6 +99,7 @@ public class ModuleDescriptor
*
* @see ModuleDescriptor#modifiers()
* @since 9
* @spec JPMS
*/
public static enum Modifier {
/**

View File

@ -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

View File

@ -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();
}
}

View File

@ -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;

View File

@ -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;
}

View File

@ -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
*/

View File

@ -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",
"_"
);
}

View File

@ -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;
}

View File

@ -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.

View File

@ -138,7 +138,7 @@ public class ModuleHashesBuilder {
}
/*
* Utilty class
* Utility class
*/
static class Graph<T> {
private final Set<T> nodes;

View File

@ -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.

View File

@ -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)

View File

@ -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();

View File

@ -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);
}
}

View File

@ -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;
}

View File

@ -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

View File

@ -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) {

View File

@ -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;
}

View File

@ -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;
}
}

View File

@ -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&trade;
@ -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;
}

View File

@ -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

View File

@ -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,

View File

@ -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();
}
}
}
}

View File

@ -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

View File

@ -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

View File

@ -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);
}
/*

View File

@ -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}

View File

@ -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>

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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);
}
}
}

View File

@ -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

View File

@ -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) {

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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);
}

View File

@ -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);
}
}

View File

@ -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);

View File

@ -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());

View File

@ -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

View File

@ -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=\

View File

@ -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);

View File

@ -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() {

View File

@ -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;
}

View File

@ -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() {

View File

@ -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)

View File

@ -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);
}

View File

@ -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.

View File

@ -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)) {

View File

@ -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\

View File

@ -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");

View 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();
}
}
}

View File

@ -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);

View File

@ -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";

View 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) {
}
}

View 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.
*/

View File

@ -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;
}

View 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, '/');
}
}

View 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;
}
}

View 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 {
}

View File

@ -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);
}
}

View 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");
}
}

View File

@ -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);
}
/**

View File

@ -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());
}

View File

@ -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");

View File

@ -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");

View File

@ -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;
}
}

View 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;
}

View 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();
}
}

View 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;
}

View 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");
}
}

View File

@ -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();
}
}

View File

@ -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

View 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 {
}

View 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);
}
}

View File

@ -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 {

View File

@ -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;

View File

@ -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.*;

View File

@ -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")) {

View File

@ -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, "]");
}
);

View 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
*/

View File

@ -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);
}
}

View File

@ -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");

View File

@ -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);
}

View File

@ -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);

View File

@ -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)
);

View File

@ -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 {

View File

@ -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 {

View File

@ -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 + "]");
});
}

View 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");
}
}

View File

@ -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);
}
}

View File

@ -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