This commit is contained in:
Jesper Wilhelmsson 2017-03-30 19:55:04 +02:00
commit 2c1bc6bfa8
94 changed files with 1753 additions and 380 deletions

View File

@ -405,3 +405,4 @@ c476ca73750698fa5654e101af699ee45db38e2a jdk-9+158
cac788454598b95d8b0153c021a7fae3cd7e6fda jdk-9+160
09b92d3067a38ee07bc14efa336b14790c93f7e7 jdk-9+161
f6bf027e88e9a4dd19f721001a7af00157af42c4 jdk-9+162
50171f8c47961710cbf87aead6f03fa431d8d240 jdk-9+163

View File

@ -1,5 +1,5 @@
#
# Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
# Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
@ -31,7 +31,7 @@ include MakeBase.gmk
include ModuleTools.gmk
GENGRAPHS_DIR := $(IMAGES_OUTPUTDIR)/gengraphs
SPEC_DOTFILES_DIR := $(IMAGES_OUTPUTDIR)/spec-dotfiles
SPEC_DOTFILES_DIR := $(GENGRAPHS_DIR)/spec-dotfiles
TOOLS_MODULE_SRCDIR := $(JDK_TOPDIR)/make/src/classes/build/tools/jigsaw
$(GENGRAPHS_DIR)/jdk.dot: $(BUILD_JIGSAW_TOOLS)

View File

@ -1,5 +1,5 @@
#
# Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
# Copyright (c) 2013, 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
@ -23,8 +23,9 @@
# questions.
#
include $(SPEC)
include MakeBase.gmk
ifndef _MODULE_TOOLS_GMK
_MODULE_TOOLS_GMK := 1
include JavaCompilation.gmk
TOOLS_CLASSES_DIR := $(BUILDTOOLS_OUTPUTDIR)/tools_jigsaw_classes
@ -32,7 +33,7 @@ TOOLS_CLASSES_DIR := $(BUILDTOOLS_OUTPUTDIR)/tools_jigsaw_classes
# To avoid reevaluating the compilation setup for the tools each time this file
# is included, the actual compilation is handled by CompileModuleTools.gmk. The
# following trick is used to be able to declare a dependency on the built tools.
BUILD_TOOLS_JDK := $(call SetupJavaCompilationCompileTarget, \
BUILD_JIGSAW_TOOLS := $(call SetupJavaCompilationCompileTarget, \
BUILD_JIGSAW_TOOLS, $(TOOLS_CLASSES_DIR))
TOOL_GENGRAPHS := $(BUILD_JAVA) -esa -ea -cp $(TOOLS_CLASSES_DIR) \
@ -47,3 +48,5 @@ TOOL_ADD_PACKAGES_ATTRIBUTE := $(BUILD_JAVA) $(JAVA_FLAGS_SMALL) \
-cp $(TOOLS_CLASSES_DIR) \
--add-exports java.base/jdk.internal.module=ALL-UNNAMED \
build.tools.jigsaw.AddPackagesAttribute
endif # _MODULE_TOOLS_GMK

View File

@ -26,7 +26,6 @@
package build.tools.jigsaw;
import com.sun.tools.jdeps.ModuleDotGraph;
import com.sun.tools.jdeps.ModuleDotGraph.DotGraphBuilder;
import java.io.IOException;
import java.lang.module.Configuration;
@ -36,10 +35,15 @@ import java.lang.module.ModuleReference;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;
/**
* Generate the DOT file for a module graph for each module in the JDK
@ -50,13 +54,19 @@ public class GenGraphs {
public static void main(String[] args) throws Exception {
Path dir = null;
boolean spec = false;
Properties props = null;
for (int i=0; i < args.length; i++) {
String arg = args[i];
if (arg.equals("--spec")) {
spec = true;
} else if (arg.equals("--dot-attributes")) {
if (i++ == args.length) {
throw new IllegalArgumentException("Missing argument: --dot-attributes option");
}
props = new Properties();
props.load(Files.newInputStream(Paths.get(args[i])));
} else if (arg.equals("--output")) {
i++;
dir = i < args.length ? Paths.get(args[i]) : null;
dir = ++i < args.length ? Paths.get(args[i]) : null;
} else if (arg.startsWith("-")) {
throw new IllegalArgumentException("Invalid option: " + arg);
}
@ -67,11 +77,14 @@ public class GenGraphs {
System.exit(1);
}
// setup and configure the dot graph attributes
initDotGraphAttributes();
Files.createDirectories(dir);
GenGraphs genGraphs = new GenGraphs(dir, spec);
ModuleGraphAttributes attributes;
if (props != null) {
attributes = new ModuleGraphAttributes(props);
} else {
attributes = new ModuleGraphAttributes();
}
GenGraphs genGraphs = new GenGraphs(dir, spec, attributes);
// print dot file for each module
Map<String, Configuration> configurations = new HashMap<>();
@ -99,49 +112,149 @@ public class GenGraphs {
genGraphs.genDotFiles(configurations);
}
static void initDotGraphAttributes() {
int h = 1000;
DotGraphBuilder.weight("java.se", "java.sql.rowset", h * 10);
DotGraphBuilder.weight("java.sql.rowset", "java.sql", h * 10);
DotGraphBuilder.weight("java.sql", "java.xml", h * 10);
DotGraphBuilder.weight("java.xml", "java.base", h * 10);
/**
* Custom dot file attributes.
*/
static class ModuleGraphAttributes implements ModuleDotGraph.Attributes {
static Map<String, String> DEFAULT_ATTRIBUTES = Map.of(
"ranksep", "0.6",
"fontsize", "12",
"fontcolor", BLACK,
"fontname", "DejaVuSans",
"arrowsize", "1",
"arrowwidth", "2",
"arrowcolor", DARK_GRAY,
// custom
"requiresMandatedColor", LIGHT_GRAY,
"javaSubgraphColor", ORANGE,
"jdkSubgraphColor", BLUE
);
DotGraphBuilder.sameRankNodes(Set.of("java.logging", "java.scripting", "java.xml"));
DotGraphBuilder.sameRankNodes(Set.of("java.sql"));
DotGraphBuilder.sameRankNodes(Set.of("java.compiler", "java.instrument"));
DotGraphBuilder.sameRankNodes(Set.of("java.desktop", "java.management"));
DotGraphBuilder.sameRankNodes(Set.of("java.corba", "java.xml.ws"));
DotGraphBuilder.sameRankNodes(Set.of("java.xml.bind", "java.xml.ws.annotation"));
DotGraphBuilder.setRankSep(0.7);
DotGraphBuilder.setFontSize(12);
DotGraphBuilder.setArrowSize(1);
DotGraphBuilder.setArrowWidth(2);
final Map<String, Integer> weights = new HashMap<>();
final List<Set<String>> ranks = new ArrayList<>();
final Map<String, String> attrs;
ModuleGraphAttributes(Map<String, String> attrs) {
int h = 1000;
weight("java.se", "java.sql.rowset", h * 10);
weight("java.sql.rowset", "java.sql", h * 10);
weight("java.sql", "java.xml", h * 10);
weight("java.xml", "java.base", h * 10);
ranks.add(Set.of("java.logging", "java.scripting", "java.xml"));
ranks.add(Set.of("java.sql"));
ranks.add(Set.of("java.compiler", "java.instrument"));
ranks.add(Set.of("java.desktop", "java.management"));
ranks.add(Set.of("java.corba", "java.xml.ws"));
ranks.add(Set.of("java.xml.bind", "java.xml.ws.annotation"));
this.attrs = attrs;
}
ModuleGraphAttributes() {
this(DEFAULT_ATTRIBUTES);
}
ModuleGraphAttributes(Properties props) {
this(toAttributes(props));
}
@Override
public double rankSep() {
return Double.valueOf(attrs.get("ranksep"));
}
@Override
public int fontSize() {
return Integer.valueOf(attrs.get("fontsize"));
}
@Override
public String fontName() {
return attrs.get("fontname");
}
@Override
public String fontColor() {
return attrs.get("fontcolor");
}
@Override
public int arrowSize() {
return Integer.valueOf(attrs.get("arrowsize"));
}
@Override
public int arrowWidth() {
return Integer.valueOf(attrs.get("arrowwidth"));
}
@Override
public String arrowColor() {
return attrs.get("arrowcolor");
}
@Override
public List<Set<String>> ranks() {
return ranks;
}
@Override
public String requiresMandatedColor() {
return attrs.get("requiresMandatedColor");
}
@Override
public String javaSubgraphColor() {
return attrs.get("javaSubgraphColor");
}
@Override
public String jdkSubgraphColor() {
return attrs.get("jdkSubgraphColor");
}
@Override
public int weightOf(String s, String t) {
int w = weights.getOrDefault(s + ":" + t, 1);
if (w != 1)
return w;
if (s.startsWith("java.") && t.startsWith("java."))
return 10;
return 1;
}
public void weight(String s, String t, int w) {
weights.put(s + ":" + t, w);
}
static Map<String, String> toAttributes(Properties props) {
return DEFAULT_ATTRIBUTES.keySet().stream()
.collect(Collectors.toMap(Function.identity(),
k -> props.getProperty(k, DEFAULT_ATTRIBUTES.get(k))));
}
}
private final Path dir;
private final boolean spec;
GenGraphs(Path dir, boolean spec) {
private final ModuleGraphAttributes attributes;
GenGraphs(Path dir, boolean spec, ModuleGraphAttributes attributes) {
this.dir = dir;
this.spec = spec;
this.attributes = attributes;
}
void genDotFiles(Map<String, Configuration> configurations) throws IOException {
ModuleDotGraph dotGraph = new ModuleDotGraph(configurations, spec);
dotGraph.genDotFiles(dir);
dotGraph.genDotFiles(dir, attributes);
}
/**
* Returns true for any name if generating graph for non-spec;
* otherwise, returns true except "jdk" and name with "jdk.internal." prefix
*/
boolean accept(String name, ModuleDescriptor descriptor) {
if (!spec) return true;
if (name.equals("jdk"))
return false;
if (name.equals("java.se") || name.equals("java.se.ee"))
if (!spec)
return true;
// only the module that has exported API
return descriptor.exports().stream()
.filter(e -> !e.isQualified())
.findAny().isPresent();
return !name.equals("jdk") && !name.startsWith("jdk.internal.");
}
}
}

View File

@ -0,0 +1,2 @@
arrowcolor=#999999
requiresMandatedColor=#999999

View File

@ -0,0 +1,96 @@
/*
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package build.tools.taglet;
import java.util.EnumSet;
import java.util.List;
import java.util.Set;
import javax.lang.model.element.Element;
import com.sun.source.doctree.DocTree;
import jdk.javadoc.doclet.Taglet;
import static jdk.javadoc.doclet.Taglet.Location.*;
/**
* A block tag to optionally insert a reference to a module graph.
*/
public class ModuleGraph implements Taglet {
private static final boolean enableModuleGraph =
Boolean.getBoolean("enableModuleGraph");
/** Returns the set of locations in which a taglet may be used. */
@Override
public Set<Location> getAllowedLocations() {
return EnumSet.of(MODULE);
}
@Override
public boolean isInlineTag() {
return false;
}
@Override
public String getName() {
return "moduleGraph";
}
@Override
public String toString(List<? extends DocTree> tags, Element element) {
if (!enableModuleGraph) {
return "";
}
String moduleName = element.getSimpleName().toString();
String imageFile = moduleName + "-graph.png";
int thumbnailHeight = -1;
String hoverImage = "";
if (!moduleName.equals("java.base")) {
thumbnailHeight = 100; // also appears in the stylesheet
hoverImage = "<span>"
+ getImage(moduleName, imageFile, -1, true)
+ "</span>";
}
return "<dt>"
+ "<span class=\"simpleTagLabel\">Module Graph:</span>\n"
+ "</dt>"
+ "<dd>"
+ "<a class=moduleGraph href=\"" + imageFile + "\">"
+ getImage(moduleName, imageFile, thumbnailHeight, false)
+ hoverImage
+ "</a>"
+ "</dd>";
}
private static final String VERTICAL_ALIGN = "vertical-align:top";
private static final String BORDER = "border: solid lightgray 1px;";
private String getImage(String moduleName, String file, int height, boolean useBorder) {
return String.format("<img style=\"%s\" alt=\"Module graph for %s\" src=\"%s\"%s>",
useBorder ? BORDER + " " + VERTICAL_ALIGN : VERTICAL_ALIGN,
moduleName,
file,
(height <= 0 ? "" : " height=\"" + height + "\""));
}
}

