# HG changeset patch # User jwilhelm # Date 1490896504 -7200 # Node ID e8db842f5496fcef325047edbc2d2357e55e8112 # Parent a053dcc2d9864da9b09fafee9cf8e27b3d0c15b1# Parent ae0000fbbb2ce3b565d2ae4d274cdb1ef381e787 Merge diff -r a053dcc2d986 -r e8db842f5496 jdk/.hgtags --- a/jdk/.hgtags Sat Mar 25 00:31:29 2017 +0100 +++ b/jdk/.hgtags Thu Mar 30 19:55:04 2017 +0200 @@ -405,3 +405,4 @@ cac788454598b95d8b0153c021a7fae3cd7e6fda jdk-9+160 09b92d3067a38ee07bc14efa336b14790c93f7e7 jdk-9+161 f6bf027e88e9a4dd19f721001a7af00157af42c4 jdk-9+162 +50171f8c47961710cbf87aead6f03fa431d8d240 jdk-9+163 diff -r a053dcc2d986 -r e8db842f5496 jdk/make/GenerateModuleSummary.gmk --- a/jdk/make/GenerateModuleSummary.gmk Sat Mar 25 00:31:29 2017 +0100 +++ b/jdk/make/GenerateModuleSummary.gmk Thu Mar 30 19:55:04 2017 +0200 @@ -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 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) diff -r a053dcc2d986 -r e8db842f5496 jdk/make/ModuleTools.gmk --- a/jdk/make/ModuleTools.gmk Sat Mar 25 00:31:29 2017 +0100 +++ b/jdk/make/ModuleTools.gmk Thu Mar 30 19:55:04 2017 +0200 @@ -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 @@ # 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 @@ -cp $(TOOLS_CLASSES_DIR) \ --add-exports java.base/jdk.internal.module=ALL-UNNAMED \ build.tools.jigsaw.AddPackagesAttribute + +endif # _MODULE_TOOLS_GMK diff -r a053dcc2d986 -r e8db842f5496 jdk/make/src/classes/build/tools/jigsaw/GenGraphs.java --- a/jdk/make/src/classes/build/tools/jigsaw/GenGraphs.java Sat Mar 25 00:31:29 2017 +0100 +++ b/jdk/make/src/classes/build/tools/jigsaw/GenGraphs.java Thu Mar 30 19:55:04 2017 +0200 @@ -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.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 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 @@ 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 configurations = new HashMap<>(); @@ -99,49 +112,149 @@ 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 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 + ); + + final Map weights = new HashMap<>(); + final List> ranks = new ArrayList<>(); + final Map attrs; + ModuleGraphAttributes(Map 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"); + } - 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); + @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> 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 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 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."); } -} \ No newline at end of file +} diff -r a053dcc2d986 -r e8db842f5496 jdk/make/src/classes/build/tools/jigsaw/javadoc-graphs.properties --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/make/src/classes/build/tools/jigsaw/javadoc-graphs.properties Thu Mar 30 19:55:04 2017 +0200 @@ -0,0 +1,2 @@ +arrowcolor=#999999 +requiresMandatedColor=#999999 diff -r a053dcc2d986 -r e8db842f5496 jdk/make/src/classes/build/tools/taglet/ModuleGraph.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/make/src/classes/build/tools/taglet/ModuleGraph.java Thu Mar 30 19:55:04 2017 +0200 @@ -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 getAllowedLocations() { + return EnumSet.of(MODULE); + } + + @Override + public boolean isInlineTag() { + return false; + } + + @Override + public String getName() { + return "moduleGraph"; + } + + @Override + public String toString(List 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 = "" + + getImage(moduleName, imageFile, -1, true) + + ""; + } + return "
" + + "Module Graph:\n" + + "
" + + "
" + + "" + + getImage(moduleName, imageFile, thumbnailHeight, false) + + hoverImage + + "" + + "
"; + } + + 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("\"Module", + useBorder ? BORDER + " " + VERTICAL_ALIGN : VERTICAL_ALIGN, + moduleName, + file, + (height <= 0 ? "" : " height=\"" + height + "\"")); + } +} diff -r a053dcc2d986 -r e8db842f5496 jdk/src/java.base/share/classes/java/lang/String.java --- a/jdk/src/java.base/share/classes/java/lang/String.java Sat Mar 25 00:31:29 2017 +0100 +++ b/jdk/src/java.base/share/classes/java/lang/String.java Thu Mar 30 19:55:04 2017 +0200 @@ -2672,7 +2672,6 @@ * point is passed through uninterpreted. * * @return an IntStream of char values from this sequence - * @since 9 */ @Override public IntStream chars() { @@ -2692,7 +2691,6 @@ * {@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() { diff -r a053dcc2d986 -r e8db842f5496 jdk/src/java.base/share/classes/java/lang/System.java --- a/jdk/src/java.base/share/classes/java/lang/System.java Sat Mar 25 00:31:29 2017 +0100 +++ b/jdk/src/java.base/share/classes/java/lang/System.java Thu Mar 30 19:55:04 2017 +0200 @@ -1568,6 +1568,14 @@ * 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 @@ * @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 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 @@ * 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 @@ * 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 @@ 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 diff -r a053dcc2d986 -r e8db842f5496 jdk/src/java.base/share/classes/java/lang/reflect/Constructor.java --- a/jdk/src/java.base/share/classes/java/lang/reflect/Constructor.java Sat Mar 25 00:31:29 2017 +0100 +++ b/jdk/src/java.base/share/classes/java/lang/reflect/Constructor.java Thu Mar 30 19:55:04 2017 +0200 @@ -174,7 +174,6 @@ * @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 diff -r a053dcc2d986 -r e8db842f5496 jdk/src/java.base/share/classes/java/nio/MappedByteBuffer.java --- a/jdk/src/java.base/share/classes/java/nio/MappedByteBuffer.java Sat Mar 25 00:31:29 2017 +0100 +++ b/jdk/src/java.base/share/classes/java/nio/MappedByteBuffer.java Thu Mar 30 19:55:04 2017 +0200 @@ -213,7 +213,6 @@ /** * {@inheritDoc} - * @since 9 */ @Override public final MappedByteBuffer position(int newPosition) { @@ -223,7 +222,6 @@ /** * {@inheritDoc} - * @since 9 */ @Override public final MappedByteBuffer limit(int newLimit) { @@ -233,7 +231,6 @@ /** * {@inheritDoc} - * @since 9 */ @Override public final MappedByteBuffer mark() { @@ -243,7 +240,6 @@ /** * {@inheritDoc} - * @since 9 */ @Override public final MappedByteBuffer reset() { @@ -253,7 +249,6 @@ /** * {@inheritDoc} - * @since 9 */ @Override public final MappedByteBuffer clear() { @@ -263,7 +258,6 @@ /** * {@inheritDoc} - * @since 9 */ @Override public final MappedByteBuffer flip() { @@ -273,7 +267,6 @@ /** * {@inheritDoc} - * @since 9 */ @Override public final MappedByteBuffer rewind() { diff -r a053dcc2d986 -r e8db842f5496 jdk/src/java.base/share/classes/java/nio/X-Buffer.java.template --- a/jdk/src/java.base/share/classes/java/nio/X-Buffer.java.template Sat Mar 25 00:31:29 2017 +0100 +++ b/jdk/src/java.base/share/classes/java/nio/X-Buffer.java.template Thu Mar 30 19:55:04 2017 +0200 @@ -1069,7 +1069,6 @@ /** * {@inheritDoc} - * @since 9 */ @Override public @@ -1083,7 +1082,6 @@ /** * {@inheritDoc} - * @since 9 */ @Override public @@ -1097,7 +1095,6 @@ /** * {@inheritDoc} - * @since 9 */ @Override public @@ -1111,7 +1108,6 @@ /** * {@inheritDoc} - * @since 9 */ @Override public @@ -1125,7 +1121,6 @@ /** * {@inheritDoc} - * @since 9 */ @Override public @@ -1139,7 +1134,6 @@ /** * {@inheritDoc} - * @since 9 */ @Override public @@ -1153,7 +1147,6 @@ /** * {@inheritDoc} - * @since 9 */ @Override public diff -r a053dcc2d986 -r e8db842f5496 jdk/src/java.base/share/classes/java/security/SecureRandom.java --- a/jdk/src/java.base/share/classes/java/security/SecureRandom.java Sat Mar 25 00:31:29 2017 +0100 +++ b/jdk/src/java.base/share/classes/java/security/SecureRandom.java Thu Mar 30 19:55:04 2017 +0200 @@ -651,8 +651,6 @@ * {@code SecureRandom}. * * @return the string representation - * - * @since 9 */ @Override public String toString() { diff -r a053dcc2d986 -r e8db842f5496 jdk/src/java.base/share/classes/java/security/SecureRandomSpi.java --- a/jdk/src/java.base/share/classes/java/security/SecureRandomSpi.java Sat Mar 25 00:31:29 2017 +0100 +++ b/jdk/src/java.base/share/classes/java/security/SecureRandomSpi.java Thu Mar 30 19:55:04 2017 +0200 @@ -211,8 +211,6 @@ * {@code SecureRandom}. * * @return the string representation - * - * @since 9 */ @Override public String toString() { diff -r a053dcc2d986 -r e8db842f5496 jdk/src/java.base/share/classes/java/time/chrono/Era.java --- a/jdk/src/java.base/share/classes/java/time/chrono/Era.java Sat Mar 25 00:31:29 2017 +0100 +++ b/jdk/src/java.base/share/classes/java/time/chrono/Era.java Thu Mar 30 19:55:04 2017 +0200 @@ -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 @@ * The parameters control the style of the returned text and the locale. *

* If no textual mapping is found then the {@link #getValue() numeric value} is returned. - *

- * 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 diff -r a053dcc2d986 -r e8db842f5496 jdk/src/java.base/share/classes/java/time/chrono/JapaneseEra.java --- a/jdk/src/java.base/share/classes/java/time/chrono/JapaneseEra.java Sat Mar 25 00:31:29 2017 +0100 +++ b/jdk/src/java.base/share/classes/java/time/chrono/JapaneseEra.java Thu Mar 30 19:55:04 2017 +0200 @@ -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 @@ } /** - * Gets the textual representation of this era. - *

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

- * 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) { diff -r a053dcc2d986 -r e8db842f5496 jdk/src/java.base/share/classes/java/util/jar/Pack200.java --- a/jdk/src/java.base/share/classes/java/util/jar/Pack200.java Sat Mar 25 00:31:29 2017 +0100 +++ b/jdk/src/java.base/share/classes/java/util/jar/Pack200.java Thu Mar 30 19:55:04 2017 +0200 @@ -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 @@ 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. *

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

* 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 @@ /** * 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. * diff -r a053dcc2d986 -r e8db842f5496 jdk/src/java.base/share/classes/jdk/internal/module/IllegalAccessLogger.java --- a/jdk/src/java.base/share/classes/jdk/internal/module/IllegalAccessLogger.java Sat Mar 25 00:31:29 2017 +0100 +++ b/jdk/src/java.base/share/classes/jdk/internal/module/IllegalAccessLogger.java Thu Mar 30 19:55:04 2017 +0200 @@ -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.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,16 +53,25 @@ 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; + + static { + PrivilegedAction 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); + } } - private static final StackWalker STACK_WALKER - = StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE); - // the maximum number of frames to capture private static final int MAX_STACK_FRAMES = 32; @@ -72,10 +85,15 @@ private final Map> exported; private final Map> opened; + // the print stream to send the warnings + private final PrintStream warningStream; + private IllegalAccessLogger(Map> exported, - Map> opened) { + Map> opened, + PrintStream warningStream) { this.exported = deepCopy(exported); this.opened = deepCopy(opened); + this.warningStream = warningStream; } /** @@ -168,7 +186,7 @@ */ private void log(Class caller, String what, Supplier msgSupplier) { // stack trace without the top-most frames in java.base - List stack = STACK_WALKER.walk(s -> + List stack = Holder.STACK_WALKER.walk(s -> s.dropWhile(this::isJavaBase) .limit(MAX_STACK_FRAMES) .collect(Collectors.toList()) @@ -184,13 +202,13 @@ // 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 @@ * A builder for IllegalAccessLogger objects. */ public static class Builder { + private final Module UNNAMED = BootLoader.getUnnamedModule(); private Map> exported; private Map> opened; + private PrintStream warningStream = System.err; public Builder() { } @@ -276,30 +296,37 @@ 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); } } diff -r a053dcc2d986 -r e8db842f5496 jdk/src/java.base/share/classes/jdk/internal/module/ModuleBootstrap.java --- a/jdk/src/java.base/share/classes/jdk/internal/module/ModuleBootstrap.java Sat Mar 25 00:31:29 2017 +0100 +++ b/jdk/src/java.base/share/classes/jdk/internal/module/ModuleBootstrap.java Thu Mar 30 19:55:04 2017 +0200 @@ -515,44 +515,42 @@ * 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> extraExports = decode(prefix); if (!extraExports.isEmpty()) { - addExtraExportsOrOpens(bootLayer, extraExports, false, builder); + addExtraExportsOrOpens(bootLayer, extraExports, false); } // --add-opens prefix = "jdk.module.addopens."; Map> 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> map, - boolean opens, - IllegalAccessLogger.Builder builder) + boolean opens) { String option = opens ? ADD_OPENS : ADD_EXPORTS; for (Map.Entry> e : map.entrySet()) { @@ -600,10 +598,8 @@ } if (allUnnamed) { if (opens) { - builder.logAccessToOpenPackage(m, pn, option); Modules.addOpensToAllUnnamed(m, pn); } else { - builder.logAccessToExportedPackage(m, pn, option); Modules.addExportsToAllUnnamed(m, pn); } } else { diff -r a053dcc2d986 -r e8db842f5496 jdk/src/java.base/share/classes/module-info.java --- a/jdk/src/java.base/share/classes/module-info.java Sat Mar 25 00:31:29 2017 +0100 +++ b/jdk/src/java.base/share/classes/module-info.java Thu Mar 30 19:55:04 2017 +0200 @@ -26,6 +26,7 @@ /** * Defines the foundational APIs of the Java SE Platform. * + * @moduleGraph * @since 9 */ module java.base { diff -r a053dcc2d986 -r e8db842f5496 jdk/src/java.base/share/classes/sun/launcher/LauncherHelper.java --- a/jdk/src/java.base/share/classes/sun/launcher/LauncherHelper.java Sat Mar 25 00:31:29 2017 +0100 +++ b/jdk/src/java.base/share/classes/sun/launcher/LauncherHelper.java Thu Mar 30 19:55:04 2017 +0200 @@ -85,7 +85,6 @@ import java.util.stream.Stream; import jdk.internal.misc.VM; -import jdk.internal.module.IllegalAccessLogger; import jdk.internal.module.Modules; @@ -429,20 +428,14 @@ 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 @@ * Process the Add-Exports or Add-Opens value. The value is * {@code / ( /)*}. */ - 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 @@ 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: diff -r a053dcc2d986 -r e8db842f5496 jdk/src/java.base/share/classes/sun/launcher/resources/launcher.properties --- a/jdk/src/java.base/share/classes/sun/launcher/resources/launcher.properties Sat Mar 25 00:31:29 2017 +0100 +++ b/jdk/src/java.base/share/classes/sun/launcher/resources/launcher.properties Thu Mar 30 19:55:04 2017 +0200 @@ -211,6 +211,4 @@ 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 diff -r a053dcc2d986 -r e8db842f5496 jdk/src/java.base/share/classes/sun/security/tools/keytool/Main.java --- a/jdk/src/java.base/share/classes/sun/security/tools/keytool/Main.java Sat Mar 25 00:31:29 2017 +0100 +++ b/jdk/src/java.base/share/classes/sun/security/tools/keytool/Main.java Thu Mar 30 19:55:04 2017 +0200 @@ -1025,6 +1025,13 @@ 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 @@ if (keyPass == null) { keyPass = promptForKeyPass(alias, null, storePass); } + checkWeak(rb.getString("the.generated.certificate"), chain[0]); keyStore.setKeyEntry(alias, privKey, keyPass, chain); - - checkWeak(rb.getString("the.generated.certificate"), chain[0]); } /** @@ -2118,6 +2124,10 @@ } 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 @@ "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 @@ } if (noprompt) { + checkWeak(rb.getString("the.input"), cert); keyStore.setCertificateEntry(alias, cert); - checkWeak(rb.getString("the.input"), cert); return true; } @@ -3049,6 +3055,11 @@ 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 @@ cert.getNotAfter().toString(), getCertFingerPrint("SHA-1", cert), getCertFingerPrint("SHA-256", cert), - withWeak(cert.getSigAlgName()), + sigName, withWeak(pkey), cert.getVersion() }; @@ -3111,7 +3122,7 @@ * or null otherwise. A label is added. */ private static Pair - 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 @@ // do we trust the cert at the top? Certificate topCert = replyCerts[replyCerts.length-1]; boolean fromKeyStore = true; - Pair root = getTrustedSigner(topCert, keyStore); + Pair 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 @@ 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 @@ } } - 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 @@ 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()); } } diff -r a053dcc2d986 -r e8db842f5496 jdk/src/java.datatransfer/share/classes/module-info.java --- a/jdk/src/java.datatransfer/share/classes/module-info.java Sat Mar 25 00:31:29 2017 +0100 +++ b/jdk/src/java.datatransfer/share/classes/module-info.java Thu Mar 30 19:55:04 2017 +0200 @@ -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 { diff -r a053dcc2d986 -r e8db842f5496 jdk/src/java.desktop/share/classes/module-info.java --- a/jdk/src/java.desktop/share/classes/module-info.java Sat Mar 25 00:31:29 2017 +0100 +++ b/jdk/src/java.desktop/share/classes/module-info.java Thu Mar 30 19:55:04 2017 +0200 @@ -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 { diff -r a053dcc2d986 -r e8db842f5496 jdk/src/java.instrument/share/classes/module-info.java --- a/jdk/src/java.instrument/share/classes/module-info.java Sat Mar 25 00:31:29 2017 +0100 +++ b/jdk/src/java.instrument/share/classes/module-info.java Thu Mar 30 19:55:04 2017 +0200 @@ -27,6 +27,7 @@ * Defines services that allow agents to * instrument programs running on the JVM. * + * @moduleGraph * @since 9 */ module java.instrument { diff -r a053dcc2d986 -r e8db842f5496 jdk/src/java.logging/share/classes/module-info.java --- a/jdk/src/java.logging/share/classes/module-info.java Sat Mar 25 00:31:29 2017 +0100 +++ b/jdk/src/java.logging/share/classes/module-info.java Thu Mar 30 19:55:04 2017 +0200 @@ -26,6 +26,7 @@ /** * Defines the Java Logging API. * + * @moduleGraph * @since 9 */ module java.logging { diff -r a053dcc2d986 -r e8db842f5496 jdk/src/java.management.rmi/share/classes/module-info.java --- a/jdk/src/java.management.rmi/share/classes/module-info.java Sat Mar 25 00:31:29 2017 +0100 +++ b/jdk/src/java.management.rmi/share/classes/module-info.java Thu Mar 30 19:55:04 2017 +0200 @@ -46,6 +46,7 @@ * and load the appropriate {@code JMXConnectorServerProvider} service * implementation for the given protocol. * + * @moduleGraph * @since 9 */ module java.management.rmi { diff -r a053dcc2d986 -r e8db842f5496 jdk/src/java.management/share/classes/module-info.java --- a/jdk/src/java.management/share/classes/module-info.java Sat Mar 25 00:31:29 2017 +0100 +++ b/jdk/src/java.management/share/classes/module-info.java Thu Mar 30 19:55:04 2017 +0200 @@ -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 { diff -r a053dcc2d986 -r e8db842f5496 jdk/src/java.naming/share/classes/module-info.java --- a/jdk/src/java.naming/share/classes/module-info.java Sat Mar 25 00:31:29 2017 +0100 +++ b/jdk/src/java.naming/share/classes/module-info.java Thu Mar 30 19:55:04 2017 +0200 @@ -26,6 +26,7 @@ /** * Defines the Java Naming and Directory Interface (JNDI) API. * + * @moduleGraph * @since 9 */ module java.naming { diff -r a053dcc2d986 -r e8db842f5496 jdk/src/java.prefs/share/classes/module-info.java --- a/jdk/src/java.prefs/share/classes/module-info.java Sat Mar 25 00:31:29 2017 +0100 +++ b/jdk/src/java.prefs/share/classes/module-info.java Thu Mar 30 19:55:04 2017 +0200 @@ -26,6 +26,7 @@ /** * Defines the Preferences API. * + * @moduleGraph * @since 9 */ module java.prefs { diff -r a053dcc2d986 -r e8db842f5496 jdk/src/java.rmi/share/classes/module-info.java --- a/jdk/src/java.rmi/share/classes/module-info.java Sat Mar 25 00:31:29 2017 +0100 +++ b/jdk/src/java.rmi/share/classes/module-info.java Thu Mar 30 19:55:04 2017 +0200 @@ -26,6 +26,7 @@ /** * Defines the Remote Method Invocation (RMI) API. * + * @moduleGraph * @since 9 */ module java.rmi { diff -r a053dcc2d986 -r e8db842f5496 jdk/src/java.scripting/share/classes/module-info.java --- a/jdk/src/java.scripting/share/classes/module-info.java Sat Mar 25 00:31:29 2017 +0100 +++ b/jdk/src/java.scripting/share/classes/module-info.java Thu Mar 30 19:55:04 2017 +0200 @@ -26,6 +26,7 @@ /** * Defines the Scripting API. * + * @moduleGraph * @since 9 */ module java.scripting { diff -r a053dcc2d986 -r e8db842f5496 jdk/src/java.se.ee/share/classes/module-info.java --- a/jdk/src/java.se.ee/share/classes/module-info.java Sat Mar 25 00:31:29 2017 +0100 +++ b/jdk/src/java.se.ee/share/classes/module-info.java Thu Mar 30 19:55:04 2017 +0200 @@ -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") diff -r a053dcc2d986 -r e8db842f5496 jdk/src/java.se/share/classes/module-info.java --- a/jdk/src/java.se/share/classes/module-info.java Sat Mar 25 00:31:29 2017 +0100 +++ b/jdk/src/java.se/share/classes/module-info.java Thu Mar 30 19:55:04 2017 +0200 @@ -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 { diff -r a053dcc2d986 -r e8db842f5496 jdk/src/java.security.jgss/share/classes/module-info.java --- a/jdk/src/java.security.jgss/share/classes/module-info.java Sat Mar 25 00:31:29 2017 +0100 +++ b/jdk/src/java.security.jgss/share/classes/module-info.java Thu Mar 30 19:55:04 2017 +0200 @@ -28,6 +28,7 @@ *

* This module also contains GSS-API mechanisms including Kerberos v5 and SPNEGO. * + * @moduleGraph * @since 9 */ module java.security.jgss { diff -r a053dcc2d986 -r e8db842f5496 jdk/src/java.security.sasl/share/classes/module-info.java --- a/jdk/src/java.security.sasl/share/classes/module-info.java Sat Mar 25 00:31:29 2017 +0100 +++ b/jdk/src/java.security.sasl/share/classes/module-info.java Thu Mar 30 19:55:04 2017 +0200 @@ -30,6 +30,7 @@ * This module also contains SASL mechanisms including DIGEST-MD5, * CRAM-MD5, and NTLM. * + * @moduleGraph * @since 9 */ module java.security.sasl { diff -r a053dcc2d986 -r e8db842f5496 jdk/src/java.smartcardio/share/classes/module-info.java --- a/jdk/src/java.smartcardio/share/classes/module-info.java Sat Mar 25 00:31:29 2017 +0100 +++ b/jdk/src/java.smartcardio/share/classes/module-info.java Thu Mar 30 19:55:04 2017 +0200 @@ -26,6 +26,7 @@ /** * Defines the Java Smart Card I/O API. * + * @moduleGraph * @since 9 */ module java.smartcardio { diff -r a053dcc2d986 -r e8db842f5496 jdk/src/java.sql.rowset/share/classes/module-info.java --- a/jdk/src/java.sql.rowset/share/classes/module-info.java Sat Mar 25 00:31:29 2017 +0100 +++ b/jdk/src/java.sql.rowset/share/classes/module-info.java Thu Mar 30 19:55:04 2017 +0200 @@ -26,6 +26,7 @@ /** * Defines the JDBC RowSet API. * + * @moduleGraph * @since 9 */ module java.sql.rowset { diff -r a053dcc2d986 -r e8db842f5496 jdk/src/java.sql/share/classes/module-info.java --- a/jdk/src/java.sql/share/classes/module-info.java Sat Mar 25 00:31:29 2017 +0100 +++ b/jdk/src/java.sql/share/classes/module-info.java Thu Mar 30 19:55:04 2017 +0200 @@ -26,6 +26,7 @@ /** * Defines the JDBC API. * + * @moduleGraph * @since 9 */ module java.sql { diff -r a053dcc2d986 -r e8db842f5496 jdk/src/java.transaction/share/classes/module-info.java --- a/jdk/src/java.transaction/share/classes/module-info.java Sat Mar 25 00:31:29 2017 +0100 +++ b/jdk/src/java.transaction/share/classes/module-info.java Thu Mar 30 19:55:04 2017 +0200 @@ -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) diff -r a053dcc2d986 -r e8db842f5496 jdk/src/java.xml.crypto/share/classes/module-info.java --- a/jdk/src/java.xml.crypto/share/classes/module-info.java Sat Mar 25 00:31:29 2017 +0100 +++ b/jdk/src/java.xml.crypto/share/classes/module-info.java Thu Mar 30 19:55:04 2017 +0200 @@ -24,8 +24,9 @@ */ /** - * Defines an API for XML cryptography. + * Defines the API for XML cryptography. * + * @moduleGraph * @since 9 */ module java.xml.crypto { diff -r a053dcc2d986 -r e8db842f5496 jdk/src/jdk.attach/share/classes/module-info.java --- a/jdk/src/jdk.attach/share/classes/module-info.java Sat Mar 25 00:31:29 2017 +0100 +++ b/jdk/src/jdk.attach/share/classes/module-info.java Thu Mar 30 19:55:04 2017 +0200 @@ -26,6 +26,7 @@ /** * Defines the attach API. * + * @moduleGraph * @since 9 */ module jdk.attach { diff -r a053dcc2d986 -r e8db842f5496 jdk/src/jdk.charsets/share/classes/module-info.java --- a/jdk/src/jdk.charsets/share/classes/module-info.java Sat Mar 25 00:31:29 2017 +0100 +++ b/jdk/src/jdk.charsets/share/classes/module-info.java Thu Mar 30 19:55:04 2017 +0200 @@ -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; diff -r a053dcc2d986 -r e8db842f5496 jdk/src/jdk.crypto.cryptoki/share/classes/module-info.java --- a/jdk/src/jdk.crypto.cryptoki/share/classes/module-info.java Sat Mar 25 00:31:29 2017 +0100 +++ b/jdk/src/jdk.crypto.cryptoki/share/classes/module-info.java Thu Mar 30 19:55:04 2017 +0200 @@ -26,6 +26,7 @@ /** * The SunPKCS11 security provider. * + * @moduleGraph * @since 9 */ module jdk.crypto.cryptoki { diff -r a053dcc2d986 -r e8db842f5496 jdk/src/jdk.crypto.ec/share/classes/module-info.java --- a/jdk/src/jdk.crypto.ec/share/classes/module-info.java Sat Mar 25 00:31:29 2017 +0100 +++ b/jdk/src/jdk.crypto.ec/share/classes/module-info.java Thu Mar 30 19:55:04 2017 +0200 @@ -26,6 +26,7 @@ /** * The SunEC security provider. * + * @moduleGraph * @since 9 */ module jdk.crypto.ec { diff -r a053dcc2d986 -r e8db842f5496 jdk/src/jdk.crypto.mscapi/windows/classes/module-info.java --- a/jdk/src/jdk.crypto.mscapi/windows/classes/module-info.java Sat Mar 25 00:31:29 2017 +0100 +++ b/jdk/src/jdk.crypto.mscapi/windows/classes/module-info.java Thu Mar 30 19:55:04 2017 +0200 @@ -26,6 +26,7 @@ /** * The SunMSCAPI security provider. * + * @moduleGraph * @since 9 */ module jdk.crypto.mscapi { diff -r a053dcc2d986 -r e8db842f5496 jdk/src/jdk.crypto.ucrypto/solaris/classes/module-info.java --- a/jdk/src/jdk.crypto.ucrypto/solaris/classes/module-info.java Sat Mar 25 00:31:29 2017 +0100 +++ b/jdk/src/jdk.crypto.ucrypto/solaris/classes/module-info.java Thu Mar 30 19:55:04 2017 +0200 @@ -26,6 +26,7 @@ /** * The OracleUCrypto security provider. * + * @moduleGraph * @since 9 */ module jdk.crypto.ucrypto { diff -r a053dcc2d986 -r e8db842f5496 jdk/src/jdk.httpserver/share/classes/module-info.java --- a/jdk/src/jdk.httpserver/share/classes/module-info.java Sat Mar 25 00:31:29 2017 +0100 +++ b/jdk/src/jdk.httpserver/share/classes/module-info.java Thu Mar 30 19:55:04 2017 +0200 @@ -23,6 +23,12 @@ * questions. */ +/** + * Defines the JDK-specific API for HTTP server. + * + * @moduleGraph + * @since 9 + */ module jdk.httpserver { exports com.sun.net.httpserver; diff -r a053dcc2d986 -r e8db842f5496 jdk/src/jdk.jartool/share/classes/module-info.java --- a/jdk/src/jdk.jartool/share/classes/module-info.java Sat Mar 25 00:31:29 2017 +0100 +++ b/jdk/src/jdk.jartool/share/classes/module-info.java Thu Mar 30 19:55:04 2017 +0200 @@ -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; diff -r a053dcc2d986 -r e8db842f5496 jdk/src/jdk.jcmd/share/classes/module-info.java --- a/jdk/src/jdk.jcmd/share/classes/module-info.java Sat Mar 25 00:31:29 2017 +0100 +++ b/jdk/src/jdk.jcmd/share/classes/module-info.java Thu Mar 30 19:55:04 2017 +0200 @@ -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; diff -r a053dcc2d986 -r e8db842f5496 jdk/src/jdk.jconsole/share/classes/module-info.java --- a/jdk/src/jdk.jconsole/share/classes/module-info.java Sat Mar 25 00:31:29 2017 +0100 +++ b/jdk/src/jdk.jconsole/share/classes/module-info.java Thu Mar 30 19:55:04 2017 +0200 @@ -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; diff -r a053dcc2d986 -r e8db842f5496 jdk/src/jdk.jdi/share/classes/module-info.java --- a/jdk/src/jdk.jdi/share/classes/module-info.java Sat Mar 25 00:31:29 2017 +0100 +++ b/jdk/src/jdk.jdi/share/classes/module-info.java Thu Mar 30 19:55:04 2017 +0200 @@ -26,6 +26,7 @@ /** * Defines the Java Debugger Interface. * + * @moduleGraph * @since 9 */ module jdk.jdi { diff -r a053dcc2d986 -r e8db842f5496 jdk/src/jdk.jdwp.agent/share/classes/module-info.java --- a/jdk/src/jdk.jdwp.agent/share/classes/module-info.java Sat Mar 25 00:31:29 2017 +0100 +++ b/jdk/src/jdk.jdwp.agent/share/classes/module-info.java Thu Mar 30 19:55:04 2017 +0200 @@ -26,6 +26,7 @@ /** * Java Debug Wire Protocol. * + * @moduleGraph * @since 9 */ module jdk.jdwp.agent { diff -r a053dcc2d986 -r e8db842f5496 jdk/src/jdk.jlink/share/classes/jdk/tools/jimage/JImageTask.java --- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jimage/JImageTask.java Sat Mar 25 00:31:29 2017 +0100 +++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jimage/JImageTask.java Thu Mar 30 19:55:04 2017 +0200 @@ -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.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 @@ } static class OptionsValues { - Task task = Task.LIST; + Task task = null; String directory = "."; String include = ""; boolean fullVersion; @@ -172,24 +176,31 @@ } try { - List 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 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", ""); + if (options.task == null && !options.help && !options.version && !options.fullVersion) { + throw TASK_HELPER.newBadArgs("err.not.a.task", + command != null ? command : ""); } 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 @@ 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) { + 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 @@ 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; diff -r a053dcc2d986 -r e8db842f5496 jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/Jlink.java --- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/Jlink.java Sat Mar 25 00:31:29 2017 +0100 +++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/Jlink.java Thu Mar 30 19:55:04 2017 +0200 @@ -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.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 @@ private final Path output; private final Set modules; private final Set limitmods; - private final ByteOrder endian; + private final ModuleFinder finder; /** * jlink configuration, @@ -160,31 +164,23 @@ * @param endian Jimage byte order. Native order by default */ public JlinkConfiguration(Path output, - List modulepaths, - Set modules, - Set 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 modulepaths, + Set modules, + Set 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 modulepaths, - Set modules, - Set 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 @@ 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(); diff -r a053dcc2d986 -r e8db842f5496 jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/JlinkTask.java --- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/JlinkTask.java Sat Mar 25 00:31:29 2017 +0100 +++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/JlinkTask.java Thu Mar 30 19:55:04 2017 +0200 @@ -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 @@ Path path = Paths.get(arg); task.options.output = path; }, "--output"), + new Option(false, (task, opt, arg) -> { + task.options.bindServices = true; + }, "--bind-services"), + new Option(false, (task, opt, arg) -> { + task.options.suggestProviders = true; + }, "--suggest-providers", "", true), new Option(true, (task, opt, arg) -> { String[] values = arg.split("="); // check values @@ -141,6 +147,9 @@ } }, "--endian"), new Option(false, (task, opt, arg) -> { + task.options.verbose = true; + }, "--verbose", "-v"), + new Option(false, (task, opt, arg) -> { task.options.version = true; }, "--version"), new Option(true, (task, opt, arg) -> { @@ -185,6 +194,7 @@ static class OptionsValues { boolean help; String saveoptsfile; + boolean verbose; boolean version; boolean fullVersion; final List modulePath = new ArrayList<>(); @@ -195,6 +205,8 @@ Path packagedModulesPath; ByteOrder endian = ByteOrder.nativeOrder(); boolean ignoreSigning = false; + boolean bindServices = false; + boolean suggestProviders = false; } int run(String[] args) { @@ -203,7 +215,11 @@ new PrintWriter(System.err, true)); } try { - optionsHelper.handleOptionsNoUnhandled(this, args); + List 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 @@ 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 @@ 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 @@ // 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 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 @@ } } - 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 @@ return Paths.get(uri); } - private static ImageProvider createImageProvider(ModuleFinder finder, - Set 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 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 @@ Map 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 roots, - Set otherMods) { + public static ModuleFinder limitFinder(ModuleFinder finder, + Set roots, + Set otherMods) { // resolve all root modules Configuration cf = Configuration.empty() @@ -484,6 +503,147 @@ }; } + /* + * Returns a map of each service type to the modules that use it + */ + private static Map> uses(Set modules) { + // collects the services used by the modules and print uses + Map> 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 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 modules, + Map> uses) { + if (modules.isEmpty()) + return; + + // Build a map of a service type to the provider modules + Map> 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 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 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 names = Stream.of(args.get(0).split(",")) + .collect(Collectors.toSet()); + // find the modules that provide the specified service + Set 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> 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 collection) { + return collection.stream().sorted() + .collect(Collectors.joining(",")); + } + private String getSaveOpts() { StringBuilder sb = new StringBuilder(); sb.append('#').append(new Date()).append("\n"); diff -r a053dcc2d986 -r e8db842f5496 jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/TaskHelper.java --- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/TaskHelper.java Sat Mar 25 00:31:29 2017 +0100 +++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/TaskHelper.java Thu Mar 30 19:55:04 2017 +0200 @@ -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.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 @@ final boolean hidden; final String name; final String shortname; + final boolean terminalOption; - public Option(boolean hasArg, Processing processing, boolean hidden, String name, String shortname) { + public Option(boolean hasArg, + Processing processing, + boolean hidden, + String name, + String shortname, + boolean isTerminal) + { if (!name.startsWith("--")) { throw new RuntimeException("option name missing --, " + name); } @@ -115,24 +123,33 @@ this.hidden = hidden; this.name = name; this.shortname = shortname; + this.terminalOption = isTerminal; + } + + public Option(boolean hasArg, Processing processing, String name, String shortname, boolean isTerminal) { + this(hasArg, processing, false, name, shortname, isTerminal); } public Option(boolean hasArg, Processing processing, String name, String shortname) { - this(hasArg, processing, false, name, shortname); + this(hasArg, processing, false, name, shortname, false); } public Option(boolean hasArg, Processing processing, boolean hidden, String name) { - this(hasArg, processing, hidden, name, ""); + this(hasArg, processing, hidden, name, "", false); } public Option(boolean hasArg, Processing 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 @@ private static class PluginOption extends Option { public PluginOption(boolean hasArg, Processing 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 processing, boolean hidden, String name) { - super(hasArg, processing, hidden, name, ""); + super(hasArg, processing, hidden, name, "", false); } public String resourcePrefix() { @@ -498,21 +515,13 @@ 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 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 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 @@ // Unit tests can call Task multiple time in same JVM. pluginOptions = new PluginsHelper(null); - List rest = collectUnhandled? new ArrayList<>() : null; // process options for (int i = 0; i < args.length; i++) { if (args[i].startsWith("-")) { @@ -531,7 +539,6 @@ if (option == null) { pluginOption = pluginOptions.getOption(name); if (pluginOption == null) { - throw new BadArgs("err.unknown.option", name). showUsage(true); } @@ -556,20 +563,23 @@ 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 getOption(String name) { diff -r a053dcc2d986 -r e8db842f5496 jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/packager/AppRuntimeImageBuilder.java --- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/packager/AppRuntimeImageBuilder.java Sat Mar 25 00:31:29 2017 +0100 +++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/packager/AppRuntimeImageBuilder.java Thu Mar 30 19:55:04 2017 +0200 @@ -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 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 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 plugins = new ArrayList(); diff -r a053dcc2d986 -r e8db842f5496 jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/resources/jlink.properties --- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/resources/jlink.properties Sat Mar 25 00:31:29 2017 +0100 +++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/resources/jlink.properties Thu Mar 30 19:55:04 2017 +0200 @@ -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} --module-path --add-modules --output\n\ -\ use --help for a list of possible options +Usage: {0} --module-path --add-modules [,...]\n\ +\Use --help for a list of possible options main.usage=\ -Usage: {0} --module-path --add-modules --output\n\ -\ Possible options include: - -error.prefix=Error: -warn.prefix=Warning: +Usage: {0} --module-path --add-modules [,...]\n\ +\Possible options include: main.opt.help=\ \ -h, --help Print this help message @@ -54,9 +51,18 @@ \ --output Location of output path main.opt.launcher=\ -\ --launcher = Launcher command name for the module\n\ -\ --launcher =/

\n\ -\ Launcher command name for the module and the main class +\ --launcher =[/]\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 [,...] Suggest providers of services used by\n\ +\ the modules that would be linked, or\n\ +\ of the given service types main.command.files=\ \ @ Read options from file @@ -75,6 +81,9 @@ \ 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 @@ \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.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 @@ 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 diff -r a053dcc2d986 -r e8db842f5496 jdk/src/jdk.jlink/share/classes/module-info.java --- a/jdk/src/jdk.jlink/share/classes/module-info.java Sat Mar 25 00:31:29 2017 +0100 +++ b/jdk/src/jdk.jlink/share/classes/module-info.java Thu Mar 30 19:55:04 2017 +0200 @@ -23,6 +23,12 @@ * questions. */ +/** + * Defines the Java linker tool, jlink. + * + * @moduleGraph + * @since 9 + */ module jdk.jlink { requires jdk.internal.opt; requires jdk.jdeps; diff -r a053dcc2d986 -r e8db842f5496 jdk/src/jdk.jsobject/share/classes/module-info.java --- a/jdk/src/jdk.jsobject/share/classes/module-info.java Sat Mar 25 00:31:29 2017 +0100 +++ b/jdk/src/jdk.jsobject/share/classes/module-info.java Thu Mar 30 19:55:04 2017 +0200 @@ -23,6 +23,12 @@ * questions. */ +/** + * Defines the API for the JavaScript Object. + * + * @moduleGraph + * @since 9 + */ module jdk.jsobject { requires java.desktop; exports netscape.javascript; diff -r a053dcc2d986 -r e8db842f5496 jdk/src/jdk.jstatd/share/classes/module-info.java --- a/jdk/src/jdk.jstatd/share/classes/module-info.java Sat Mar 25 00:31:29 2017 +0100 +++ b/jdk/src/jdk.jstatd/share/classes/module-info.java Thu Mar 30 19:55:04 2017 +0200 @@ -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 @@ provides sun.jvmstat.monitor.MonitoredHostService with sun.jvmstat.perfdata.monitor.protocol.rmi.MonitoredHostRmiService; } - diff -r a053dcc2d986 -r e8db842f5496 jdk/src/jdk.localedata/share/classes/module-info.java --- a/jdk/src/jdk.localedata/share/classes/module-info.java Sat Mar 25 00:31:29 2017 +0100 +++ b/jdk/src/jdk.localedata/share/classes/module-info.java Thu Mar 30 19:55:04 2017 +0200 @@ -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, diff -r a053dcc2d986 -r e8db842f5496 jdk/src/jdk.management.agent/share/classes/module-info.java --- a/jdk/src/jdk.management.agent/share/classes/module-info.java Sat Mar 25 00:31:29 2017 +0100 +++ b/jdk/src/jdk.management.agent/share/classes/module-info.java Thu Mar 30 19:55:04 2017 +0200 @@ -23,6 +23,12 @@ * questions. */ +/** + * Define the JMX management agent. + * + * @moduleGraph + * @since 9 + */ module jdk.management.agent { requires java.management; requires java.management.rmi; diff -r a053dcc2d986 -r e8db842f5496 jdk/src/jdk.management/share/classes/module-info.java --- a/jdk/src/jdk.management/share/classes/module-info.java Sat Mar 25 00:31:29 2017 +0100 +++ b/jdk/src/jdk.management/share/classes/module-info.java Thu Mar 30 19:55:04 2017 +0200 @@ -23,6 +23,12 @@ * questions. */ +/** + * Defines the JDK-specific Management Interfaces for JVM. + * + * @moduleGraph + * @since 9 + */ module jdk.management { requires transitive java.management; diff -r a053dcc2d986 -r e8db842f5496 jdk/src/jdk.naming.dns/share/classes/module-info.java --- a/jdk/src/jdk.naming.dns/share/classes/module-info.java Sat Mar 25 00:31:29 2017 +0100 +++ b/jdk/src/jdk.naming.dns/share/classes/module-info.java Thu Mar 30 19:55:04 2017 +0200 @@ -23,6 +23,12 @@ * questions. */ +/** + * DNS Java Naming provider. + * + * @moduleGraph + * @since 9 + */ module jdk.naming.dns { requires java.naming; diff -r a053dcc2d986 -r e8db842f5496 jdk/src/jdk.naming.rmi/share/classes/module-info.java --- a/jdk/src/jdk.naming.rmi/share/classes/module-info.java Sat Mar 25 00:31:29 2017 +0100 +++ b/jdk/src/jdk.naming.rmi/share/classes/module-info.java Thu Mar 30 19:55:04 2017 +0200 @@ -23,6 +23,12 @@ * questions. */ +/** + * RMI Java Naming provider. + * + * @moduleGraph + * @since 9 + */ module jdk.naming.rmi { requires java.naming; requires java.rmi; diff -r a053dcc2d986 -r e8db842f5496 jdk/src/jdk.net/share/classes/module-info.java --- a/jdk/src/jdk.net/share/classes/module-info.java Sat Mar 25 00:31:29 2017 +0100 +++ b/jdk/src/jdk.net/share/classes/module-info.java Thu Mar 30 19:55:04 2017 +0200 @@ -23,6 +23,12 @@ * questions. */ +/** + * Defines the JDK-specific Networking API. + * + * @moduleGraph + * @since 9 + */ module jdk.net { exports jdk.net; } diff -r a053dcc2d986 -r e8db842f5496 jdk/src/jdk.sctp/share/classes/module-info.java --- a/jdk/src/jdk.sctp/share/classes/module-info.java Sat Mar 25 00:31:29 2017 +0100 +++ b/jdk/src/jdk.sctp/share/classes/module-info.java Thu Mar 30 19:55:04 2017 +0200 @@ -23,6 +23,12 @@ * questions. */ +/** + * Defines the JDK-specific API for SCTP. + * + * @moduleGraph + * @since 9 + */ module jdk.sctp { exports com.sun.nio.sctp; } diff -r a053dcc2d986 -r e8db842f5496 jdk/src/jdk.security.auth/share/classes/module-info.java --- a/jdk/src/jdk.security.auth/share/classes/module-info.java Sat Mar 25 00:31:29 2017 +0100 +++ b/jdk/src/jdk.security.auth/share/classes/module-info.java Thu Mar 30 19:55:04 2017 +0200 @@ -27,6 +27,7 @@ * Contains the implementation of the javax.security.auth.* interfaces and * various authentication modules. * + * @moduleGraph * @since 9 */ module jdk.security.auth { diff -r a053dcc2d986 -r e8db842f5496 jdk/src/jdk.security.jgss/share/classes/module-info.java --- a/jdk/src/jdk.security.jgss/share/classes/module-info.java Sat Mar 25 00:31:29 2017 +0100 +++ b/jdk/src/jdk.security.jgss/share/classes/module-info.java Thu Mar 30 19:55:04 2017 +0200 @@ -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 { diff -r a053dcc2d986 -r e8db842f5496 jdk/src/jdk.zipfs/share/classes/module-info.java --- a/jdk/src/jdk.zipfs/share/classes/module-info.java Sat Mar 25 00:31:29 2017 +0100 +++ b/jdk/src/jdk.zipfs/share/classes/module-info.java Thu Mar 30 19:55:04 2017 +0200 @@ -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; } diff -r a053dcc2d986 -r e8db842f5496 jdk/test/ProblemList.txt --- a/jdk/test/ProblemList.txt Sat Mar 25 00:31:29 2017 +0100 +++ b/jdk/test/ProblemList.txt Thu Mar 30 19:55:04 2017 +0200 @@ -180,8 +180,6 @@ 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 diff -r a053dcc2d986 -r e8db842f5496 jdk/test/TEST.groups --- a/jdk/test/TEST.groups Sat Mar 25 00:31:29 2017 +0100 +++ b/jdk/test/TEST.groups Thu Mar 30 19:55:04 2017 +0200 @@ -73,6 +73,7 @@ jdk/internal/misc \ jdk/internal/ref \ jdk/internal/jimage \ + jdk/internal/math \ jdk/modules \ vm @@ -141,8 +142,7 @@ java/util/stream jdk_math = \ - java/math \ - jdk/internal/math + java/math jdk_io = \ java/io diff -r a053dcc2d986 -r e8db842f5496 jdk/test/java/nio/channels/DatagramChannel/NetworkConfiguration.java --- a/jdk/test/java/nio/channels/DatagramChannel/NetworkConfiguration.java Sat Mar 25 00:31:29 2017 +0100 +++ b/jdk/test/java/nio/channels/DatagramChannel/NetworkConfiguration.java Thu Mar 30 19:55:04 2017 +0200 @@ -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 @@ 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> ip4Interfaces = new HashMap>(); Map> ip6Interfaces = new HashMap>(); - boolean isIPv6Supported = isIPv6Supported(); // find the interfaces that support IPv4 and IPv6 List nifs = Collections @@ -92,7 +81,7 @@ } list.add(addr); ip4Interfaces.put(nif, list); - } else if (isIPv6Supported && (addr instanceof Inet6Address)) { + } else if (addr instanceof Inet6Address) { List list = ip6Interfaces.get(nif); if (list == null) { list = new LinkedList(); diff -r a053dcc2d986 -r e8db842f5496 jdk/test/java/nio/channels/FileChannel/Transfer4GBFile.java --- a/jdk/test/java/nio/channels/FileChannel/Transfer4GBFile.java Sat Mar 25 00:31:29 2017 +0100 +++ b/jdk/test/java/nio/channels/FileChannel/Transfer4GBFile.java Thu Mar 30 19:55:04 2017 +0200 @@ -52,11 +52,6 @@ // 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; diff -r a053dcc2d986 -r e8db842f5496 jdk/test/java/nio/channels/FileChannel/TransferTo6GBFile.java --- a/jdk/test/java/nio/channels/FileChannel/TransferTo6GBFile.java Sat Mar 25 00:31:29 2017 +0100 +++ b/jdk/test/java/nio/channels/FileChannel/TransferTo6GBFile.java Thu Mar 30 19:55:04 2017 +0200 @@ -50,11 +50,6 @@ // 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 diff -r a053dcc2d986 -r e8db842f5496 jdk/test/java/nio/channels/Selector/OutOfBand.java --- a/jdk/test/java/nio/channels/Selector/OutOfBand.java Sat Mar 25 00:31:29 2017 +0100 +++ b/jdk/test/java/nio/channels/Selector/OutOfBand.java Thu Mar 30 19:55:04 2017 +0200 @@ -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 */ diff -r a053dcc2d986 -r e8db842f5496 jdk/test/java/nio/channels/Selector/SelectorLimit.java --- a/jdk/test/java/nio/channels/Selector/SelectorLimit.java Sat Mar 25 00:31:29 2017 +0100 +++ b/jdk/test/java/nio/channels/Selector/SelectorLimit.java Thu Mar 30 19:55:04 2017 +0200 @@ -66,15 +66,6 @@ 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); diff -r a053dcc2d986 -r e8db842f5496 jdk/test/sun/security/tools/keytool/WeakAlg.java --- a/jdk/test/sun/security/tools/keytool/WeakAlg.java Sat Mar 25 00:31:29 2017 +0100 +++ b/jdk/test/sun/security/tools/keytool/WeakAlg.java Thu Mar 30 19:55:04 2017 +0200 @@ -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 @@ .shouldMatch(".*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 @@ .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 @@ } } 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") @@ -266,6 +295,26 @@ // install reply reStore(); + certreq("c", ""); + gencert("a-c", ""); + kt("-importcert -alias c -file a-c.cert") + .shouldContain("Warning") + .shouldMatch("Issuer .*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", ""); gencert("b-c", ""); diff -r a053dcc2d986 -r e8db842f5496 jdk/test/tools/jlink/IntegrationTest.java --- a/jdk/test/tools/jlink/IntegrationTest.java Sat Mar 25 00:31:29 2017 +0100 +++ b/jdk/test/tools/jlink/IntegrationTest.java Thu Mar 30 19:55:04 2017 +0200 @@ -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.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 @@ } 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 @@ Set limits = new HashSet<>(); limits.add("java.management"); JlinkConfiguration config = new Jlink.JlinkConfiguration(output, - modulePaths, mods, limits, null); + modulePaths, mods, limits, ByteOrder.nativeOrder()); List lst = new ArrayList<>(); diff -r a053dcc2d986 -r e8db842f5496 jdk/test/tools/jlink/JLinkTest.java --- a/jdk/test/tools/jlink/JLinkTest.java Sat Mar 25 00:31:29 2017 +0100 +++ b/jdk/test/tools/jlink/JLinkTest.java Thu Mar 30 19:55:04 2017 +0200 @@ -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 @@ 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 @@ 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 diff -r a053dcc2d986 -r e8db842f5496 jdk/test/tools/jlink/bindservices/BindServices.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/tools/jlink/bindservices/BindServices.java Thu Mar 30 19:55:04 2017 +0200 @@ -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 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 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 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 output() { + return output; + } + } +} diff -r a053dcc2d986 -r e8db842f5496 jdk/test/tools/jlink/bindservices/SuggestProviders.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/tools/jlink/bindservices/SuggestProviders.java Thu Mar 30 19:55:04 2017 +0200 @@ -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 output = JLink.run("--module-path", MODULE_PATH, + "--add-modules", "m1", + "--suggest-providers").output(); + // check a subset of services used by java.base + List 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 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 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 output = + JLink.run("--module-path", MODULE_PATH, + "--add-modules", "m1", + "--suggest-providers", + "nonExistentType").output(); + + System.out.println(output); + List 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 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 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 output() { + return output; + } + } +} diff -r a053dcc2d986 -r e8db842f5496 jdk/test/tools/jlink/bindservices/src/m1/module-info.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/tools/jlink/bindservices/src/m1/module-info.java Thu Mar 30 19:55:04 2017 +0200 @@ -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; +} diff -r a053dcc2d986 -r e8db842f5496 jdk/test/tools/jlink/bindservices/src/m1/p1/Impl.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/tools/jlink/bindservices/src/m1/p1/Impl.java Thu Mar 30 19:55:04 2017 +0200 @@ -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(); + } +} diff -r a053dcc2d986 -r e8db842f5496 jdk/test/tools/jlink/bindservices/src/m1/p1/Main.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/tools/jlink/bindservices/src/m1/p1/Main.java Thu Mar 30 19:55:04 2017 +0200 @@ -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 modules = ModuleFinder.ofSystem().findAll().stream() + .map(mref -> mref.descriptor().name()) + .filter(mn -> !mn.equals("java.base")) + .collect(Collectors.toSet()); + + Set 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); + } + } +} diff -r a053dcc2d986 -r e8db842f5496 jdk/test/tools/jlink/bindservices/src/m1/p1/S.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/tools/jlink/bindservices/src/m1/p1/S.java Thu Mar 30 19:55:04 2017 +0200 @@ -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(); +} diff -r a053dcc2d986 -r e8db842f5496 jdk/test/tools/jlink/bindservices/src/m2/module-info.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/tools/jlink/bindservices/src/m2/module-info.java Thu Mar 30 19:55:04 2017 +0200 @@ -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; +} diff -r a053dcc2d986 -r e8db842f5496 jdk/test/tools/jlink/bindservices/src/m2/p2/Impl.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/tools/jlink/bindservices/src/m2/p2/Impl.java Thu Mar 30 19:55:04 2017 +0200 @@ -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() { + } +} diff -r a053dcc2d986 -r e8db842f5496 jdk/test/tools/jlink/bindservices/src/m2/p2/T.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/tools/jlink/bindservices/src/m2/p2/T.java Thu Mar 30 19:55:04 2017 +0200 @@ -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(); +} diff -r a053dcc2d986 -r e8db842f5496 jdk/test/tools/jlink/bindservices/src/m3/module-info.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/tools/jlink/bindservices/src/m3/module-info.java Thu Mar 30 19:55:04 2017 +0200 @@ -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; +} diff -r a053dcc2d986 -r e8db842f5496 jdk/test/tools/jlink/bindservices/src/m3/p3/Impl.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/tools/jlink/bindservices/src/m3/p3/Impl.java Thu Mar 30 19:55:04 2017 +0200 @@ -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() { + } +} diff -r a053dcc2d986 -r e8db842f5496 jdk/test/tools/launcher/modules/permit/PermitIllegalAccess.java --- a/jdk/test/tools/launcher/modules/permit/PermitIllegalAccess.java Sat Mar 25 00:31:29 2017 +0100 +++ b/jdk/test/tools/launcher/modules/permit/PermitIllegalAccess.java Thu Mar 30 19:55:04 2017 +0200 @@ -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 @@ * 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 s1 = Stream.of(args); + Stream 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 @@ * 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"); } /** @@ -195,6 +195,61 @@ } /** + * 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. */