View File

@ -2672,7 +2672,6 @@ public final class String
* point</a> is passed through uninterpreted.
*
* @return an IntStream of char values from this sequence
* @since 9
*/
@Override
public IntStream chars() {
@ -2692,7 +2691,6 @@ public final class String
* {@code int} values which are then passed to the stream.
*
* @return an IntStream of Unicode code points from this sequence
* @since 9
*/
@Override
public IntStream codePoints() {

View File

@ -1568,6 +1568,14 @@ public final class System {
* obtained by calling {@link LoggerFinder#getLogger(java.lang.String,
* java.lang.reflect.Module) LoggerFinder.getLogger(name, module)}, where
* {@code module} is the caller's module.
* In cases where {@code System.getLogger} is called from a context where
* there is no caller frame on the stack (e.g when called directly
* from a JNI attached thread), {@code IllegalCallerException} is thrown.
* To obtain a logger in such a context, use an auxiliary class that will
* implicitly be identified as the caller, or use the system {@link
* LoggerFinder#getLoggerFinder() LoggerFinder} to obtain a logger instead.
* Note that doing the latter may eagerly initialize the underlying
* logging system.
*
* @apiNote
* This method may defer calling the {@link
@ -1580,6 +1588,8 @@ public final class System {
* @return an instance of {@link Logger} that can be used by the calling
* class.
* @throws NullPointerException if {@code name} is {@code null}.
* @throws IllegalCallerException if there is no Java caller frame on the
* stack.
*
* @since 9
*/
@ -1587,6 +1597,9 @@ public final class System {
public static Logger getLogger(String name) {
Objects.requireNonNull(name);
final Class<?> caller = Reflection.getCallerClass();
if (caller == null) {
throw new IllegalCallerException("no caller frame");
}
return LazyLoggers.getLogger(name, caller.getModule());
}
@ -1600,8 +1613,16 @@ public final class System {
* The returned logger will perform message localization as specified
* by {@link LoggerFinder#getLocalizedLogger(java.lang.String,
* java.util.ResourceBundle, java.lang.reflect.Module)
* LoggerFinder.getLocalizedLogger(name, bundle, module}, where
* LoggerFinder.getLocalizedLogger(name, bundle, module)}, where
* {@code module} is the caller's module.
* In cases where {@code System.getLogger} is called from a context where
* there is no caller frame on the stack (e.g when called directly
* from a JNI attached thread), {@code IllegalCallerException} is thrown.
* To obtain a logger in such a context, use an auxiliary class that
* will implicitly be identified as the caller, or use the system {@link
* LoggerFinder#getLoggerFinder() LoggerFinder} to obtain a logger instead.
* Note that doing the latter may eagerly initialize the underlying
* logging system.
*
* @apiNote
* This method is intended to be used after the system is fully initialized.
@ -1620,6 +1641,8 @@ public final class System {
* resource bundle for message localization.
* @throws NullPointerException if {@code name} is {@code null} or
* {@code bundle} is {@code null}.
* @throws IllegalCallerException if there is no Java caller frame on the
* stack.
*
* @since 9
*/
@ -1628,6 +1651,9 @@ public final class System {
final ResourceBundle rb = Objects.requireNonNull(bundle);
Objects.requireNonNull(name);
final Class<?> caller = Reflection.getCallerClass();
if (caller == null) {
throw new IllegalCallerException("no caller frame");
}
final SecurityManager sm = System.getSecurityManager();
// We don't use LazyLoggers if a resource bundle is specified.
// Bootstrap sensitive classes in the JDK do not use resource bundles

View File

@ -174,7 +174,6 @@ public final class Constructor<T> extends Executable {
* @throws SecurityException if the request is denied by the security manager
* or this is a constructor for {@code java.lang.Class}
*
* @since 9
* @spec JPMS
*/
@Override

View File

@ -213,7 +213,6 @@ public abstract class MappedByteBuffer
/**
* {@inheritDoc}
* @since 9
*/
@Override
public final MappedByteBuffer position(int newPosition) {
@ -223,7 +222,6 @@ public abstract class MappedByteBuffer
/**
* {@inheritDoc}
* @since 9
*/
@Override
public final MappedByteBuffer limit(int newLimit) {
@ -233,7 +231,6 @@ public abstract class MappedByteBuffer
/**
* {@inheritDoc}
* @since 9
*/
@Override
public final MappedByteBuffer mark() {
@ -243,7 +240,6 @@ public abstract class MappedByteBuffer
/**
* {@inheritDoc}
* @since 9
*/
@Override
public final MappedByteBuffer reset() {
@ -253,7 +249,6 @@ public abstract class MappedByteBuffer
/**
* {@inheritDoc}
* @since 9
*/
@Override
public final MappedByteBuffer clear() {
@ -263,7 +258,6 @@ public abstract class MappedByteBuffer
/**
* {@inheritDoc}
* @since 9
*/
@Override
public final MappedByteBuffer flip() {
@ -273,7 +267,6 @@ public abstract class MappedByteBuffer
/**
* {@inheritDoc}
* @since 9
*/
@Override
public final MappedByteBuffer rewind() {

View File

@ -1069,7 +1069,6 @@ public abstract class $Type$Buffer
/**
* {@inheritDoc}
* @since 9
*/
@Override
public
@ -1083,7 +1082,6 @@ public abstract class $Type$Buffer
/**
* {@inheritDoc}
* @since 9
*/
@Override
public
@ -1097,7 +1095,6 @@ public abstract class $Type$Buffer
/**
* {@inheritDoc}
* @since 9
*/
@Override
public
@ -1111,7 +1108,6 @@ public abstract class $Type$Buffer
/**
* {@inheritDoc}
* @since 9
*/
@Override
public
@ -1125,7 +1121,6 @@ public abstract class $Type$Buffer
/**
* {@inheritDoc}
* @since 9
*/
@Override
public
@ -1139,7 +1134,6 @@ public abstract class $Type$Buffer
/**
* {@inheritDoc}
* @since 9
*/
@Override
public
@ -1153,7 +1147,6 @@ public abstract class $Type$Buffer
/**
* {@inheritDoc}
* @since 9
*/
@Override
public

View File

@ -651,8 +651,6 @@ public class SecureRandom extends java.util.Random {
* {@code SecureRandom}.
*
* @return the string representation
*
* @since 9
*/
@Override
public String toString() {

View File

@ -211,8 +211,6 @@ public abstract class SecureRandomSpi implements java.io.Serializable {
* {@code SecureRandom}.
*
* @return the string representation
*
* @since 9
*/
@Override
public String toString() {

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 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
@ -310,8 +310,8 @@ public interface Era extends TemporalAccessor, TemporalAdjuster {
* The parameters control the style of the returned text and the locale.
* <p>
* If no textual mapping is found then the {@link #getValue() numeric value} is returned.
* <p>
* This default implementation is suitable for all implementations.
*
* @apiNote This default implementation is suitable for most implementations.
*
* @param style the style of the text required, not null
* @param locale the locale to use, not null

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 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
@ -240,19 +240,10 @@ public final class JapaneseEra
}
/**
* Gets the textual representation of this era.
* <p>
* This returns the textual name used to identify the era,
* suitable for presentation to the user.
* The parameters control the style of the returned text and the locale.
* <p>
* If no textual mapping is found then the {@link #getValue() numeric value}
* is returned.
* {@inheritDoc}
*
* @param style the style of the text required, not null
* @param locale the locale to use, not null
* @return the text value of the era, not null
* @since 9
* @param style {@inheritDoc}
* @param locale {@inheritDoc}
*/
@Override
public String getDisplayName(TextStyle style, Locale locale) {

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2003, 2014, 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
@ -452,13 +452,13 @@ public abstract class Pack200 {
String CODE_ATTRIBUTE_PFX = "pack.code.attribute.";
/**
* The unpacker's progress as a percentage, as periodically
* updated by the unpacker.
* The packer's progress as a percentage, as periodically
* updated by the packer.
* Values of 0 - 100 are normal, and -1 indicates a stall.
* Progress can be monitored by polling the value of this
* property.
* <p>
* At a minimum, the unpacker must set progress to 0
* At a minimum, the packer must set progress to 0
* at the beginning of a packing operation, and to 100
* at the end.
*/
@ -623,7 +623,7 @@ public abstract class Pack200 {
* property.
* <p>
* At a minimum, the unpacker must set progress to 0
* at the beginning of a packing operation, and to 100
* at the beginning of an unpacking operation, and to 100
* at the end.
*/
String PROGRESS = "unpack.progress";
@ -631,7 +631,7 @@ public abstract class Pack200 {
/**
* Get the set of this engine's properties. This set is
* a "live view", so that changing its
* contents immediately affects the Packer engine, and
* contents immediately affects the Unpacker engine, and
* changes from the engine (such as progress indications)
* are immediately visible in the map.
*

View File

@ -25,6 +25,7 @@
package jdk.internal.module;
import java.io.PrintStream;
import java.lang.invoke.MethodHandles;
import java.lang.reflect.Module;
import java.net.URL;
@ -42,6 +43,9 @@ import java.util.WeakHashMap;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import jdk.internal.loader.BootLoader;
import sun.security.action.GetPropertyAction;
/**
* Supports logging of access to members of API packages that are exported or
* opened via backdoor mechanisms to code in unnamed modules.
@ -49,15 +53,24 @@ import java.util.stream.Collectors;
public final class IllegalAccessLogger {
// true to print stack trace
private static final boolean PRINT_STACK_TRACE;
static {
String s = System.getProperty("sun.reflect.debugModuleAccessChecks");
PRINT_STACK_TRACE = "access".equals(s);
}
/**
* Holder class to lazily create the StackWalker object and determine
* if the stack trace should be printed
*/
static class Holder {
static final StackWalker STACK_WALKER;
static final boolean PRINT_STACK_TRACE;
private static final StackWalker STACK_WALKER
= StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE);
static {
PrivilegedAction<StackWalker> pa = () ->
StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE);
STACK_WALKER = AccessController.doPrivileged(pa);
String name = "sun.reflect.debugModuleAccessChecks";
String value = GetPropertyAction.privilegedGetProperty(name, null);
PRINT_STACK_TRACE = "access" .equals(value);
}
}
// the maximum number of frames to capture
private static final int MAX_STACK_FRAMES = 32;
@ -72,10 +85,15 @@ public final class IllegalAccessLogger {
private final Map<Module, Map<String, String>> exported;
private final Map<Module, Map<String, String>> opened;
// the print stream to send the warnings
private final PrintStream warningStream;
private IllegalAccessLogger(Map<Module, Map<String, String>> exported,
Map<Module, Map<String, String>> opened) {
Map<Module, Map<String, String>> opened,
PrintStream warningStream) {
this.exported = deepCopy(exported);
this.opened = deepCopy(opened);
this.warningStream = warningStream;
}
/**
@ -168,7 +186,7 @@ public final class IllegalAccessLogger {
*/
private void log(Class<?> caller, String what, Supplier<String> msgSupplier) {
// stack trace without the top-most frames in java.base
List<StackWalker.StackFrame> stack = STACK_WALKER.walk(s ->
List<StackWalker.StackFrame> stack = Holder.STACK_WALKER.walk(s ->
s.dropWhile(this::isJavaBase)
.limit(MAX_STACK_FRAMES)
.collect(Collectors.toList())
@ -184,13 +202,13 @@ public final class IllegalAccessLogger {
// log message if first usage
if (firstUsage) {
String msg = msgSupplier.get();
if (PRINT_STACK_TRACE) {
if (Holder.PRINT_STACK_TRACE) {
synchronized (OUTPUT_LOCK) {
System.err.println(msg);
stack.forEach(f -> System.err.println("\tat " + f));
warningStream.println(msg);
stack.forEach(f -> warningStream.println("\tat " + f));
}
} else {
System.err.println(msg);
warningStream.println(msg);
}
}
}
@ -265,8 +283,10 @@ public final class IllegalAccessLogger {
* A builder for IllegalAccessLogger objects.
*/
public static class Builder {
private final Module UNNAMED = BootLoader.getUnnamedModule();
private Map<Module, Map<String, String>> exported;
private Map<Module, Map<String, String>> opened;
private PrintStream warningStream = System.err;
public Builder() { }
@ -276,30 +296,37 @@ public final class IllegalAccessLogger {
this.opened = deepCopy(opened);
}
public void logAccessToExportedPackage(Module m, String pn, String how) {
if (!m.isExported(pn)) {
public Builder logAccessToExportedPackage(Module m, String pn, String how) {
if (!m.isExported(pn, UNNAMED)) {
if (exported == null)
exported = new HashMap<>();
exported.computeIfAbsent(m, k -> new HashMap<>()).putIfAbsent(pn, how);
}
return this;
}
public void logAccessToOpenPackage(Module m, String pn, String how) {
public Builder logAccessToOpenPackage(Module m, String pn, String how) {
// opens implies exported at run-time.
logAccessToExportedPackage(m, pn, how);
if (!m.isOpen(pn)) {
if (!m.isOpen(pn, UNNAMED)) {
if (opened == null)
opened = new HashMap<>();
opened.computeIfAbsent(m, k -> new HashMap<>()).putIfAbsent(pn, how);
}
return this;
}
public Builder warningStream(PrintStream warningStream) {
this.warningStream = Objects.requireNonNull(warningStream);
return this;
}
/**
* Builds the logger.
*/
public IllegalAccessLogger build() {
return new IllegalAccessLogger(exported, opened);
return new IllegalAccessLogger(exported, opened, warningStream);
}
}

View File

@ -515,44 +515,42 @@ public final class ModuleBootstrap {
* additional packages specified on the command-line.
*/
private static void addExtraExportsAndOpens(Layer bootLayer) {
IllegalAccessLogger.Builder builder = new IllegalAccessLogger.Builder();
// --add-exports
String prefix = "jdk.module.addexports.";
Map<String, List<String>> extraExports = decode(prefix);
if (!extraExports.isEmpty()) {
addExtraExportsOrOpens(bootLayer, extraExports, false, builder);
addExtraExportsOrOpens(bootLayer, extraExports, false);
}
// --add-opens
prefix = "jdk.module.addopens.";
Map<String, List<String>> extraOpens = decode(prefix);
if (!extraOpens.isEmpty()) {
addExtraExportsOrOpens(bootLayer, extraOpens, true, builder);
addExtraExportsOrOpens(bootLayer, extraOpens, true);
}
// --permit-illegal-access
if (getAndRemoveProperty("jdk.module.permitIllegalAccess") != null) {
warn("--permit-illegal-access will be removed in the next major release");
IllegalAccessLogger.Builder builder = new IllegalAccessLogger.Builder();
Module unnamed = BootLoader.getUnnamedModule();
bootLayer.modules().stream().forEach(m -> {
m.getDescriptor()
.packages()
.stream()
.filter(pn -> !m.isOpen(pn))
.filter(pn -> !m.isOpen(pn, unnamed)) // skip if opened by --add-opens
.forEach(pn -> {
builder.logAccessToOpenPackage(m, pn, "--permit-illegal-access");
Modules.addOpensToAllUnnamed(m, pn);
});
});
IllegalAccessLogger.setIllegalAccessLogger(builder.build());
}
IllegalAccessLogger.setIllegalAccessLogger(builder.build());
}
private static void addExtraExportsOrOpens(Layer bootLayer,
Map<String, List<String>> map,
boolean opens,
IllegalAccessLogger.Builder builder)
boolean opens)
{
String option = opens ? ADD_OPENS : ADD_EXPORTS;
for (Map.Entry<String, List<String>> e : map.entrySet()) {
@ -600,10 +598,8 @@ public final class ModuleBootstrap {
}
if (allUnnamed) {
if (opens) {
builder.logAccessToOpenPackage(m, pn, option);
Modules.addOpensToAllUnnamed(m, pn);
} else {
builder.logAccessToExportedPackage(m, pn, option);
Modules.addExportsToAllUnnamed(m, pn);
}
} else {

View File

@ -26,6 +26,7 @@
/**
* Defines the foundational APIs of the Java SE Platform.
*
* @moduleGraph
* @since 9
*/
module java.base {

View File

@ -85,7 +85,6 @@ import java.util.stream.Collectors;
import java.util.stream.Stream;
import jdk.internal.misc.VM;
import jdk.internal.module.IllegalAccessLogger;
import jdk.internal.module.Modules;
@ -429,20 +428,14 @@ public final class LauncherHelper {
abort(null, "java.launcher.jar.error3", jarname);
}
// Add-Exports and Add-Opens to allow illegal access
// Add-Exports and Add-Opens
String exports = mainAttrs.getValue(ADD_EXPORTS);
if (exports != null) {
String warn = getLocalizedMessage("java.launcher.permitaccess.warning",
jarname, ADD_EXPORTS);
System.err.println(warn);
addExportsOrOpens(exports, false, ADD_EXPORTS);
addExportsOrOpens(exports, false);
}
String opens = mainAttrs.getValue(ADD_OPENS);
if (opens != null) {
String warn = getLocalizedMessage("java.launcher.permitaccess.warning",
jarname, ADD_OPENS);
System.err.println(warn);
addExportsOrOpens(opens, true, ADD_OPENS);
addExportsOrOpens(opens, true);
}
/*
@ -467,15 +460,7 @@ public final class LauncherHelper {
* Process the Add-Exports or Add-Opens value. The value is
* {@code <module>/<package> ( <module>/<package>)*}.
*/
static void addExportsOrOpens(String value, boolean open, String how) {
IllegalAccessLogger.Builder builder;
IllegalAccessLogger logger = IllegalAccessLogger.illegalAccessLogger();
if (logger == null) {
builder = new IllegalAccessLogger.Builder();
} else {
builder = logger.toBuilder();
}
static void addExportsOrOpens(String value, boolean open) {
for (String moduleAndPackage : value.split(" ")) {
String[] s = moduleAndPackage.trim().split("/");
if (s.length == 2) {
@ -485,18 +470,14 @@ public final class LauncherHelper {
Layer.boot().findModule(mn).ifPresent(m -> {
if (m.getDescriptor().packages().contains(pn)) {
if (open) {
builder.logAccessToOpenPackage(m, pn, how);
Modules.addOpensToAllUnnamed(m, pn);
} else {
builder.logAccessToExportedPackage(m, pn, how);
Modules.addExportsToAllUnnamed(m, pn);
}
}
});
}
}
IllegalAccessLogger.setIllegalAccessLogger(builder.build());
}
// From src/share/bin/java.c:

View File

@ -211,6 +211,4 @@ java.launcher.module.error2=\
java.launcher.module.error3=\
Error: Unable to load main class {0} from module {1}\n\
\t{2}
java.launcher.permitaccess.warning=\
WARNING: Main manifest of {0} contains {1} attribute to permit illegal access

View File

@ -1025,6 +1025,13 @@ public final class Main {
cf = CertificateFactory.getInstance("X509");
}
// -trustcacerts can only be specified on -importcert.
// Reset it so that warnings on CA cert will remain for
// -printcert, etc.
if (command != IMPORTCERT) {
trustcacerts = false;
}
if (trustcacerts) {
caks = KeyStoreUtil.getCacertsKeyStore();
}
@ -1758,9 +1765,8 @@ public final class Main {
if (keyPass == null) {
keyPass = promptForKeyPass(alias, null, storePass);
}
keyStore.setKeyEntry(alias, privKey, keyPass, chain);
checkWeak(rb.getString("the.generated.certificate"), chain[0]);
keyStore.setKeyEntry(alias, privKey, keyPass, chain);
}
/**
@ -2118,6 +2124,10 @@ public final class Main {
}
try {
Certificate c = srckeystore.getCertificate(alias);
if (c != null) {
checkWeak("<" + newAlias + ">", c);
}
keyStore.setEntry(newAlias, entry, pp);
// Place the check so that only successful imports are blocked.
// For example, we don't block a failed SecretEntry import.
@ -2127,10 +2137,6 @@ public final class Main {
"The.destination.pkcs12.keystore.has.different.storepass.and.keypass.Please.retry.with.destkeypass.specified."));
}
}
Certificate c = srckeystore.getCertificate(alias);
if (c != null) {
checkWeak("<" + newAlias + ">", c);
}
return 1;
} catch (KeyStoreException kse) {
Object[] source2 = {alias, kse.toString()};
@ -2814,8 +2820,8 @@ public final class Main {
}
if (noprompt) {
keyStore.setCertificateEntry(alias, cert);
checkWeak(rb.getString("the.input"), cert);
keyStore.setCertificateEntry(alias, cert);
return true;
}
@ -3049,6 +3055,11 @@ public final class Main {
MessageFormat form = new MessageFormat
(rb.getString(".PATTERN.printX509Cert.with.weak"));
PublicKey pkey = cert.getPublicKey();
String sigName = cert.getSigAlgName();
// No need to warn about sigalg of a trust anchor
if (!isTrustedCert(cert)) {
sigName = withWeak(sigName);
}
Object[] source = {cert.getSubjectDN().toString(),
cert.getIssuerDN().toString(),
cert.getSerialNumber().toString(16),
@ -3056,7 +3067,7 @@ public final class Main {
cert.getNotAfter().toString(),
getCertFingerPrint("SHA-1", cert),
getCertFingerPrint("SHA-256", cert),
withWeak(cert.getSigAlgName()),
sigName,
withWeak(pkey),
cert.getVersion()
};
@ -3111,7 +3122,7 @@ public final class Main {
* or null otherwise. A label is added.
*/
private static Pair<String,Certificate>
getTrustedSigner(Certificate cert, KeyStore ks) throws Exception {
getSigner(Certificate cert, KeyStore ks) throws Exception {
if (ks.getCertificateAlias(cert) != null) {
return new Pair<>("", cert);
}
@ -3467,9 +3478,9 @@ public final class Main {
// do we trust the cert at the top?
Certificate topCert = replyCerts[replyCerts.length-1];
boolean fromKeyStore = true;
Pair<String,Certificate> root = getTrustedSigner(topCert, keyStore);
Pair<String,Certificate> root = getSigner(topCert, keyStore);
if (root == null && trustcacerts && caks != null) {
root = getTrustedSigner(topCert, caks);
root = getSigner(topCert, caks);
fromKeyStore = false;
}
if (root == null) {
@ -4301,9 +4312,19 @@ public final class Main {
return result;
}
private boolean isTrustedCert(Certificate cert) throws KeyStoreException {
if (caks != null && caks.getCertificateAlias(cert) != null) {
return true;
} else {
String inKS = keyStore.getCertificateAlias(cert);
return inKS != null && keyStore.isCertificateEntry(inKS);
}
}
private void checkWeak(String label, String sigAlg, Key key) {
if (!DISABLED_CHECK.permits(SIG_PRIMITIVE_SET, sigAlg, null)) {
if (sigAlg != null && !DISABLED_CHECK.permits(
SIG_PRIMITIVE_SET, sigAlg, null)) {
weakWarnings.add(String.format(
rb.getString("whose.sigalg.risk"), label, sigAlg));
}
@ -4316,7 +4337,8 @@ public final class Main {
}
}
private void checkWeak(String label, Certificate[] certs) {
private void checkWeak(String label, Certificate[] certs)
throws KeyStoreException {
for (int i = 0; i < certs.length; i++) {
Certificate cert = certs[i];
if (cert instanceof X509Certificate) {
@ -4325,15 +4347,18 @@ public final class Main {
if (certs.length > 1) {
fullLabel = oneInMany(label, i, certs.length);
}
checkWeak(fullLabel, xc.getSigAlgName(), xc.getPublicKey());
checkWeak(fullLabel, xc);
}
}
}
private void checkWeak(String label, Certificate cert) {
private void checkWeak(String label, Certificate cert)
throws KeyStoreException {
if (cert instanceof X509Certificate) {
X509Certificate xc = (X509Certificate)cert;
checkWeak(label, xc.getSigAlgName(), xc.getPublicKey());
// No need to check the sigalg of a trust anchor
String sigAlg = isTrustedCert(cert) ? null : xc.getSigAlgName();
checkWeak(label, sigAlg, xc.getPublicKey());
}
}

View File

@ -24,8 +24,9 @@
*/
/**
* Defines an API for transferring data between and within applications.
* Defines the API for transferring data between and within applications.
*
* @moduleGraph
* @since 9
*/
module java.datatransfer {

View File

@ -27,6 +27,7 @@
* Defines the AWT and Swing user interface toolkits, plus APIs for
* accessibility, audio, imaging, printing, and JavaBeans.
*
* @moduleGraph
* @since 9
*/
module java.desktop {

View File

@ -27,6 +27,7 @@
* Defines services that allow agents to
* instrument programs running on the JVM.
*
* @moduleGraph
* @since 9
*/
module java.instrument {

View File

@ -26,6 +26,7 @@
/**
* Defines the Java Logging API.
*
* @moduleGraph
* @since 9
*/
module java.logging {

View File

@ -46,6 +46,7 @@
* and load the appropriate {@code JMXConnectorServerProvider} service
* implementation for the given protocol.
*
* @moduleGraph
* @since 9
*/
module java.management.rmi {

View File

@ -29,6 +29,7 @@
* The JMX API consists of interfaces for monitoring and management of the
* JVM and other components in the Java runtime.
*
* @moduleGraph
* @since 9
*/
module java.management {

View File

@ -26,6 +26,7 @@
/**
* Defines the Java Naming and Directory Interface (JNDI) API.
*
* @moduleGraph
* @since 9
*/
module java.naming {

View File

@ -26,6 +26,7 @@
/**
* Defines the Preferences API.
*
* @moduleGraph
* @since 9
*/
module java.prefs {

View File

@ -26,6 +26,7 @@
/**
* Defines the Remote Method Invocation (RMI) API.
*
* @moduleGraph
* @since 9
*/
module java.rmi {

View File

@ -26,6 +26,7 @@
/**
* Defines the Scripting API.
*
* @moduleGraph
* @since 9
*/
module java.scripting {

View File

@ -29,6 +29,7 @@
* This module requires {@code java.se} and supplements it with modules
* that define CORBA and Java EE APIs. These modules are upgradeable.
*
* @moduleGraph
* @since 9
*/
@SuppressWarnings("deprecation")

View File

@ -29,6 +29,7 @@
* The modules defining CORBA and Java EE APIs are not required by
* this module, but they are required by {@code java.se.ee}.
*
* @moduleGraph
* @since 9
*/
module java.se {

View File

@ -28,6 +28,7 @@
* <P>
* This module also contains GSS-API mechanisms including Kerberos v5 and SPNEGO.
*
* @moduleGraph
* @since 9
*/
module java.security.jgss {

View File

@ -30,6 +30,7 @@
* This module also contains SASL mechanisms including DIGEST-MD5,
* CRAM-MD5, and NTLM.
*
* @moduleGraph
* @since 9
*/
module java.security.sasl {

View File

@ -26,6 +26,7 @@
/**
* Defines the Java Smart Card I/O API.
*
* @moduleGraph
* @since 9
*/
module java.smartcardio {

View File

@ -26,6 +26,7 @@
/**
* Defines the JDBC RowSet API.
*
* @moduleGraph
* @since 9
*/
module java.sql.rowset {

View File

@ -26,6 +26,7 @@
/**
* Defines the JDBC API.
*
* @moduleGraph
* @since 9
*/
module java.sql {

View File

@ -29,6 +29,7 @@
* The subset consists of RMI exception types which are mapped to CORBA system
* exceptions by the 'Java Language to IDL Mapping Specification'.
*
* @moduleGraph
* @since 9
*/
@Deprecated(since="9", forRemoval=true)

View File

@ -24,8 +24,9 @@
*/
/**
* Defines an API for XML cryptography.
* Defines the API for XML cryptography.
*
* @moduleGraph
* @since 9
*/
module java.xml.crypto {

View File

@ -26,6 +26,7 @@
/**
* Defines the attach API.
*
* @moduleGraph
* @since 9
*/
module jdk.attach {

View File

@ -23,6 +23,13 @@
* questions.
*/
/**
* {@link java.nio.charset.Charset Charset} provider for the charsets that
* are not in {@code java.base} (mostly double byte and IBM charsets).
*
* @moduleGraph
* @since 9
*/
module jdk.charsets {
provides java.nio.charset.spi.CharsetProvider
with sun.nio.cs.ext.ExtendedCharsets;

View File

@ -26,6 +26,7 @@
/**
* The SunPKCS11 security provider.
*
* @moduleGraph
* @since 9
*/
module jdk.crypto.cryptoki {

View File

@ -26,6 +26,7 @@
/**
* The SunEC security provider.
*
* @moduleGraph
* @since 9
*/
module jdk.crypto.ec {

View File

@ -26,6 +26,7 @@
/**
* The SunMSCAPI security provider.
*
* @moduleGraph
* @since 9
*/
module jdk.crypto.mscapi {

View File

@ -26,6 +26,7 @@
/**
* The OracleUCrypto security provider.
*
* @moduleGraph
* @since 9
*/
module jdk.crypto.ucrypto {

View File

@ -23,6 +23,12 @@
* questions.
*/
/**
* Defines the JDK-specific API for HTTP server.
*
* @moduleGraph
* @since 9
*/
module jdk.httpserver {
exports com.sun.net.httpserver;

View File

@ -23,6 +23,13 @@
* questions.
*/
/**
* Defines tools for manipulating Java Archive (JAR) files,
* including the jar and jarsigner tools.
*
* @moduleGraph
* @since 9
*/
module jdk.jartool {
exports com.sun.jarsigner;
exports jdk.security.jarsigner;

View File

@ -23,6 +23,13 @@
* questions.
*/
/**
* Defines tools for diagnostics and troubleshooting a JVM,
* including the jcmd, jps, jstat and other diagnostics tools.
*
* @moduleGraph
* @since 9
*/
module jdk.jcmd {
requires jdk.attach;
requires jdk.internal.jvmstat;

View File

@ -23,6 +23,13 @@
* questions.
*/
/**
* Defines the JMX graphical tool, jconsole, for monitoring and managing
* a running application.
*
* @moduleGraph
* @since 9
*/
module jdk.jconsole {
requires transitive java.desktop;
requires transitive java.management;

View File

@ -26,6 +26,7 @@
/**
* Defines the Java Debugger Interface.
*
* @moduleGraph
* @since 9
*/
module jdk.jdi {

View File

@ -26,6 +26,7 @@
/**
* Java Debug Wire Protocol.
*
* @moduleGraph
* @since 9
*/
module jdk.jdwp.agent {

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, 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
@ -35,8 +35,12 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
import java.util.MissingResourceException;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import jdk.internal.jimage.BasicImageReader;
import jdk.internal.jimage.ImageHeader;
import jdk.internal.jimage.ImageLocation;
@ -99,7 +103,7 @@ class JImageTask {
}
static class OptionsValues {
Task task = Task.LIST;
Task task = null;
String directory = ".";
String include = "";
boolean fullVersion;
@ -172,24 +176,31 @@ class JImageTask {
}
try {
List<String> unhandled = OPTION_HELPER.handleOptions(this, args);
String command;
String[] remaining = args;
try {
command = args[0];
options.task = Enum.valueOf(Task.class, args[0].toUpperCase(Locale.ENGLISH));
remaining = args.length > 1 ? Arrays.copyOfRange(args, 1, args.length)
: new String[0];
} catch (IllegalArgumentException ex) {
command = null;
options.task = null;
}
if(!unhandled.isEmpty()) {
try {
options.task = Enum.valueOf(Task.class, unhandled.get(0).toUpperCase());
} catch (IllegalArgumentException ex) {
throw TASK_HELPER.newBadArgs("err.not.a.task", unhandled.get(0));
}
// process arguments
List<String> unhandled = OPTION_HELPER.handleOptions(this, remaining);
for (String f : unhandled) {
options.jimages.add(new File(f));
}
for(int i = 1; i < unhandled.size(); i++) {
options.jimages.add(new File(unhandled.get(i)));
}
} else if (!options.help && !options.version && !options.fullVersion) {
throw TASK_HELPER.newBadArgs("err.invalid.task", "<unspecified>");
if (options.task == null && !options.help && !options.version && !options.fullVersion) {
throw TASK_HELPER.newBadArgs("err.not.a.task",
command != null ? command : "<unspecified>");
}
if (options.help) {
if (unhandled.isEmpty()) {
if (options.task == null) {
log.println(TASK_HELPER.getMessage("main.usage", PROGNAME));
Arrays.asList(RECOGNIZED_OPTIONS).stream()
.filter(option -> !option.isHidden())
@ -203,15 +214,19 @@ class JImageTask {
log.println(TASK_HELPER.getMessage("main.usage." +
options.task.toString().toLowerCase()));
} catch (MissingResourceException ex) {
throw TASK_HELPER.newBadArgs("err.not.a.task", unhandled.get(0));
throw TASK_HELPER.newBadArgs("err.not.a.task", command);
}
}
return EXIT_OK;
}
if (options.version || options.fullVersion) {
TASK_HELPER.showVersion(options.fullVersion);
if (options.task == null && !unhandled.isEmpty()) {
throw TASK_HELPER.newBadArgs("err.not.a.task",
Stream.of(args).collect(Collectors.joining(" ")));
}
TASK_HELPER.showVersion(options.fullVersion);
if (unhandled.isEmpty()) {
return EXIT_OK;
}
@ -435,7 +450,7 @@ class JImageTask {
iterate(this::listTitle, null, this::verify);
break;
default:
throw TASK_HELPER.newBadArgs("err.invalid.task",
throw TASK_HELPER.newBadArgs("err.not.a.task",
options.task.name()).showUsage(true);
}
return true;

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
@ -24,6 +24,8 @@
*/
package jdk.tools.jlink.internal;
import java.lang.module.Configuration;
import java.lang.module.ModuleFinder;
import java.lang.reflect.Layer;
import java.nio.ByteOrder;
import java.nio.file.Path;
@ -33,6 +35,8 @@ import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import jdk.internal.module.ModulePath;
import jdk.tools.jlink.plugin.Plugin;
import jdk.tools.jlink.plugin.PluginException;
import jdk.tools.jlink.builder.ImageBuilder;
@ -147,8 +151,8 @@ public final class Jlink {
private final Path output;
private final Set<String> modules;
private final Set<String> limitmods;
private final ByteOrder endian;
private final ModuleFinder finder;
/**
* jlink configuration,
@ -160,31 +164,23 @@ public final class Jlink {
* @param endian Jimage byte order. Native order by default
*/
public JlinkConfiguration(Path output,
List<Path> modulepaths,
Set<String> modules,
Set<String> limitmods,
ByteOrder endian) {
this.output = output;
this.modulepaths = modulepaths == null ? Collections.emptyList() : modulepaths;
this.modules = modules == null ? Collections.emptySet() : modules;
this.limitmods = limitmods == null ? Collections.emptySet() : limitmods;
this.endian = endian == null ? ByteOrder.nativeOrder() : endian;
}
List<Path> modulepaths,
Set<String> modules,
Set<String> limitmods,
ByteOrder endian) {
if (Objects.requireNonNull(modulepaths).isEmpty()) {
throw new IllegalArgumentException("Empty module path");
}
if (Objects.requireNonNull(modules).isEmpty()) {
throw new IllegalArgumentException("Empty modules");
}
/**
* jlink configuration,
*
* @param output Output directory, must not exist.
* @param modulepaths Modules paths
* @param modules Root modules to resolve
* @param limitmods Limit the universe of observable modules
*/
public JlinkConfiguration(Path output,
List<Path> modulepaths,
Set<String> modules,
Set<String> limitmods) {
this(output, modulepaths, modules, limitmods,
ByteOrder.nativeOrder());
this.output = output;
this.modulepaths = modulepaths;
this.modules = modules;
this.limitmods = Objects.requireNonNull(limitmods);
this.endian = Objects.requireNonNull(endian);
this.finder = moduleFinder();
}
/**
@ -222,6 +218,45 @@ public final class Jlink {
return limitmods;
}
/**
* Returns {@link ModuleFinder} that finds all observable modules
* for this jlink configuration.
*/
public ModuleFinder finder() {
return finder;
}
/**
* Returns a {@link Configuration} of the given module path,
* root modules with full service binding.
*/
public Configuration resolveAndBind()
{
return Configuration.empty().resolveAndBind(finder,
ModuleFinder.of(),
modules);
}
/**
* Returns a {@link Configuration} of the given module path,
* root modules with no service binding.
*/
public Configuration resolve()
{
return Configuration.empty().resolve(finder,
ModuleFinder.of(),
modules);
}
private ModuleFinder moduleFinder() {
Path[] entries = modulepaths.toArray(new Path[0]);
ModuleFinder finder = ModulePath.of(Runtime.version(), true, entries);
if (!limitmods.isEmpty()) {
finder = JlinkTask.limitFinder(finder, limitmods, modules);
}
return finder;
}
@Override
public String toString() {
StringBuilder builder = new StringBuilder();

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
@ -110,6 +110,12 @@ public class JlinkTask {
Path path = Paths.get(arg);
task.options.output = path;
}, "--output"),
new Option<JlinkTask>(false, (task, opt, arg) -> {
task.options.bindServices = true;
}, "--bind-services"),
new Option<JlinkTask>(false, (task, opt, arg) -> {
task.options.suggestProviders = true;
}, "--suggest-providers", "", true),
new Option<JlinkTask>(true, (task, opt, arg) -> {
String[] values = arg.split("=");
// check values
@ -140,6 +146,9 @@ public class JlinkTask {
throw taskHelper.newBadArgs("err.unknown.byte.order", arg);
}
}, "--endian"),
new Option<JlinkTask>(false, (task, opt, arg) -> {
task.options.verbose = true;
}, "--verbose", "-v"),
new Option<JlinkTask>(false, (task, opt, arg) -> {
task.options.version = true;
}, "--version"),
@ -185,6 +194,7 @@ public class JlinkTask {
static class OptionsValues {
boolean help;
String saveoptsfile;
boolean verbose;
boolean version;
boolean fullVersion;
final List<Path> modulePath = new ArrayList<>();
@ -195,6 +205,8 @@ public class JlinkTask {
Path packagedModulesPath;
ByteOrder endian = ByteOrder.nativeOrder();
boolean ignoreSigning = false;
boolean bindServices = false;
boolean suggestProviders = false;
}
int run(String[] args) {
@ -203,7 +215,11 @@ public class JlinkTask {
new PrintWriter(System.err, true));
}
try {
optionsHelper.handleOptionsNoUnhandled(this, args);
List<String> remaining = optionsHelper.handleOptions(this, args);
if (remaining.size() > 0 && !options.suggestProviders) {
throw taskHelper.newBadArgs("err.orphan.arguments", toString(remaining))
.showUsage(true);
}
if (options.help) {
optionsHelper.showHelp(PROGNAME);
return EXIT_OK;
@ -217,17 +233,24 @@ public class JlinkTask {
return EXIT_OK;
}
if (taskHelper.getExistingImage() == null) {
if (options.modulePath.isEmpty()) {
throw taskHelper.newBadArgs("err.modulepath.must.be.specified").showUsage(true);
}
createImage();
} else {
if (taskHelper.getExistingImage() != null) {
postProcessOnly(taskHelper.getExistingImage());
return EXIT_OK;
}
if (options.saveoptsfile != null) {
Files.write(Paths.get(options.saveoptsfile), getSaveOpts().getBytes());
if (options.modulePath.isEmpty()) {
throw taskHelper.newBadArgs("err.modulepath.must.be.specified")
.showUsage(true);
}
JlinkConfiguration config = initJlinkConfig();
if (options.suggestProviders) {
suggestProviders(config, remaining);
} else {
createImage(config);
if (options.saveoptsfile != null) {
Files.write(Paths.get(options.saveoptsfile), getSaveOpts().getBytes());
}
}
return EXIT_OK;
@ -266,25 +289,13 @@ public class JlinkTask {
Objects.requireNonNull(config.getOutput());
plugins = plugins == null ? new PluginsConfiguration() : plugins;
if (config.getModulepaths().isEmpty()) {
throw new IllegalArgumentException("Empty module paths");
}
ModuleFinder finder = newModuleFinder(config.getModulepaths(),
config.getLimitmods(),
config.getModules());
if (config.getModules().isEmpty()) {
throw new IllegalArgumentException("No modules to add");
}
// First create the image provider
ImageProvider imageProvider =
createImageProvider(finder,
config.getModules(),
config.getByteOrder(),
createImageProvider(config,
null,
IGNORE_SIGNING_DEFAULT,
false,
false,
null);
// Then create the Plugin Stack
@ -319,20 +330,24 @@ public class JlinkTask {
// the token for "all modules on the module path"
private static final String ALL_MODULE_PATH = "ALL-MODULE-PATH";
private void createImage() throws Exception {
if (options.output == null) {
throw taskHelper.newBadArgs("err.output.must.be.specified").showUsage(true);
}
private JlinkConfiguration initJlinkConfig() throws BadArgs {
if (options.addMods.isEmpty()) {
throw taskHelper.newBadArgs("err.mods.must.be.specified", "--add-modules")
.showUsage(true);
.showUsage(true);
}
Set<String> roots = new HashSet<>();
for (String mod : options.addMods) {
if (mod.equals(ALL_MODULE_PATH)) {
ModuleFinder finder = modulePathFinder();
Path[] entries = options.modulePath.toArray(new Path[0]);
ModuleFinder finder = ModulePath.of(Runtime.version(), true, entries);
if (!options.limitMods.isEmpty()) {
// finder for the observable modules specified in
// the --module-path and --limit-modules options
finder = limitFinder(finder, options.limitMods, Collections.emptySet());
}
// all observable modules are roots
finder.findAll()
.stream()
.map(ModuleReference::descriptor)
@ -343,40 +358,34 @@ public class JlinkTask {
}
}
ModuleFinder finder = newModuleFinder(options.modulePath,
options.limitMods,
roots);
return new JlinkConfiguration(options.output,
options.modulePath,
roots,
options.limitMods,
options.endian);
}
private void createImage(JlinkConfiguration config) throws Exception {
if (options.output == null) {
throw taskHelper.newBadArgs("err.output.must.be.specified").showUsage(true);
}
// First create the image provider
ImageProvider imageProvider = createImageProvider(finder,
roots,
options.endian,
ImageProvider imageProvider = createImageProvider(config,
options.packagedModulesPath,
options.ignoreSigning,
options.bindServices,
options.verbose,
log);
// Then create the Plugin Stack
ImagePluginStack stack = ImagePluginConfiguration.
parseConfiguration(taskHelper.getPluginsConfig(options.output, options.launchers));
ImagePluginStack stack = ImagePluginConfiguration.parseConfiguration(
taskHelper.getPluginsConfig(options.output, options.launchers));
//Ask the stack to proceed
stack.operate(imageProvider);
}
/**
* Returns a module finder to find the observable modules specified in
* the --module-path and --limit-modules options
*/
private ModuleFinder modulePathFinder() {
Path[] entries = options.modulePath.toArray(new Path[0]);
ModuleFinder finder = ModulePath.of(Runtime.version(), true, entries);
if (!options.limitMods.isEmpty()) {
finder = limitFinder(finder, options.limitMods, Collections.emptySet());
}
return finder;
}
/*
* Returns a module finder of the given module path that limits
* the observable modules to those in the transitive closure of
@ -405,22 +414,32 @@ public class JlinkTask {
return Paths.get(uri);
}
private static ImageProvider createImageProvider(ModuleFinder finder,
Set<String> roots,
ByteOrder order,
private static ImageProvider createImageProvider(JlinkConfiguration config,
Path retainModulesPath,
boolean ignoreSigning,
boolean bindService,
boolean verbose,
PrintWriter log)
throws IOException
{
if (roots.isEmpty()) {
throw new IllegalArgumentException("empty modules and limitmods");
}
Configuration cf = bindService ? config.resolveAndBind()
: config.resolve();
Configuration cf = Configuration.empty()
.resolve(finder,
ModuleFinder.of(),
roots);
if (verbose && log != null) {
// print modules to be linked in
cf.modules().stream()
.sorted(Comparator.comparing(ResolvedModule::name))
.forEach(rm -> log.format("module %s (%s)%n",
rm.name(), rm.reference().location().get()));
// print provider info
Set<ModuleReference> references = cf.modules().stream()
.map(ResolvedModule::reference).collect(Collectors.toSet());
String msg = String.format("%n%s:", taskHelper.getMessage("providers.header"));
printProviders(log, msg, references);
}
// emit a warning for any incubating modules in the configuration
if (log != null) {
@ -438,16 +457,16 @@ public class JlinkTask {
Map<String, Path> mods = cf.modules().stream()
.collect(Collectors.toMap(ResolvedModule::name, JlinkTask::toPathLocation));
return new ImageHelper(cf, mods, order, retainModulesPath, ignoreSigning);
return new ImageHelper(cf, mods, config.getByteOrder(), retainModulesPath, ignoreSigning);
}
/*
* Returns a ModuleFinder that limits observability to the given root
* modules, their transitive dependences, plus a set of other modules.
*/
private static ModuleFinder limitFinder(ModuleFinder finder,
Set<String> roots,
Set<String> otherMods) {
public static ModuleFinder limitFinder(ModuleFinder finder,
Set<String> roots,
Set<String> otherMods) {
// resolve all root modules
Configuration cf = Configuration.empty()
@ -484,6 +503,147 @@ public class JlinkTask {
};
}
/*
* Returns a map of each service type to the modules that use it
*/
private static Map<String, Set<String>> uses(Set<ModuleReference> modules) {
// collects the services used by the modules and print uses
Map<String, Set<String>> uses = new HashMap<>();
modules.stream()
.map(ModuleReference::descriptor)
.forEach(md -> md.uses().forEach(s ->
uses.computeIfAbsent(s, _k -> new HashSet<>()).add(md.name()))
);
return uses;
}
private static void printProviders(PrintWriter log,
String header,
Set<ModuleReference> modules) {
printProviders(log, header, modules, uses(modules));
}
/*
* Prints the providers that are used by the services specified in
* the given modules.
*
* The specified uses maps a service type name to the modules
* using the service type and that may or may not be present
* the given modules.
*/
private static void printProviders(PrintWriter log,
String header,
Set<ModuleReference> modules,
Map<String, Set<String>> uses) {
if (modules.isEmpty())
return;
// Build a map of a service type to the provider modules
Map<String, Set<ModuleDescriptor>> providers = new HashMap<>();
modules.stream()
.map(ModuleReference::descriptor)
.forEach(md -> {
md.provides().stream()
.filter(p -> uses.containsKey(p.service()))
.forEach(p -> providers.computeIfAbsent(p.service(), _k -> new HashSet<>())
.add(md));
});
if (!providers.isEmpty()) {
log.println(header);
}
// print the providers of the service types used by the specified modules
// sorted by the service type name and then provider's module name
providers.entrySet().stream()
.sorted(Map.Entry.comparingByKey())
.forEach(e -> {
String service = e.getKey();
e.getValue().stream()
.sorted(Comparator.comparing(ModuleDescriptor::name))
.forEach(md ->
md.provides().stream()
.filter(p -> p.service().equals(service))
.forEach(p -> log.format(" module %s provides %s, used by %s%n",
md.name(), p.service(),
uses.get(p.service()).stream()
.sorted()
.collect(Collectors.joining(","))))
);
});
}
private void suggestProviders(JlinkConfiguration config, List<String> args)
throws BadArgs
{
if (args.size() > 1) {
throw taskHelper.newBadArgs("err.orphan.argument",
toString(args.subList(1, args.size())))
.showUsage(true);
}
if (options.bindServices) {
log.println(taskHelper.getMessage("no.suggested.providers"));
return;
}
ModuleFinder finder = config.finder();
if (args.isEmpty()) {
// print providers used by the modules resolved without service binding
Configuration cf = config.resolve();
Set<ModuleReference> mrefs = cf.modules().stream()
.map(ResolvedModule::reference)
.collect(Collectors.toSet());
// print uses of the modules that would be linked into the image
mrefs.stream()
.sorted(Comparator.comparing(mref -> mref.descriptor().name()))
.forEach(mref -> {
ModuleDescriptor md = mref.descriptor();
log.format("module %s located (%s)%n", md.name(),
mref.location().get());
md.uses().stream().sorted()
.forEach(s -> log.format(" uses %s%n", s));
});
String msg = String.format("%n%s:", taskHelper.getMessage("suggested.providers.header"));
printProviders(log, msg, finder.findAll(), uses(mrefs));
} else {
// comma-separated service types, if specified
Set<String> names = Stream.of(args.get(0).split(","))
.collect(Collectors.toSet());
// find the modules that provide the specified service
Set<ModuleReference> mrefs = finder.findAll().stream()
.filter(mref -> mref.descriptor().provides().stream()
.map(ModuleDescriptor.Provides::service)
.anyMatch(names::contains))
.collect(Collectors.toSet());
// the specified services may or may not be in the modules that
// would be linked in. So find uses declared in all observable modules
Map<String, Set<String>> uses = uses(finder.findAll());
// check if any name given on the command line are unused service
mrefs.stream()
.flatMap(mref -> mref.descriptor().provides().stream()
.map(ModuleDescriptor.Provides::service))
.forEach(names::remove);
if (!names.isEmpty()) {
log.println(taskHelper.getMessage("warn.unused.services",
toString(names)));
}
String msg = String.format("%n%s:", taskHelper.getMessage("suggested.providers.header"));
printProviders(log, msg, mrefs, uses);
}
}
private static String toString(Collection<String> collection) {
return collection.stream().sorted()
.collect(Collectors.joining(","));
}
private String getSaveOpts() {
StringBuilder sb = new StringBuilder();
sb.append('#').append(new Date()).append("\n");

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
@ -46,6 +46,7 @@ import java.util.Map.Entry;
import java.util.MissingResourceException;
import java.util.ResourceBundle;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import jdk.tools.jlink.internal.plugins.ExcludeJmodSectionPlugin;
@ -101,8 +102,15 @@ public final class TaskHelper {
final boolean hidden;
final String name;
final String shortname;
final boolean terminalOption;
public Option(boolean hasArg, Processing<T> processing, boolean hidden, String name, String shortname) {
public Option(boolean hasArg,
Processing<T> processing,
boolean hidden,
String name,
String shortname,
boolean isTerminal)
{
if (!name.startsWith("--")) {
throw new RuntimeException("option name missing --, " + name);
}
@ -115,24 +123,33 @@ public final class TaskHelper {
this.hidden = hidden;
this.name = name;
this.shortname = shortname;
this.terminalOption = isTerminal;
}
public Option(boolean hasArg, Processing<T> processing, String name, String shortname, boolean isTerminal) {
this(hasArg, processing, false, name, shortname, isTerminal);
}
public Option(boolean hasArg, Processing<T> processing, String name, String shortname) {
this(hasArg, processing, false, name, shortname);
this(hasArg, processing, false, name, shortname, false);
}
public Option(boolean hasArg, Processing<T> processing, boolean hidden, String name) {
this(hasArg, processing, hidden, name, "");
this(hasArg, processing, hidden, name, "", false);
}
public Option(boolean hasArg, Processing<T> processing, String name) {
this(hasArg, processing, false, name, "");
this(hasArg, processing, false, name, "", false);
}
public boolean isHidden() {
return hidden;
}
public boolean isTerminal() {
return terminalOption;
}
public boolean matches(String opt) {
return opt.equals(name) ||
opt.equals(shortname) ||
@ -179,12 +196,12 @@ public final class TaskHelper {
private static class PluginOption extends Option<PluginsHelper> {
public PluginOption(boolean hasArg,
Processing<PluginsHelper> processing, boolean hidden, String name, String shortname) {
super(hasArg, processing, hidden, name, shortname);
super(hasArg, processing, hidden, name, shortname, false);
}
public PluginOption(boolean hasArg,
Processing<PluginsHelper> processing, boolean hidden, String name) {
super(hasArg, processing, hidden, name, "");
super(hasArg, processing, hidden, name, "", false);
}
public String resourcePrefix() {
@ -498,21 +515,13 @@ public final class TaskHelper {
return null;
}
// used by jimage. Return unhandled arguments like "create", "describe".
/**
* Handles all options. This method stops processing the argument
* at the first non-option argument i.e. not starts with `-`, or
* at the first terminal option and returns the remaining arguments,
* if any.
*/
public List<String> handleOptions(T task, String[] args) throws BadArgs {
return handleOptions(task, args, true);
}
// used by jlink. No unhandled arguments like "create", "describe".
void handleOptionsNoUnhandled(T task, String[] args) throws BadArgs {
handleOptions(task, args, false);
}
// shared code that handles options for both jlink and jimage. jimage uses arguments like
// "create", "describe" etc. as "task names". Those arguments are unhandled here and returned
// as "unhandled arguments list". jlink does not want such arguments. "collectUnhandled" flag
// tells whether to allow for unhandled arguments or not.
private List<String> handleOptions(T task, String[] args, boolean collectUnhandled) throws BadArgs {
// findbugs warning, copy instead of keeping a reference.
command = Arrays.copyOf(args, args.length);
@ -521,7 +530,6 @@ public final class TaskHelper {
// Unit tests can call Task multiple time in same JVM.
pluginOptions = new PluginsHelper(null);
List<String> rest = collectUnhandled? new ArrayList<>() : null;
// process options
for (int i = 0; i < args.length; i++) {
if (args[i].startsWith("-")) {
@ -531,7 +539,6 @@ public final class TaskHelper {
if (option == null) {
pluginOption = pluginOptions.getOption(name);
if (pluginOption == null) {
throw new BadArgs("err.unknown.option", name).
showUsage(true);
}
@ -556,20 +563,23 @@ public final class TaskHelper {
pluginOption.process(pluginOptions, name, param);
} else {
option.process(task, name, param);
if (option.isTerminal()) {
return ++i < args.length
? Stream.of(Arrays.copyOfRange(args, i, args.length))
.collect(Collectors.toList())
: Collections.emptyList();
}
}
if (opt.ignoreRest()) {
i = args.length;
}
} else {
if (collectUnhandled) {
rest.add(args[i]);
} else {
throw new BadArgs("err.orphan.argument", args[i]).
showUsage(true);
}
return Stream.of(Arrays.copyOfRange(args, i, args.length))
.collect(Collectors.toList());
}
}
return rest;
return Collections.emptyList();
}
private Option<T> getOption(String name) {

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -34,6 +34,7 @@ import jdk.tools.jlink.plugin.Plugin;
import java.io.File;
import java.io.IOException;
import java.lang.module.ModuleFinder;
import java.nio.ByteOrder;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Collections;
@ -93,9 +94,12 @@ public final class AppRuntimeImageBuilder {
public void build() throws IOException {
// jlink main arguments
Jlink.JlinkConfiguration jlinkConfig = new Jlink.JlinkConfiguration(
new File("").toPath(), // Unused
modulePath, addModules, limitModules);
Jlink.JlinkConfiguration jlinkConfig =
new Jlink.JlinkConfiguration(new File("").toPath(), // Unused
modulePath,
addModules,
limitModules,
ByteOrder.nativeOrder());
// plugin configuration
List<Plugin> plugins = new ArrayList<Plugin>();

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
@ -24,15 +24,12 @@
#
main.usage.summary=\
Usage: {0} <options> --module-path <modulepath> --add-modules <mods> --output\n\
\<path> use --help for a list of possible options
Usage: {0} <options> --module-path <modulepath> --add-modules <module>[,<module>...]\n\
\Use --help for a list of possible options
main.usage=\
Usage: {0} <options> --module-path <modulepath> --add-modules <mods> --output\n\
\<path> Possible options include:
error.prefix=Error:
warn.prefix=Warning:
Usage: {0} <options> --module-path <modulepath> --add-modules <module>[,<module>...]\n\
\Possible options include:
main.opt.help=\
\ -h, --help Print this help message
@ -54,9 +51,18 @@ main.opt.output=\
\ --output <path> Location of output path
main.opt.launcher=\
\ --launcher <command>=<module> Launcher command name for the module\n\
\ --launcher <command>=<module>/<main>\n\
\ Launcher command name for the module and the main class
\ --launcher <name>=<module>[/<mainclass>]\n\
\ Add a launcher command of the given\n\
\ name for the module and the main class\n\
\ if specified
main.opt.bind-services=\
\ --bind-services Do full service binding
main.opt.suggest-providers=\
\ --suggest-providers [<name>,...] Suggest providers of services used by\n\
\ the modules that would be linked, or\n\
\ of the given service types
main.command.files=\
\ @<filename> Read options from file
@ -75,6 +81,9 @@ main.opt.ignore-signing-information=\
\ signed modular JARs are not copied to\n\
\ the runtime image.
main.opt.verbose=\
\ -v, --verbose Enable verbose tracing
main.msg.bug=\
An exception has occurred in jlink. \
Please file a bug at the Java Bug Database (http://bugreport.java.com/bugreport/) \
@ -95,6 +104,9 @@ main.extended.help.footer=\
\n\
error.prefix=Error:
warn.prefix=Warning:
err.unknown.byte.order:unknown byte order {0}
err.launcher.main.class.empty:launcher main class name cannot be empty: {0}
err.launcher.module.name.empty:launcher module name cannot be empty: {0}
@ -111,12 +123,12 @@ err.file.error=cannot access file: {0}
err.dir.exists={0} already exists
err.badpattern=bad pattern {0}
err.unknown.option=unknown option: {0}
err.orphan.argument=orphan argument: {0}
err.missing.arg=no value given for {0}
err.internal.error=internal error: {0} {1} {2}
err.invalid.arg.for.option=invalid argument for option: {0}
err.option.after.class=option must be specified before classes: {0}
err.option.unsupported={0} not supported: {1}
err.orphan.arguments=invalid argument: {0}
err.config.defaults=property {0} is missing from configuration
err.config.defaults.value=wrong value in defaults property: {0}
err.bom.generation=bom file generation failed: {0}
@ -126,3 +138,7 @@ err.signing=signed modular JAR {0} is currently not supported,\
warn.signing=WARNING: signed modular JAR {0} is currently not supported
warn.invalid.arg=invalid classname or pathname not exist: {0}
warn.split.package=package {0} defined in {1} {2}
warn.unused.services=Services specified in --suggest-providers not used: {0}
no.suggested.providers=--bind-services option is specified. No additional providers suggested.
suggested.providers.header=Suggested providers
providers.header=Providers

View File

@ -23,6 +23,12 @@
* questions.
*/
/**
* Defines the Java linker tool, jlink.
*
* @moduleGraph
* @since 9
*/
module jdk.jlink {
requires jdk.internal.opt;
requires jdk.jdeps;

View File

@ -23,6 +23,12 @@
* questions.
*/
/**
* Defines the API for the JavaScript Object.
*
* @moduleGraph
* @since 9
*/
module jdk.jsobject {
requires java.desktop;
exports netscape.javascript;

View File

@ -23,6 +23,13 @@
* questions.
*/
/**
* Defines the tool for starting a daemon for the jstat tool to monitor
* JVM statistics remotely.
*
* @moduleGraph
* @since 9
*/
module jdk.jstatd {
requires java.rmi;
requires jdk.internal.jvmstat;
@ -32,4 +39,3 @@ module jdk.jstatd {
provides sun.jvmstat.monitor.MonitoredHostService with sun.jvmstat.perfdata.monitor.protocol.rmi.MonitoredHostRmiService;
}

View File

@ -23,6 +23,12 @@
* questions.
*/
/**
* Locale data provider for locales other than {@linkplain java.util.Locale#US US locale}.
*
* @moduleGraph
* @since 9
*/
module jdk.localedata {
provides sun.util.locale.provider.LocaleDataMetaInfo with
sun.util.resources.cldr.provider.CLDRLocaleDataMetaInfo,

View File

@ -23,6 +23,12 @@
* questions.
*/
/**
* Define the JMX management agent.
*
* @moduleGraph
* @since 9
*/
module jdk.management.agent {
requires java.management;
requires java.management.rmi;

View File

@ -23,6 +23,12 @@
* questions.
*/
/**
* Defines the JDK-specific Management Interfaces for JVM.
*
* @moduleGraph
* @since 9
*/
module jdk.management {
requires transitive java.management;

View File

@ -23,6 +23,12 @@
* questions.
*/
/**
* DNS Java Naming provider.
*
* @moduleGraph
* @since 9
*/
module jdk.naming.dns {
requires java.naming;

View File

@ -23,6 +23,12 @@
* questions.
*/
/**
* RMI Java Naming provider.
*
* @moduleGraph
* @since 9
*/
module jdk.naming.rmi {
requires java.naming;
requires java.rmi;

View File

@ -23,6 +23,12 @@
* questions.
*/
/**
* Defines the JDK-specific Networking API.
*
* @moduleGraph
* @since 9
*/
module jdk.net {
exports jdk.net;
}

View File

@ -23,6 +23,12 @@
* questions.
*/
/**
* Defines the JDK-specific API for SCTP.
*
* @moduleGraph
* @since 9
*/
module jdk.sctp {
exports com.sun.nio.sctp;
}

View File

@ -27,6 +27,7 @@
* Contains the implementation of the javax.security.auth.* interfaces and
* various authentication modules.
*
* @moduleGraph
* @since 9
*/
module jdk.security.auth {

View File

@ -27,6 +27,7 @@
* Defines Java extensions to the GSS-API and an implementation of the SASL
* GSSAPI mechanism.
*
* @moduleGraph
* @since 9
*/
module jdk.security.jgss {

View File

@ -23,6 +23,12 @@
* questions.
*/
/**
* Zip file system provider.
*
* @moduleGraph
* @since 9
*/
module jdk.zipfs {
provides java.nio.file.spi.FileSystemProvider with jdk.nio.zipfs.ZipFileSystemProvider;
}

View File

@ -180,8 +180,6 @@ java/nio/channels/Selector/Wakeup.java 6963118 windows-
java/nio/channels/DatagramChannel/ChangingAddress.java 7141822 macosx-all
java/nio/channels/Selector/OutOfBand.java 7132677 macosx-all
java/nio/file/WatchService/Basic.java 7158947 solaris-all Solaris 11
java/nio/file/WatchService/MayFlies.java 7158947 solaris-all Solaris 11
java/nio/file/WatchService/LotsOfEvents.java 7158947 solaris-all Solaris 11

View File

@ -73,6 +73,7 @@ jdk_lang = \
jdk/internal/misc \
jdk/internal/ref \
jdk/internal/jimage \
jdk/internal/math \
jdk/modules \
vm
@ -141,8 +142,7 @@ jdk_stream = \
java/util/stream
jdk_math = \
java/math \
jdk/internal/math
java/math
jdk_io = \
java/io

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2007, 2011, 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
@ -57,22 +57,11 @@ class NetworkConfiguration {
return ip6Interfaces.get(nif);
}
// IPv6 not supported for Windows XP/Server 2003
static boolean isIPv6Supported() {
if (System.getProperty("os.name").startsWith("Windows")) {
String ver = System.getProperty("os.version");
int major = Integer.parseInt(ver.split("\\.")[0]);
return (major >= 6);
}
return true;
}
static NetworkConfiguration probe() throws IOException {
Map<NetworkInterface,List<InetAddress>> ip4Interfaces =
new HashMap<NetworkInterface,List<InetAddress>>();
Map<NetworkInterface,List<InetAddress>> ip6Interfaces =
new HashMap<NetworkInterface,List<InetAddress>>();
boolean isIPv6Supported = isIPv6Supported();
// find the interfaces that support IPv4 and IPv6
List<NetworkInterface> nifs = Collections
@ -92,7 +81,7 @@ class NetworkConfiguration {
}
list.add(addr);
ip4Interfaces.put(nif, list);
} else if (isIPv6Supported && (addr instanceof Inet6Address)) {
} else if (addr instanceof Inet6Address) {
List<InetAddress> list = ip6Interfaces.get(nif);
if (list == null) {
list = new LinkedList<InetAddress>();

View File

@ -52,11 +52,6 @@ public class Transfer4GBFile {
// Test transferTo with large file
@Test
public void xferTest04() throws Exception { // for bug 4638365
// Windows and Linux can't handle the really large file sizes for a
// truncate or a positional write required by the test for 4563125
String osName = System.getProperty("os.name");
if (!(osName.startsWith("SunOS") || osName.contains("OS X")))
return;
File source = File.createTempFile("blah", null);
source.deleteOnExit();
long testSize = ((long)Integer.MAX_VALUE) * 2;

View File

@ -50,11 +50,6 @@ public class TransferTo6GBFile {
// Test transferTo with file positions larger than 2 and 4GB
@Test
public void xferTest08() throws Exception { // for bug 6253145
// Creating a sparse 6GB file on Windows takes too long
String osName = System.getProperty("os.name");
if (osName.startsWith("Windows"))
return;
final long G = 1024L * 1024L * 1024L;
// Create 6GB file

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2010, 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
@ -23,6 +23,9 @@
/* @test
* @bug 6213702
* @requires (os.family != "mac") | (os.version == "10.10.5")
* | (os.simpleVersion != "10.8" & os.simpleVersion != "10.9"
* & os.simpleVersion != "10.10")
* @summary OOB data causes a SocketChannel, with OOBINLINE disabled, to be
* selected
*/

View File

@ -66,15 +66,6 @@ public class SelectorLimit {
static final int MIN_KEYS = 100;
public static void main(String[] args) throws Exception {
// win9X can't handle many connections at once
String osName = System.getProperty("os.name");
if (osName.toLowerCase().startsWith("win")) {
if (!(osName.equals("Windows NT")
|| osName.equals("Windows 2000")
|| osName.equals("Windows XP")))
return;
}
ServerSocketChannel ssc = ServerSocketChannel.open();
TestUtil.bind(ssc);
Listener lth = new Listener(ssc);

View File

@ -23,7 +23,7 @@
/*
* @test
* @bug 8171319
* @bug 8171319 8177569
* @summary keytool should print out warnings when reading or generating
* cert/cert req using weak algorithms
* @library /test/lib
@ -78,7 +78,8 @@ public class WeakAlg {
.shouldMatch("<b>.*512-bit RSA key.*risk")
.shouldContain("512-bit RSA key (weak)");
// Multiple warnings for multiple cert in -printcert or -list or -exportcert
// Multiple warnings for multiple cert in -printcert
// or -list or -exportcert
// -certreq, -printcertreq, -gencert
checkCertReq("a", "", null);
@ -184,7 +185,7 @@ public class WeakAlg {
.shouldMatch("The input.*MD5withRSA.*risk")
.shouldNotContain("[no]");
// cert is self-signed cacerts
// JDK-8177569: no warning for sigalg of trusted cert
String weakSigAlgCA = null;
KeyStore ks = KeyStoreUtil.getCacertsKeyStore();
if (ks != null) {
@ -208,12 +209,40 @@ public class WeakAlg {
}
}
if (weakSigAlgCA != null) {
// The following 2 commands still have a warning on why not using
// the -cacerts option directly.
kt("-list -keystore " + KeyStoreUtil.getCacerts())
.shouldNotContain("risk");
kt("-list -v -keystore " + KeyStoreUtil.getCacerts())
.shouldNotContain("risk");
// -printcert will always show warnings
kt("-printcert -file ca.cert")
.shouldContain("name: " + weakSigAlgCA + " (weak)")
.shouldContain("Warning")
.shouldMatch("The certificate.*" + weakSigAlgCA + ".*risk");
kt("-printcert -file ca.cert -trustcacerts") // -trustcacerts useless
.shouldContain("name: " + weakSigAlgCA + " (weak)")
.shouldContain("Warning")
.shouldMatch("The certificate.*" + weakSigAlgCA + ".*risk");
// Importing with -trustcacerts ignore CA cert's sig alg
kt("-delete -alias d");
kt("-importcert -alias d -trustcacerts -file ca.cert", "no")
.shouldContain("Certificate already exists in system-wide CA")
.shouldNotContain("risk")
.shouldContain("Do you still want to add it to your own keystore?");
kt("-importcert -alias d -trustcacerts -file ca.cert -noprompt")
.shouldNotContain("risk")
.shouldNotContain("[no]");
// but not without -trustcacerts
kt("-delete -alias d");
kt("-importcert -alias d -file ca.cert", "no")
.shouldContain("name: " + weakSigAlgCA + " (weak)")
.shouldContain("Warning")
.shouldMatch("The input.*" + weakSigAlgCA + ".*risk")
.shouldContain("Do you still want to add it to your own keystore?");
.shouldContain("Trust this certificate?");
kt("-importcert -alias d -file ca.cert -noprompt")
.shouldContain("Warning")
.shouldMatch("The input.*" + weakSigAlgCA + ".*risk")
@ -265,6 +294,26 @@ public class WeakAlg {
// install reply
reStore();
certreq("c", "");
gencert("a-c", "");
kt("-importcert -alias c -file a-c.cert")
.shouldContain("Warning")
.shouldMatch("Issuer <a>.*MD5withRSA.*risk");
// JDK-8177569: no warning for sigalg of trusted cert
reStore();
// Change a into a TrustedCertEntry
kt("-exportcert -alias a -file a.cert");
kt("-delete -alias a");
kt("-importcert -alias a -file a.cert -noprompt");
kt("-list -alias a -v")
.shouldNotContain("weak")
.shouldNotContain("Warning");
// This time a is trusted and no warning on its weak sig alg
kt("-importcert -alias c -file a-c.cert")
.shouldNotContain("Warning");
reStore();
gencert("a-b", "");

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
@ -25,6 +25,7 @@ import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.nio.ByteOrder;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
@ -135,11 +136,6 @@ public class IntegrationTest {
}
System.out.println(jl);
JlinkConfiguration config
= new JlinkConfiguration(null, null, null, null);
System.out.println(config);
Plugin p = Jlink.newPlugin("toto", Collections.emptyMap(), null);
if (p != null) {
throw new Exception("Plugin should be null");
@ -163,7 +159,7 @@ public class IntegrationTest {
Set<String> limits = new HashSet<>();
limits.add("java.management");
JlinkConfiguration config = new Jlink.JlinkConfiguration(output,
modulePaths, mods, limits, null);
modulePaths, mods, limits, ByteOrder.nativeOrder());
List<Plugin> lst = new ArrayList<>();

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
@ -274,7 +274,7 @@ public class JLinkTest {
String[] userOptions = {"--compress", "2", "foo" };
String moduleName = "orphanarg1";
helper.generateDefaultJModule(moduleName, "composite2");
helper.generateDefaultImage(userOptions, moduleName).assertFailure("Error: orphan argument: foo");
helper.generateDefaultImage(userOptions, moduleName).assertFailure("Error: invalid argument: foo");
}
// orphan argument - JDK-8166810
@ -282,7 +282,7 @@ public class JLinkTest {
String[] userOptions = {"--output", "foo", "bar" };
String moduleName = "orphanarg2";
helper.generateDefaultJModule(moduleName, "composite2");
helper.generateDefaultImage(userOptions, moduleName).assertFailure("Error: orphan argument: bar");
helper.generateDefaultImage(userOptions, moduleName).assertFailure("Error: invalid argument: bar");
}
// basic check for --help - JDK-8173717

View File

@ -0,0 +1,200 @@
/*
* 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.io.File;
import java.io.PrintWriter;
import java.io.StringWriter;
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.spi.ToolProvider;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import static jdk.testlibrary.Asserts.assertTrue;
import static jdk.testlibrary.ProcessTools.*;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.Test;
import static org.testng.Assert.*;
/**
* @test
* @bug 8174826
* @library /lib/testlibrary
* @modules jdk.compiler jdk.jlink
* @build BindServices CompilerUtils jdk.testlibrary.ProcessTools
* @run testng BindServices
*/
public class BindServices {
private static final String JAVA_HOME = System.getProperty("java.home");
private static final String TEST_SRC = System.getProperty("test.src");
private static final Path SRC_DIR = Paths.get(TEST_SRC, "src");
private static final Path MODS_DIR = Paths.get("mods");
private static final String MODULE_PATH =
Paths.get(JAVA_HOME, "jmods").toString() +
File.pathSeparator + MODS_DIR.toString();
// the names of the modules in this test
private static String[] modules = new String[] {"m1", "m2", "m3"};
private static boolean hasJmods() {
if (!Files.exists(Paths.get(JAVA_HOME, "jmods"))) {
System.err.println("Test skipped. NO jmods directory");
return false;
}
return true;
}
/*
* Compiles all modules used by the test
*/
@BeforeTest
public void compileAll() throws Throwable {
if (!hasJmods()) return;
for (String mn : modules) {
Path msrc = SRC_DIR.resolve(mn);
assertTrue(CompilerUtils.compile(msrc, MODS_DIR,
"--module-source-path", SRC_DIR.toString()));
}
}
@Test
public void noServiceBinding() throws Throwable {
if (!hasJmods()) return;
Path dir = Paths.get("noServiceBinding");
// no service binding and does not link m2,m3 providers.
JLink.run("--output", dir.toString(),
"--module-path", MODULE_PATH,
"--add-modules", "m1").output();
testImage(dir, "m1");
}
@Test
public void fullServiceBinding() throws Throwable {
if (!hasJmods()) return;
Path dir = Paths.get("fullServiceBinding");
// full service binding
// m2 is a provider used by m1. During service binding, when m2 is
// resolved, m2 uses p2.T that causes m3 to be linked as it is a
// provider to p2.T
JLink.run("--output", dir.toString(),
"--module-path", MODULE_PATH,
"--add-modules", "m1",
"--bind-services",
"--limit-modules", "m1,m2,m3,java.base");
testImage(dir, "m1", "m2", "m3");
}
@Test
public void testVerbose() throws Throwable {
if (!hasJmods()) return;
Path dir = Paths.get("verbose");
List<String> output =
JLink.run("--output", dir.toString(),
"--module-path", MODULE_PATH,
"--add-modules", "m1",
"--bind-services",
"--verbose",
"--limit-modules", "m1,m2,m3,java.base").output();
List<String> expected = List.of(
"module m1 (" + MODS_DIR.resolve("m1").toUri().toString() + ")",
"module m2 (" + MODS_DIR.resolve("m2").toUri().toString() + ")",
"module m3 (" + MODS_DIR.resolve("m3").toUri().toString() + ")",
"module m1 provides p1.S, used by m1",
"module m2 provides p1.S, used by m1",
"module m2 provides p2.T, used by m2",
"module m3 provides p2.T, used by m2"
);
assertTrue(output.containsAll(expected));
testImage(dir, "m1", "m2", "m3");
}
/*
* Tests the given ${java.home} to only contain the specified modules
*/
private void testImage(Path javaHome, String... modules) throws Throwable {
Path java = javaHome.resolve("bin").resolve("java");
String[] cmd = Stream.concat(
Stream.of(java.toString(), "-m", "m1/p1.Main"),
Stream.of(modules)).toArray(String[]::new);
assertTrue(executeProcess(cmd).outputTo(System.out)
.errorTo(System.out)
.getExitValue() == 0);
}
static class JLink {
static final ToolProvider JLINK_TOOL = ToolProvider.findFirst("jlink")
.orElseThrow(() ->
new RuntimeException("jlink tool not found")
);
static JLink run(String... options) {
JLink jlink = new JLink();
assertTrue(jlink.execute(options) == 0);
return jlink;
}
final List<String> output = new ArrayList<>();
private int execute(String... options) {
System.out.println("jlink " +
Stream.of(options).collect(Collectors.joining(" ")));
StringWriter writer = new StringWriter();
PrintWriter pw = new PrintWriter(writer);
int rc = JLINK_TOOL.run(pw, pw, options);
System.out.println(writer.toString());
Stream.of(writer.toString().split("\\v"))
.map(String::trim)
.forEach(output::add);
return rc;
}
boolean contains(String s) {
return output.contains(s);
}
List<String> output() {
return output;
}
}
}

View File

@ -0,0 +1,209 @@
/*
* 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.io.File;
import java.io.PrintWriter;
import java.io.StringWriter;
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.spi.ToolProvider;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import static jdk.testlibrary.Asserts.assertTrue;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.Test;
import static org.testng.Assert.*;
/**
* @test
* @bug 8174826
* @library /lib/testlibrary
* @modules jdk.charsets jdk.compiler jdk.jlink
* @build SuggestProviders CompilerUtils
* @run testng SuggestProviders
*/
public class SuggestProviders {
private static final String JAVA_HOME = System.getProperty("java.home");
private static final String TEST_SRC = System.getProperty("test.src");
private static final Path SRC_DIR = Paths.get(TEST_SRC, "src");
private static final Path MODS_DIR = Paths.get("mods");
private static final String MODULE_PATH =
Paths.get(JAVA_HOME, "jmods").toString() +
File.pathSeparator + MODS_DIR.toString();
// the names of the modules in this test
private static String[] modules = new String[] {"m1", "m2", "m3"};
private static boolean hasJmods() {
if (!Files.exists(Paths.get(JAVA_HOME, "jmods"))) {
System.err.println("Test skipped. NO jmods directory");
return false;
}
return true;
}
/*
* Compiles all modules used by the test
*/
@BeforeTest
public void compileAll() throws Throwable {
if (!hasJmods()) return;
for (String mn : modules) {
Path msrc = SRC_DIR.resolve(mn);
assertTrue(CompilerUtils.compile(msrc, MODS_DIR,
"--module-source-path", SRC_DIR.toString()));
}
}
@Test
public void suggestProviders() throws Throwable {
if (!hasJmods()) return;
List<String> output = JLink.run("--module-path", MODULE_PATH,
"--add-modules", "m1",
"--suggest-providers").output();
// check a subset of services used by java.base
List<String> expected = List.of(
"uses java.lang.System$LoggerFinder",
"uses java.net.ContentHandlerFactory",
"uses java.net.spi.URLStreamHandlerProvider",
"uses java.nio.channels.spi.AsynchronousChannelProvider",
"uses java.nio.channels.spi.SelectorProvider",
"uses java.nio.charset.spi.CharsetProvider",
"uses java.nio.file.spi.FileSystemProvider",
"uses java.nio.file.spi.FileTypeDetector",
"uses java.security.Provider",
"uses java.util.spi.ToolProvider",
"uses p1.S",
"module jdk.charsets provides java.nio.charset.spi.CharsetProvider, used by java.base",
"module jdk.compiler provides java.util.spi.ToolProvider, used by java.base",
"module jdk.jlink provides java.util.spi.ToolProvider, used by java.base",
"module m1 provides p1.S, used by m1",
"module m2 provides p1.S, used by m1"
);
assertTrue(output.containsAll(expected));
}
@Test
public void providersForServices() throws Throwable {
if (!hasJmods()) return;
List<String> output =
JLink.run("--module-path", MODULE_PATH,
"--add-modules", "m1",
"--suggest-providers",
"java.nio.charset.spi.CharsetProvider,p1.S,p2.T").output();
System.out.println(output);
List<String> expected = List.of(
"module jdk.charsets provides java.nio.charset.spi.CharsetProvider, used by java.base",
"module m1 provides p1.S, used by m1",
"module m2 provides p1.S, used by m1",
"module m2 provides p2.T, used by m2",
"module m3 provides p2.T, used by m2"
);
assertTrue(output.containsAll(expected));
}
@Test
public void unusedService() throws Throwable {
if (!hasJmods()) return;
List<String> output =
JLink.run("--module-path", MODULE_PATH,
"--add-modules", "m1",
"--suggest-providers",
"nonExistentType").output();
System.out.println(output);
List<String> expected = List.of(
"Services specified in --suggest-providers not used: nonExistentType"
);
assertTrue(output.containsAll(expected));
}
@Test
public void noSuggestProviders() throws Throwable {
if (!hasJmods()) return;
List<String> output =
JLink.run("--module-path", MODULE_PATH,
"--add-modules", "m1",
"--bind-services",
"--limit-modules", "m1,m2,m3,java.base",
"--suggest-providers").output();
String expected = "--bind-services option is specified. No additional providers suggested.";
assertTrue(output.contains(expected));
}
static class JLink {
static final ToolProvider JLINK_TOOL = ToolProvider.findFirst("jlink")
.orElseThrow(() ->
new RuntimeException("jlink tool not found")
);
static JLink run(String... options) {
JLink jlink = new JLink();
assertTrue(jlink.execute(options) == 0);
return jlink;
}
final List<String> output = new ArrayList<>();
private int execute(String... options) {
System.out.println("jlink " +
Stream.of(options).collect(Collectors.joining(" ")));
StringWriter writer = new StringWriter();
PrintWriter pw = new PrintWriter(writer);
int rc = JLINK_TOOL.run(pw, pw, options);
System.out.println(writer.toString());
Stream.of(writer.toString().split("\\v"))
.map(String::trim)
.forEach(output::add);
return rc;
}
boolean contains(String s) {
return output.contains(s);
}
List<String> output() {
return 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.
*/
module m1 {
exports p1;
uses p1.S;
provides p1.S with p1.Impl;
}

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 p1;
public class Impl implements S {
public String name() {
return this.getClass().getName();
}
}

View File

@ -0,0 +1,53 @@
/*
* 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 p1;
import java.lang.module.ModuleFinder;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* This tests if JAVA_HOME is linked only with the specified modules.
*/
public class Main {
public static void main(String... args) {
Set<String> modules = ModuleFinder.ofSystem().findAll().stream()
.map(mref -> mref.descriptor().name())
.filter(mn -> !mn.equals("java.base"))
.collect(Collectors.toSet());
Set<String> notLinked = Stream.of(args).filter(mn -> !modules.contains(mn))
.collect(Collectors.toSet());
if (!notLinked.isEmpty()) {
throw new RuntimeException("Expected modules not linked in the image: "
+ notLinked);
}
Stream.of(args).forEach(modules::remove);
if (!modules.isEmpty()) {
throw new RuntimeException("Unexpected modules linked in the image: "
+ modules);
}
}
}

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.
*/
package p1;
public interface S {
String name();
}

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.
*/
module m2 {
requires m1;
exports p2;
uses p2.T;
provides p1.S with p2.Impl;
provides p2.T with p2.Impl;
}

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.
*/
package p2;
public class Impl implements p1.S, T {
public String name() {
return this.getClass().getName();
}
public void run() {
}
}

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.
*/
package p2;
public interface T {
void run();
}

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 m3 {
requires m2;
provides p2.T with p3.Impl;
}

View File

@ -0,0 +1,29 @@
/*
* 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 p3;
public class Impl implements p2.T {
public void run() {
}
}

View File

@ -29,7 +29,10 @@
* @summary Basic test for java --permit-illegal-access
*/
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;
import jdk.testlibrary.ProcessTools;
import jdk.testlibrary.OutputAnalyzer;
@ -58,10 +61,13 @@ public class PermitIllegalAccess {
* Launches AttemptAccess to execute an action, returning the OutputAnalyzer
* to analyze the output/exitCode.
*/
private OutputAnalyzer tryAction(String action, int count) throws Exception {
String arg = "" + count;
return ProcessTools
.executeTestJava("-cp", TEST_CLASSES, TEST_MAIN, action, arg)
private OutputAnalyzer tryAction(String action, int count, String... args)
throws Exception
{
Stream<String> s1 = Stream.of(args);
Stream<String> s2 = Stream.of("-cp", TEST_CLASSES, TEST_MAIN, action, "" + count);
String[] opts = Stream.concat(s1, s2).toArray(String[]::new);
return ProcessTools.executeTestJava(opts)
.outputTo(System.out)
.errorTo(System.out);
}
@ -70,16 +76,10 @@ public class PermitIllegalAccess {
* Launches AttemptAccess with --permit-illegal-access to execute an action,
* returning the OutputAnalyzer to analyze the output/exitCode.
*/
private OutputAnalyzer tryActionPermittingIllegalAccess(String action,
int count)
private OutputAnalyzer tryActionPermittingIllegalAccess(String action, int count)
throws Exception
{
String arg = "" + count;
return ProcessTools
.executeTestJava("-cp", TEST_CLASSES, "--permit-illegal-access",
TEST_MAIN, action, arg)
.outputTo(System.out)
.errorTo(System.out);
return tryAction(action, count, "--permit-illegal-access");
}
/**
@ -194,6 +194,61 @@ public class PermitIllegalAccess {
}
/**
* Permit access to succeed with --add-exports. No warning should be printed.
*/
public void testAccessWithAddExports() throws Exception {
tryAction("access", 1, "--add-exports", "java.base/sun.security.x509=ALL-UNNAMED")
.stdoutShouldNotContain(WARNING)
.stdoutShouldNotContain("IllegalAccessException")
.stderrShouldNotContain(WARNING)
.stderrShouldNotContain("IllegalAccessException")
.shouldHaveExitValue(0);
}
/**
* Permit access to succeed with --add-exports and --permit-illegal-access.
* The only warning emitted should be the startup warning.
*/
public void testAccessWithePermittedAddExports() throws Exception {
tryAction("access", 1, "--permit-illegal-access",
"--add-exports", "java.base/sun.security.x509=ALL-UNNAMED")
.stdoutShouldNotContain(WARNING)
.stdoutShouldNotContain("IllegalAccessException")
.stderrShouldContain(STARTUP_WARNING)
.stderrShouldNotContain("IllegalAccessException")
.stderrShouldNotContain(ILLEGAL_ACCESS_WARNING)
.shouldHaveExitValue(0);
}
/**
* Permit setAccessible to succeed with --add-opens. No warning should be printed.
*/
public void testSetAccessibleWithAddOpens() throws Exception {
tryAction("setAccessible", 1, "--add-opens", "java.base/java.lang=ALL-UNNAMED")
.stdoutShouldNotContain(WARNING)
.stdoutShouldNotContain("InaccessibleObjectException")
.stderrShouldNotContain(WARNING)
.stderrShouldNotContain("InaccessibleObjectException")
.shouldHaveExitValue(0);
}
/**
* Permit setAccessible to succeed with both --add-opens and --permit-illegal-access.
* The only warning emitted should be the startup warning.
*/
public void testSetAccessiblePermittedWithAddOpens() throws Exception {
tryAction("setAccessible", 1, "--permit-illegal-access",
"--add-opens", "java.base/java.lang=ALL-UNNAMED")
.stdoutShouldNotContain(WARNING)
.stdoutShouldNotContain("InaccessibleObjectException")
.stderrShouldContain(STARTUP_WARNING)
.stderrShouldNotContain("InaccessibleObjectException")
.stderrShouldNotContain(ILLEGAL_ACCESS_WARNING)
.shouldHaveExitValue(0);
}
/**
* Returns the number of lines in the given input that contain the
* given char sequence.