# HG changeset patch # User prr # Date 1482190412 28800 # Node ID 0d1409532a4100d11518468c8b64cd7b769187a9 # Parent e5d5f0f2d40d2d4e0976f831cb9298ebd7e91955# Parent 74bcf37d15d83d171193be8230f4322df1d6e9e1 Merge diff -r e5d5f0f2d40d -r 0d1409532a41 jdk/src/java.base/share/classes/java/lang/reflect/Layer.java --- a/jdk/src/java.base/share/classes/java/lang/reflect/Layer.java Mon Dec 19 09:16:40 2016 -0800 +++ b/jdk/src/java.base/share/classes/java/lang/reflect/Layer.java Mon Dec 19 15:33:32 2016 -0800 @@ -602,12 +602,8 @@ checkGetClassLoaderPermission(); - // For now, no two modules in the boot Layer may contain the same - // package so we use a simple check for the boot Layer to keep - // the overhead at startup to a minimum - if (boot() == null) { - checkBootModulesForDuplicatePkgs(cf); - } else { + // The boot layer is checked during module system initialization + if (boot() != null) { checkForDuplicatePkgs(cf, clf); } @@ -657,27 +653,6 @@ } /** - * Checks a configuration for the boot Layer to ensure that no two modules - * have the same package. - * - * @throws LayerInstantiationException - */ - private static void checkBootModulesForDuplicatePkgs(Configuration cf) { - Map packageToModule = new HashMap<>(); - for (ResolvedModule resolvedModule : cf.modules()) { - ModuleDescriptor descriptor = resolvedModule.reference().descriptor(); - String name = descriptor.name(); - for (String p : descriptor.packages()) { - String other = packageToModule.putIfAbsent(p, name); - if (other != null) { - throw fail("Package " + p + " in both module " - + name + " and module " + other); - } - } - } - } - - /** * Checks a configuration and the module-to-loader mapping to ensure that * no two modules mapped to the same class loader have the same package. * It also checks that no two automatic modules have the same package. diff -r e5d5f0f2d40d -r 0d1409532a41 jdk/src/java.base/share/classes/java/util/ResourceBundle.java --- a/jdk/src/java.base/share/classes/java/util/ResourceBundle.java Mon Dec 19 09:16:40 2016 -0800 +++ b/jdk/src/java.base/share/classes/java/util/ResourceBundle.java Mon Dec 19 15:33:32 2016 -0800 @@ -60,7 +60,6 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.jar.JarEntry; -import java.util.spi.ResourceBundleControlProvider; import java.util.spi.ResourceBundleProvider; import jdk.internal.loader.BootLoader; @@ -232,8 +231,6 @@ *
  • {@code ResourceBundle.Control} is not supported in named modules. * If the {@code getBundle} method with a {@code ResourceBundle.Control} is called * in a named module, the method will throw an {@code UnsupportedOperationException}. - * Any service providers of {@link ResourceBundleControlProvider} are ignored in - * named modules. *
  • * * @@ -264,17 +261,6 @@ * {@link #getBundle(String, Locale, ClassLoader, Control) getBundle} * factory method for details. * - *

    For the {@code getBundle} factory - * methods that take no {@link Control} instance, their default behavior of resource bundle loading - * can be modified with installed {@link - * ResourceBundleControlProvider} implementations. Any installed providers are - * detected at the {@code ResourceBundle} class loading time. If any of the - * providers provides a {@link Control} for the given base name, that {@link - * Control} will be used instead of the default {@link Control}. If there is - * more than one service provider installed for supporting the same base name, - * the first one returned from {@link ServiceLoader} will be used. - * *

    Cache Management

    * * Resource bundle instances created by the getBundle factory @@ -469,21 +455,6 @@ */ private volatile Set keySet; - private static final List providers; - - static { - List list = null; - ServiceLoader serviceLoaders - = ServiceLoader.loadInstalled(ResourceBundleControlProvider.class); - for (ResourceBundleControlProvider provider : serviceLoaders) { - if (list == null) { - list = new ArrayList<>(); - } - list.add(provider); - } - providers = list; - } - /** * Sole constructor. (For invocation by subclass constructors, typically * implicit.) @@ -948,7 +919,7 @@ { Class caller = Reflection.getCallerClass(); return getBundleImpl(baseName, Locale.getDefault(), - caller, getDefaultControl(caller, baseName)); + caller, Control.INSTANCE); } /** @@ -1022,7 +993,7 @@ { Class caller = Reflection.getCallerClass(); return getBundleImpl(baseName, locale, - caller, getDefaultControl(caller, baseName)); + caller, Control.INSTANCE); } /** @@ -1163,10 +1134,7 @@ * *

    This method behaves the same as calling * {@link #getBundle(String, Locale, ClassLoader, Control)} passing a - * default instance of {@link Control} unless another {@link Control} is - * provided with the {@link ResourceBundleControlProvider} SPI. Refer to the - * description of modifying the default - * behavior. + * default instance of {@link Control}. * *

    The following describes the default * behavior. @@ -1364,7 +1332,7 @@ throw new NullPointerException(); } Class caller = Reflection.getCallerClass(); - return getBundleImpl(baseName, locale, caller, loader, getDefaultControl(caller, baseName)); + return getBundleImpl(baseName, locale, caller, loader, Control.INSTANCE); } /** @@ -1589,18 +1557,6 @@ return getBundleImpl(baseName, targetLocale, caller, loader, control); } - private static Control getDefaultControl(Class caller, String baseName) { - if (providers != null && !caller.getModule().isNamed()) { - for (ResourceBundleControlProvider provider : providers) { - Control control = provider.getControl(baseName); - if (control != null) { - return control; - } - } - } - return Control.INSTANCE; - } - private static void checkNamedModule(Class caller) { if (caller.getModule().isNamed()) { throw new UnsupportedOperationException( @@ -2573,8 +2529,7 @@ * @apiNote {@code ResourceBundle.Control} is not supported * in named modules. If the {@code ResourceBundle.getBundle} method with * a {@code ResourceBundle.Control} is called in a named module, the method - * will throw an {@link UnsupportedOperationException}. Any service providers - * of {@link ResourceBundleControlProvider} are ignored in named modules. + * will throw an {@link UnsupportedOperationException}. * * @since 1.6 * @see java.util.spi.ResourceBundleProvider diff -r e5d5f0f2d40d -r 0d1409532a41 jdk/src/java.base/share/classes/java/util/spi/ResourceBundleControlProvider.java --- a/jdk/src/java.base/share/classes/java/util/spi/ResourceBundleControlProvider.java Mon Dec 19 09:16:40 2016 -0800 +++ b/jdk/src/java.base/share/classes/java/util/spi/ResourceBundleControlProvider.java Mon Dec 19 15:33:32 2016 -0800 @@ -35,21 +35,19 @@ * no {@link java.util.ResourceBundle.Control} instance can be modified with {@code * ResourceBundleControlProvider} implementations. * - *

    Provider implementations must be packaged using the Java Extension - * Mechanism as installed extensions. Refer to {@link java.util.ServiceLoader} - * for the extension packaging. Any installed {@code - * ResourceBundleControlProvider} implementations are loaded using {@link - * java.util.ServiceLoader} at the {@code ResourceBundle} class loading time. - * - *

    All {@code ResourceBundleControlProvider}s are ignored in named modules. - * * @author Masayoshi Okutsu * @since 1.8 * @see ResourceBundle#getBundle(String, java.util.Locale, ClassLoader, ResourceBundle.Control) * ResourceBundle.getBundle * @see java.util.ServiceLoader#loadInstalled(Class) + * @deprecated There is no longer any mechanism to install a custom + * {@code ResourceBundleControlProvider} implementation defined + * by the platform class loader or its ancestor. The recommended + * way to use a custom {@code Control} implementation to load resource bundle + * is to use {@link java.util.ResourceBundle#getBundle(String, Control)} + * or other factory methods that take custom {@link java.util.ResourceBundle.Control}. */ +@Deprecated(since="9", forRemoval=true) public interface ResourceBundleControlProvider { /** * Returns a {@code ResourceBundle.Control} instance that is used diff -r e5d5f0f2d40d -r 0d1409532a41 jdk/src/java.base/share/classes/jdk/internal/module/ModuleBootstrap.java --- a/jdk/src/java.base/share/classes/jdk/internal/module/ModuleBootstrap.java Mon Dec 19 09:16:40 2016 -0800 +++ b/jdk/src/java.base/share/classes/jdk/internal/module/ModuleBootstrap.java Mon Dec 19 15:33:32 2016 -0800 @@ -306,8 +306,32 @@ fail(name + ": cannot be loaded from application module path"); } } + + // check if module specified in --patch-module is present + for (String mn: patcher.patchedModules()) { + if (!cf.findModule(mn).isPresent()) { + warnUnknownModule(PATCH_MODULE, mn); + } + } } + // if needed check that there are no split packages in the set of + // resolved modules for the boot layer + if (SystemModules.hasSplitPackages() || needPostResolutionChecks) { + Map packageToModule = new HashMap<>(); + for (ResolvedModule resolvedModule : cf.modules()) { + ModuleDescriptor descriptor = + resolvedModule.reference().descriptor(); + String name = descriptor.name(); + for (String p : descriptor.packages()) { + String other = packageToModule.putIfAbsent(p, name); + if (other != null) { + fail("Package " + p + " in both module " + + name + " and module " + other); + } + } + } + } long t4 = System.nanoTime(); @@ -464,7 +488,7 @@ String mn = e.getKey(); Optional om = bootLayer.findModule(mn); if (!om.isPresent()) { - warn("Unknown module: " + mn); + warnUnknownModule(ADD_READS, mn); continue; } Module m = om.get(); @@ -478,7 +502,7 @@ if (om.isPresent()) { Modules.addReads(m, om.get()); } else { - warn("Unknown module: " + name); + warnUnknownModule(ADD_READS, name); } } } @@ -510,24 +534,25 @@ Map> map, boolean opens) { + String option = opens ? ADD_OPENS : ADD_EXPORTS; for (Map.Entry> e : map.entrySet()) { // the key is $MODULE/$PACKAGE String key = e.getKey(); String[] s = key.split("/"); if (s.length != 2) - fail("Unable to parse as /: " + key); + fail(unableToParse(option, "/", key)); String mn = s[0]; String pn = s[1]; if (mn.isEmpty() || pn.isEmpty()) - fail("Module and package name must be specified: " + key); + fail(unableToParse(option, "/", key)); // The exporting module is in the boot layer Module m; Optional om = bootLayer.findModule(mn); if (!om.isPresent()) { - warn("Unknown module: " + mn); + warnUnknownModule(option, mn); continue; } @@ -549,7 +574,7 @@ if (om.isPresent()) { other = om.get(); } else { - warn("Unknown module: " + name); + warnUnknownModule(option, name); continue; } } @@ -593,24 +618,30 @@ int pos = value.indexOf('='); if (pos == -1) - fail("Unable to parse as =: " + value); + fail(unableToParse(option(prefix), "=", value)); if (pos == 0) - fail("Missing module name in: " + value); + fail(unableToParse(option(prefix), "=", value)); // key is or / String key = value.substring(0, pos); String rhs = value.substring(pos+1); if (rhs.isEmpty()) - fail("Unable to parse as =: " + value); + fail(unableToParse(option(prefix), "=", value)); // value is (,)* or ()* if (!allowDuplicates && map.containsKey(key)) - fail(key + " specified more than once"); + fail(key + " specified more than once in " + option(prefix)); List values = map.computeIfAbsent(key, k -> new ArrayList<>()); + int ntargets = 0; for (String s : rhs.split(regex)) { - if (s.length() > 0) values.add(s); + if (s.length() > 0) { + values.add(s); + ntargets++; + } } + if (ntargets == 0) + fail("Target must be specified: " + option(prefix) + " " + value); index++; value = getAndRemoveProperty(prefix + index); @@ -672,6 +703,42 @@ System.err.println("WARNING: " + m); } + static void warnUnknownModule(String option, String mn) { + warn("Unknown module: " + mn + " specified in " + option); + } + + static String unableToParse(String option, String text, String value) { + return "Unable to parse " + option + " " + text + ": " + value; + } + + private static final String ADD_MODULES = "--add-modules"; + private static final String ADD_EXPORTS = "--add-exports"; + private static final String ADD_OPENS = "--add-opens"; + private static final String ADD_READS = "--add-reads"; + private static final String PATCH_MODULE = "--patch-module"; + + + /* + * Returns the command-line option name corresponds to the specified + * system property prefix. + */ + static String option(String prefix) { + switch (prefix) { + case "jdk.module.addexports.": + return ADD_EXPORTS; + case "jdk.module.addopens.": + return ADD_OPENS; + case "jdk.module.addreads.": + return ADD_READS; + case "jdk.module.patch.": + return PATCH_MODULE; + case "jdk.module.addmods.": + return ADD_MODULES; + default: + throw new IllegalArgumentException(prefix); + } + } + static class PerfCounters { static PerfCounter systemModulesTime diff -r e5d5f0f2d40d -r 0d1409532a41 jdk/src/java.base/share/classes/jdk/internal/module/ModulePatcher.java --- a/jdk/src/java.base/share/classes/jdk/internal/module/ModulePatcher.java Mon Dec 19 09:16:40 2016 -0800 +++ b/jdk/src/java.base/share/classes/jdk/internal/module/ModulePatcher.java Mon Dec 19 15:33:32 2016 -0800 @@ -175,6 +175,12 @@ return map.isEmpty(); } + /* + * Returns the names of the patched modules. + */ + Set patchedModules() { + return map.keySet(); + } /** * A ModuleReader that reads resources from a patched module. diff -r e5d5f0f2d40d -r 0d1409532a41 jdk/src/java.base/share/classes/jdk/internal/module/SystemModules.java --- a/jdk/src/java.base/share/classes/jdk/internal/module/SystemModules.java Mon Dec 19 09:16:40 2016 -0800 +++ b/jdk/src/java.base/share/classes/jdk/internal/module/SystemModules.java Mon Dec 19 15:33:32 2016 -0800 @@ -57,6 +57,14 @@ public static int PACKAGES_IN_BOOT_LAYER = 1024; /** + * @return {@code false} if there are no split packages in the run-time + * image, {@code true} if there are or if it's not been checked. + */ + public static boolean hasSplitPackages() { + return true; + } + + /** * Returns a non-empty array of ModuleDescriptors in the run-time image. * * When running an exploded image it returns an empty array. diff -r e5d5f0f2d40d -r 0d1409532a41 jdk/src/java.base/share/native/libjli/java.c --- a/jdk/src/java.base/share/native/libjli/java.c Mon Dec 19 09:16:40 2016 -0800 +++ b/jdk/src/java.base/share/native/libjli/java.c Mon Dec 19 15:33:32 2016 -0800 @@ -573,6 +573,17 @@ JLI_StrCmp(name, "--patch-module") == 0; } +static jboolean +IsLongFormModuleOption(const char* name) { + return JLI_StrCCmp(name, "--module-path=") == 0 || + JLI_StrCCmp(name, "--upgrade-module-path=") == 0 || + JLI_StrCCmp(name, "--add-modules=") == 0 || + JLI_StrCCmp(name, "--limit-modules=") == 0 || + JLI_StrCCmp(name, "--add-exports=") == 0 || + JLI_StrCCmp(name, "--add-reads=") == 0 || + JLI_StrCCmp(name, "--patch-module=") == 0; +} + /* * Test if the given name has a white space option. */ @@ -1236,7 +1247,7 @@ char *option = NULL; char *value = NULL; int kind = GetOpt(&argc, &argv, &option, &value); - jboolean has_arg = value != NULL; + jboolean has_arg = value != NULL && JLI_StrLen(value) > 0; /* * Option to set main entry point @@ -1285,19 +1296,13 @@ /* * Error missing argument */ - } else if (!has_arg && IsWhiteSpaceOption(arg)) { - if (JLI_StrCmp(arg, "--module-path") == 0 || - JLI_StrCmp(arg, "-p") == 0 || - JLI_StrCmp(arg, "--upgrade-module-path") == 0) { - REPORT_ERROR (has_arg, ARG_ERROR4, arg); - } else if (JLI_StrCmp(arg, "--add-modules") == 0 || - JLI_StrCmp(arg, "--limit-modules") == 0 || - JLI_StrCmp(arg, "--add-exports") == 0 || - JLI_StrCmp(arg, "--add-opens") == 0 || - JLI_StrCmp(arg, "--add-reads") == 0 || - JLI_StrCmp(arg, "--patch-module") == 0) { - REPORT_ERROR (has_arg, ARG_ERROR6, arg); - } + } else if (!has_arg && (JLI_StrCmp(arg, "--module-path") == 0 || + JLI_StrCmp(arg, "-p") == 0 || + JLI_StrCmp(arg, "--upgrade-module-path") == 0)) { + REPORT_ERROR (has_arg, ARG_ERROR4, arg); + + } else if (!has_arg && (IsModuleOption(arg) || IsLongFormModuleOption(arg))) { + REPORT_ERROR (has_arg, ARG_ERROR6, arg); /* * The following cases will cause the argument parsing to stop */ diff -r e5d5f0f2d40d -r 0d1409532a41 jdk/src/java.base/unix/conf/arm/jvm.cfg --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/java.base/unix/conf/arm/jvm.cfg Mon Dec 19 15:33:32 2016 -0800 @@ -0,0 +1,36 @@ +# Copyright (c) 2011, 2016, 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. +# +# +# List of JVMs that can be used as an option to java, javac, etc. +# Order is important -- first in this list is the default JVM. +# NOTE that this both this file and its format are UNSUPPORTED and +# WILL GO AWAY in a future release. +# +# You may also select a JVM in an arbitrary location with the +# "-XXaltjvm=" option, but that too is unsupported +# and may not be available in a future release. +# +-server KNOWN +-client KNOWN +-minimal KNOWN diff -r e5d5f0f2d40d -r 0d1409532a41 jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/SystemModulesPlugin.java --- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/SystemModulesPlugin.java Mon Dec 19 09:16:40 2016 -0800 +++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/SystemModulesPlugin.java Mon Dec 19 15:33:32 2016 -0800 @@ -34,6 +34,7 @@ import java.util.Collection; import java.util.EnumSet; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; @@ -342,7 +343,8 @@ * * static Map map = new HashMap<>(); */ - private void clinit(int numModules, int numPackages) { + private void clinit(int numModules, int numPackages, + boolean hasSplitPackages) { cw.visit(Opcodes.V1_8, ACC_PUBLIC+ACC_FINAL+ACC_SUPER, CLASSNAME, null, "java/lang/Object", null); @@ -379,6 +381,17 @@ clinit.visitInsn(RETURN); clinit.visitMaxs(0, 0); clinit.visitEnd(); + + // public static boolean hasSplitPackages(); + MethodVisitor split = + cw.visitMethod(ACC_PUBLIC+ACC_STATIC, "hasSplitPackages", + "()Z", null, null); + split.visitCode(); + split.visitInsn(hasSplitPackages ? ICONST_1 : ICONST_0); + split.visitInsn(IRETURN); + split.visitMaxs(0, 0); + split.visitEnd(); + } /* @@ -416,12 +429,16 @@ */ public ClassWriter getClassWriter() { int numModules = moduleInfos.size(); - int numPackages = 0; + Set allPackages = new HashSet<>(); + int packageCount = 0; for (ModuleInfo minfo : moduleInfos) { - numPackages += minfo.packages.size(); + allPackages.addAll(minfo.packages); + packageCount += minfo.packages.size(); } - clinit(numModules, numPackages); + int numPackages = allPackages.size(); + boolean hasSplitPackages = (numPackages < packageCount); + clinit(numModules, numPackages, hasSplitPackages); // generate SystemModules::descriptors genDescriptorsMethod(); diff -r e5d5f0f2d40d -r 0d1409532a41 jdk/test/ProblemList.txt --- a/jdk/test/ProblemList.txt Mon Dec 19 09:16:40 2016 -0800 +++ b/jdk/test/ProblemList.txt Mon Dec 19 15:33:32 2016 -0800 @@ -292,8 +292,6 @@ # jdk_util -java/util/spi/ResourceBundleControlProvider/UserDefaultControlTest.java 8062512 generic-all - java/util/BitSet/BitSetStreamTest.java 8079538 generic-all diff -r e5d5f0f2d40d -r 0d1409532a41 jdk/test/java/util/spi/ResourceBundleControlProvider/UserDefaultControlTest.java --- a/jdk/test/java/util/spi/ResourceBundleControlProvider/UserDefaultControlTest.java Mon Dec 19 09:16:40 2016 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,59 +0,0 @@ -/* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -/* - * @test - * @bug 6959653 - * @summary Test ResourceBundle.Control provided using SPI. - * @build UserDefaultControlTest - * @run shell UserDefaultControlTest.sh - */ - -import java.io.*; -import java.net.*; -import java.util.*; - -public class UserDefaultControlTest { - public static void main(String[] args) { - ResourceBundle rb = ResourceBundle.getBundle("com.foo.XmlRB", Locale.ROOT); - String type = rb.getString("type"); - if (!type.equals("XML")) { - throw new RuntimeException("Root Locale: type: got " + type - + ", expected XML (ASCII)"); - } - - rb = ResourceBundle.getBundle("com.foo.XmlRB", Locale.JAPAN); - type = rb.getString("type"); - // Expect fullwidth "XML" - if (!type.equals("\uff38\uff2d\uff2c")) { - throw new RuntimeException("Locale.JAPAN: type: got " + type - + ", expected \uff38\uff2d\uff2c (fullwidth XML)"); - } - - try { - rb = ResourceBundle.getBundle("com.bar.XmlRB", Locale.JAPAN); - throw new RuntimeException("com.bar.XmlRB test failed."); - } catch (MissingResourceException e) { - // OK - } - } -} diff -r e5d5f0f2d40d -r 0d1409532a41 jdk/test/java/util/spi/ResourceBundleControlProvider/UserDefaultControlTest.sh --- a/jdk/test/java/util/spi/ResourceBundleControlProvider/UserDefaultControlTest.sh Mon Dec 19 09:16:40 2016 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,25 +0,0 @@ -# -# Copyright (c) 2012, 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. -# - -${TESTJAVA}/bin/java ${TESTVMOPTS} -Djava.ext.dirs=${TESTSRC} -cp ${TESTCLASSES} UserDefaultControlTest - diff -r e5d5f0f2d40d -r 0d1409532a41 jdk/test/java/util/spi/ResourceBundleControlProvider/providersrc/Makefile --- a/jdk/test/java/util/spi/ResourceBundleControlProvider/providersrc/Makefile Mon Dec 19 09:16:40 2016 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,63 +0,0 @@ -# -# Copyright (c) 2012, 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. -# - -# -# Makefile for building a ResourceBundleControlProvider jar file for testing. -# -# Usage: make JDK_HOME=... all install -# - -DESTDIR = .. -TMPDIR = tmp -SERVICESDIR = $(TMPDIR)/META-INF/services -TARGETJAR = rbcontrolprovider.jar -BINDIR = $(JDK_HOME)/bin - - -all: $(TARGETJAR) - -install: all - cp $(TARGETJAR) $(DESTDIR) - -SERVICES = java.util.spi.ResourceBundleControlProvider - -FILES_JAVA = UserControlProvider.java \ - UserXMLControl.java - -RESOURCE_FILES = XmlRB.xml \ - XmlRB_ja.xml - -$(TARGETJAR): $(SERVICES) $(FILES_JAVA) $(RESOURCE_FILES) - rm -rf $(TMPDIR) $@ - mkdir -p $(SERVICESDIR) - $(BINDIR)/javac -d $(TMPDIR) $(FILES_JAVA) - cp $(SERVICES) $(SERVICESDIR) - cp $(RESOURCE_FILES) $(TMPDIR)/com/foo - $(BINDIR)/jar cvf $@ -C $(TMPDIR) . - -clean: - rm -rf $(TMPDIR) $(TARGETJAR) - -.PHONY: all install clean diff -r e5d5f0f2d40d -r 0d1409532a41 jdk/test/java/util/spi/ResourceBundleControlProvider/providersrc/UserControlProvider.java --- a/jdk/test/java/util/spi/ResourceBundleControlProvider/providersrc/UserControlProvider.java Mon Dec 19 09:16:40 2016 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,43 +0,0 @@ -/* - * Copyright (c) 2012, 2013, 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 com.foo; - -import java.util.ResourceBundle; -import java.util.spi.ResourceBundleControlProvider; - -public class UserControlProvider implements ResourceBundleControlProvider { - static final ResourceBundle.Control XMLCONTROL = new UserXMLControl(); - - public ResourceBundle.Control getControl(String baseName) { - System.out.println(getClass().getName()+".getControl called for " + baseName); - - // Throws a NPE if baseName is null. - if (baseName.startsWith("com.foo.Xml")) { - System.out.println("\treturns " + XMLCONTROL); - return XMLCONTROL; - } - System.out.println("\treturns null"); - return null; - } -} diff -r e5d5f0f2d40d -r 0d1409532a41 jdk/test/java/util/spi/ResourceBundleControlProvider/providersrc/UserXMLControl.java --- a/jdk/test/java/util/spi/ResourceBundleControlProvider/providersrc/UserXMLControl.java Mon Dec 19 09:16:40 2016 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,95 +0,0 @@ -/* - * Copyright (c) 2012, 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 com.foo; - -import java.io.*; -import java.net.*; -import java.util.*; -import static java.util.ResourceBundle.Control.*; - -public class UserXMLControl extends ResourceBundle.Control { - @Override - public List getFormats(String baseName) { - if (baseName == null) { - throw new NullPointerException(); - } - return Arrays.asList("xml"); - } - - @Override - public ResourceBundle newBundle(String baseName, Locale locale, - String format, - ClassLoader loader, - boolean reload) - throws IllegalAccessException, - InstantiationException, IOException { - if (baseName == null || locale == null - || format == null || loader == null) { - throw new NullPointerException(); - } - ResourceBundle bundle = null; - if (format.equals("xml")) { - String bundleName = toBundleName(baseName, locale); - String resourceName = toResourceName(bundleName, format); - URL url = loader.getResource(resourceName); - if (url != null) { - URLConnection connection = url.openConnection(); - if (connection != null) { - if (reload) { - // disable caches if reloading - connection.setUseCaches(false); - } - try (InputStream stream = connection.getInputStream()) { - if (stream != null) { - BufferedInputStream bis = new BufferedInputStream(stream); - bundle = new XMLResourceBundle(bis); - } - } - } - } - } - return bundle; - } - - private static class XMLResourceBundle extends ResourceBundle { - private Properties props; - - XMLResourceBundle(InputStream stream) throws IOException { - props = new Properties(); - props.loadFromXML(stream); - } - - protected Object handleGetObject(String key) { - if (key == null) { - throw new NullPointerException(); - } - return props.get(key); - } - - public Enumeration getKeys() { - // Not implemented - return null; - } - } -} diff -r e5d5f0f2d40d -r 0d1409532a41 jdk/test/java/util/spi/ResourceBundleControlProvider/providersrc/XmlRB.xml --- a/jdk/test/java/util/spi/ResourceBundleControlProvider/providersrc/XmlRB.xml Mon Dec 19 09:16:40 2016 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,40 +0,0 @@ - - - - - - - - - - -]> - - - Test data for UserDefaultControlTest.java - XML - diff -r e5d5f0f2d40d -r 0d1409532a41 jdk/test/java/util/spi/ResourceBundleControlProvider/providersrc/XmlRB_ja.xml --- a/jdk/test/java/util/spi/ResourceBundleControlProvider/providersrc/XmlRB_ja.xml Mon Dec 19 09:16:40 2016 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,40 +0,0 @@ - - - - - - - - - - -]> - - - Test data for UserDefaultControlTest.java - XML - diff -r e5d5f0f2d40d -r 0d1409532a41 jdk/test/java/util/spi/ResourceBundleControlProvider/providersrc/java.util.spi.ResourceBundleControlProvider --- a/jdk/test/java/util/spi/ResourceBundleControlProvider/providersrc/java.util.spi.ResourceBundleControlProvider Mon Dec 19 09:16:40 2016 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1 +0,0 @@ -com.foo.UserControlProvider diff -r e5d5f0f2d40d -r 0d1409532a41 jdk/test/java/util/spi/ResourceBundleControlProvider/rbcontrolprovider.jar Binary file jdk/test/java/util/spi/ResourceBundleControlProvider/rbcontrolprovider.jar has changed diff -r e5d5f0f2d40d -r 0d1409532a41 jdk/test/lib/testlibrary/ModuleSourceBuilder.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/lib/testlibrary/ModuleSourceBuilder.java Mon Dec 19 15:33:32 2016 -0800 @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2016, 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.BufferedWriter; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Arrays; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Stream; + +import static org.testng.Assert.assertTrue; + +/** + * Utility class for creating test modules. + */ +public class ModuleSourceBuilder { + private static String MODULE_INFO_JAVA = "module-info.java"; + private static Pattern MODULE_PATTERN = + Pattern.compile("module\\s+((?:\\w+\\.)*)"); + private static Pattern PACKAGE_PATTERN = + Pattern.compile("package\\s+(((?:\\w+\\.)*)(?:\\w+))"); + private static Pattern CLASS_PATTERN = + Pattern.compile("(?:public\\s+)?(?:class|enum|interface)\\s+(\\w+)"); + + private final Path dir; + public ModuleSourceBuilder(Path dir) { + this.dir = dir; + } + + /** + * Create java source files of the given module + */ + public void writeJavaFiles(String module, String moduleInfoJava, String... contents) + throws IOException + { + Path msrc = dir.resolve(module); + new JavaSource(moduleInfoJava).write(msrc); + for (String c : contents) { + new JavaSource(c).write(msrc); + } + } + + /** + * Compile the module to the given destination. + */ + public void compile(String module, Path dest, String... options) + throws IOException + { + Path msrc = dir.resolve(module); + Stream args = + Stream.concat(Arrays.stream(options), + Stream.of("--module-source-path", + dir.toString())); + assertTrue(CompilerUtils.compile(msrc, dest, args.toArray(String[]::new)), + "Fail to compile " + module); + } + + static class JavaSource { + final String source; + JavaSource(String source) { + this.source = source; + } + + /** + * Writes the source code to a file in a specified directory. + * @param dir the directory + * @throws IOException if there is a problem writing the file + */ + public void write(Path dir) throws IOException { + Path file = dir.resolve(getJavaFileNameFromSource(source)); + Files.createDirectories(file.getParent()); + try (BufferedWriter out = Files.newBufferedWriter(file)) { + out.write(source.replace("\n", System.lineSeparator())); + } + } + + /** + * Extracts the Java file name from the class declaration. + * This method is intended for simple files and uses regular expressions, + * so comments matching the pattern can make the method fail. + */ + static String getJavaFileNameFromSource(String source) { + String packageName = null; + + Matcher matcher = MODULE_PATTERN.matcher(source); + if (matcher.find()) + return MODULE_INFO_JAVA; + + matcher = PACKAGE_PATTERN.matcher(source); + if (matcher.find()) + packageName = matcher.group(1).replace(".", "/"); + + matcher = CLASS_PATTERN.matcher(source); + if (matcher.find()) { + String className = matcher.group(1) + ".java"; + return (packageName == null) ? className : packageName + "/" + className; + } else if (packageName != null) { + return packageName + "/package-info.java"; + } else { + throw new Error("Could not extract the java class " + + "name from the provided source"); + } + } + } +} diff -r e5d5f0f2d40d -r 0d1409532a41 jdk/test/sun/management/jmxremote/bootstrap/CustomLauncherTest.java --- a/jdk/test/sun/management/jmxremote/bootstrap/CustomLauncherTest.java Mon Dec 19 09:16:40 2016 -0800 +++ b/jdk/test/sun/management/jmxremote/bootstrap/CustomLauncherTest.java Mon Dec 19 15:33:32 2016 -0800 @@ -56,8 +56,6 @@ private static final String TEST_SRC = System.getProperty("test.src"); private static final String OSNAME = System.getProperty("os.name"); private static final String ARCH; - private static final String LIBARCH; - static { // magic with os.arch String osarch = System.getProperty("os.arch"); @@ -84,7 +82,6 @@ ARCH = osarch; } } - LIBARCH = ARCH.equals("i586") ? "i386" : ARCH; } public static void main(String[] args) throws Exception { @@ -184,15 +181,12 @@ } private static Path findLibjvm(FileSystem FS) { - Path libjvmPath = findLibjvm(FS.getPath(TEST_JDK, "jre", "lib", LIBARCH)); - if (libjvmPath == null) { - libjvmPath = findLibjvm(FS.getPath(TEST_JDK, "lib", LIBARCH)); - } + Path libjvmPath = findLibjvm(FS.getPath(TEST_JDK, "lib")); return libjvmPath; } private static Path findLibjvm(Path libPath) { - // ARCH/libjvm.so -> ARCH/server/libjvm.so -> ARCH/client/libjvm.so + // libjvm.so -> server/libjvm.so -> client/libjvm.so Path libjvmPath = libPath.resolve("libjvm.so"); if (isFileOk(libjvmPath)) { return libjvmPath; diff -r e5d5f0f2d40d -r 0d1409532a41 jdk/test/sun/security/tools/jarsigner/multiRelease/MVJarSigningTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/sun/security/tools/jarsigner/multiRelease/MVJarSigningTest.java Mon Dec 19 15:33:32 2016 -0800 @@ -0,0 +1,228 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8047305 8075618 + * @summary Tests jarsigner tool and JarSigner API work with multi-release JAR files. + * @library /test/lib + * @library /lib/testlibrary + * @run main MVJarSigningTest + */ + +import jdk.security.jarsigner.JarSigner; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStreamReader; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.security.KeyStore; +import java.security.PrivateKey; +import java.security.cert.Certificate; +import java.security.cert.CertificateFactory; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.TimeUnit; +import java.util.jar.JarFile; +import java.util.stream.Stream; +import java.util.zip.ZipEntry; +import java.util.zip.ZipFile; +import java.util.zip.ZipOutputStream; + +import jdk.test.lib.JDKToolFinder; +import jdk.test.lib.JDKToolLauncher; +import jdk.test.lib.Utils; +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.process.ProcessTools; + + +public class MVJarSigningTest { + + private static final String TEST_SRC = System.getProperty("test.src", "."); + private static final String USR_DIR = System.getProperty("user.dir", "."); + private static final String JAR_NAME = "MV.jar"; + private static final String KEYSTORE = "keystore.jks"; + private static final String ALIAS = "JavaTest"; + private static final String STOREPASS = "changeit"; + private static final String KEYPASS = "changeit"; + private static final String SIGNED_JAR = "Signed.jar"; + private static final String POLICY_FILE = "SignedJar.policy"; + private static final String VERSION_MESSAGE = "I am running on version 9"; + + public static void main(String[] args) throws Throwable { + // compile java files in jarContent directory + compile("jarContent"); + + // create multi-release jar + Path classes = Paths.get("classes"); + jar("cf", JAR_NAME, "-C", classes.resolve("base").toString(), ".", + "--release", "9", "-C", classes.resolve("v9").toString(), ".", + "--release", "10", "-C", classes.resolve("v10").toString(), ".") + .shouldHaveExitValue(0); + + genKey(); + signJar(JAR_NAME) + .shouldHaveExitValue(0) + .shouldMatch("signing.*META-INF/versions/9/version/Version.class") + .shouldMatch("signing.*META-INF/versions/10/version/Version.class") + .shouldMatch("signing.*version/Main.class") + .shouldMatch("signing.*version/Version.class"); + verify(SIGNED_JAR); + + // test with JarSigner API + Files.deleteIfExists(Paths.get(SIGNED_JAR)); + signWithJarSignerAPI(JAR_NAME); + verify(SIGNED_JAR); + + // test Permission granted + File keypass = new File("keypass"); + try (FileOutputStream fos = new FileOutputStream(keypass)) { + fos.write(KEYPASS.getBytes()); + } + String[] cmd = { + "-classpath", SIGNED_JAR, + "-Djava.security.manager", + "-Djava.security.policy=" + + TEST_SRC + File.separator + POLICY_FILE, + "version.Main"}; + ProcessTools.executeTestJvm(cmd) + .shouldHaveExitValue(0) + .shouldContain(VERSION_MESSAGE); + } + + private static void compile (String jarContent_path) throws Throwable { + Path classes = Paths.get(USR_DIR, "classes", "base"); + Path source = Paths.get(TEST_SRC, jarContent_path, "base", "version"); + CompilerUtils.compile(source, classes); + + classes = Paths.get(USR_DIR, "classes", "v9"); + source = Paths.get(TEST_SRC, jarContent_path , "v9", "version"); + CompilerUtils.compile(source, classes); + + classes = Paths.get(USR_DIR, "classes", "v10"); + source = Paths.get(TEST_SRC, jarContent_path, "v10", "version"); + CompilerUtils.compile(source, classes); + } + + private static OutputAnalyzer jar(String...args) throws Throwable { + JDKToolLauncher launcher = JDKToolLauncher.createUsingTestJDK("jar"); + Stream.of(args).forEach(launcher::addToolArg); + return ProcessTools.executeCommand(launcher.getCommand()); + } + + private static void genKey() throws Throwable { + String keytool = JDKToolFinder.getJDKTool("keytool"); + Files.deleteIfExists(Paths.get(KEYSTORE)); + ProcessTools.executeCommand(keytool, + "-J-Duser.language=en", + "-J-Duser.country=US", + "-genkey", + "-alias", ALIAS, + "-keystore", KEYSTORE, + "-keypass", KEYPASS, + "-dname", "cn=sample", + "-storepass", STOREPASS + ).shouldHaveExitValue(0); + } + + private static OutputAnalyzer signJar(String jarName) throws Throwable { + List args = new ArrayList<>(); + args.add("-verbose"); + args.add("-signedjar"); + args.add(SIGNED_JAR); + args.add(jarName); + args.add(ALIAS); + + return jarsigner(args); + } + + private static void verify(String signedJarName) throws Throwable { + verifyJar(signedJarName) + .shouldHaveExitValue(0) + .shouldContain("jar verified") + .shouldMatch("smk.*META-INF/versions/9/version/Version.class") + .shouldMatch("smk.*META-INF/versions/10/version/Version.class") + .shouldMatch("smk.*version/Main.class") + .shouldMatch("smk.*version/Version.class"); + } + + private static OutputAnalyzer verifyJar(String signedJarName) throws Throwable { + List args = new ArrayList<>(); + args.add("-verbose"); + args.add("-verify"); + args.add(signedJarName); + + return jarsigner(args); + } + + private static OutputAnalyzer jarsigner(List extra) + throws Throwable { + JDKToolLauncher launcher = JDKToolLauncher.createUsingTestJDK("jarsigner") + .addVMArg("-Duser.language=en") + .addVMArg("-Duser.country=US") + .addToolArg("-keystore") + .addToolArg(KEYSTORE) + .addToolArg("-storepass") + .addToolArg(STOREPASS) + .addToolArg("-keypass") + .addToolArg(KEYPASS); + for (String s : extra) { + if (s.startsWith("-J")) { + launcher.addVMArg(s.substring(2)); + } else { + launcher.addToolArg(s); + } + } + return ProcessTools.executeCommand(launcher.getCommand()); + } + + private static void signWithJarSignerAPI(String jarName) + throws Throwable { + // Get JarSigner + try (FileInputStream fis = new FileInputStream(KEYSTORE)) { + KeyStore ks = KeyStore.getInstance("JKS"); + ks.load(fis, STOREPASS.toCharArray()); + PrivateKey pk = (PrivateKey)ks.getKey(ALIAS, KEYPASS.toCharArray()); + Certificate cert = ks.getCertificate(ALIAS); + JarSigner signer = new JarSigner.Builder(pk, + CertificateFactory.getInstance("X.509").generateCertPath( + Collections.singletonList(cert))) + .build(); + // Sign jar + try (ZipFile src = new JarFile(jarName); + FileOutputStream out = new FileOutputStream(SIGNED_JAR)) { + signer.sign(src,out); + } + } + } + +} + + diff -r e5d5f0f2d40d -r 0d1409532a41 jdk/test/sun/security/tools/jarsigner/multiRelease/SignedJar.policy --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/sun/security/tools/jarsigner/multiRelease/SignedJar.policy Mon Dec 19 15:33:32 2016 -0800 @@ -0,0 +1,10 @@ +keystore "file:keystore.jks"; +keystorePasswordURL "file:keypass"; + +grant signedBy "JavaTest" { + permission java.lang.RuntimePermission "setIO"; +}; + +grant signedBy "other" { + permission java.lang.RuntimePermission "setFactory"; +}; diff -r e5d5f0f2d40d -r 0d1409532a41 jdk/test/sun/security/tools/jarsigner/multiRelease/jarContent/base/version/Main.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/sun/security/tools/jarsigner/multiRelease/jarContent/base/version/Main.java Mon Dec 19 15:33:32 2016 -0800 @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2016, 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 version; + +import java.security.Permission; + +public class Main { + + public static void main(String[] args) { + Version v = new Version(); + System.out.println("I am running on version " + v.getVersion()); + } +} diff -r e5d5f0f2d40d -r 0d1409532a41 jdk/test/sun/security/tools/jarsigner/multiRelease/jarContent/base/version/Version.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/sun/security/tools/jarsigner/multiRelease/jarContent/base/version/Version.java Mon Dec 19 15:33:32 2016 -0800 @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2016, 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 version; + +public class Version { + + public int getVersion() { + return 8; + } +} diff -r e5d5f0f2d40d -r 0d1409532a41 jdk/test/sun/security/tools/jarsigner/multiRelease/jarContent/v10/version/Version.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/sun/security/tools/jarsigner/multiRelease/jarContent/v10/version/Version.java Mon Dec 19 15:33:32 2016 -0800 @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2016, 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 version; + +public class Version { + + public int getVersion() { + return 10; + } +} + diff -r e5d5f0f2d40d -r 0d1409532a41 jdk/test/sun/security/tools/jarsigner/multiRelease/jarContent/v9/version/Version.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/sun/security/tools/jarsigner/multiRelease/jarContent/v9/version/Version.java Mon Dec 19 15:33:32 2016 -0800 @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2016, 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 version; + +import java.security.AccessControlException; +import java.security.AccessController; +import java.security.Permission; +import java.security.PrivilegedAction; + +public class Version { + private static final Permission PERM1 = new RuntimePermission("setIO"); + private static final Permission PERM2 = new RuntimePermission("setFactory"); + + public int getVersion() { + checkPermission(PERM1, false); + checkPermission(PERM2, true); + return 9; + } + + private void checkPermission(Permission perm, boolean expectException) { + boolean getException = (Boolean) AccessController + .doPrivileged((PrivilegedAction) () -> { + try { + AccessController.checkPermission(perm); + return (Boolean) false; + } catch (AccessControlException ex) { + return (Boolean) true; + } + }); + + if (expectException ^ getException) { + String message = "Check Permission :" + perm + "\n ExpectException = " + + expectException + "\n getException = " + getException; + throw new RuntimeException(message); + } + } +} diff -r e5d5f0f2d40d -r 0d1409532a41 jdk/test/tools/launcher/modules/addexports/AddExportsTestWarningError.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/tools/launcher/modules/addexports/AddExportsTestWarningError.java Mon Dec 19 15:33:32 2016 -0800 @@ -0,0 +1,234 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @bug 8168836 + * @summary Basic argument validation for --add-exports + * @library /lib/testlibrary + * @modules jdk.compiler + * @build AddExportsTestWarningError CompilerUtils ModuleSourceBuilder + * @build jdk.testlibrary.* + * @run testng AddExportsTestWarningError + */ + +import java.io.BufferedOutputStream; +import java.io.ByteArrayOutputStream; +import java.io.PrintStream; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Arrays; +import java.util.stream.Stream; + +import jdk.testlibrary.OutputAnalyzer; +import static jdk.testlibrary.ProcessTools.*; + +import org.testng.annotations.BeforeTest; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; +import static org.testng.Assert.*; + + +@Test +public class AddExportsTestWarningError { + + private static final Path MODS_DIR = Paths.get("mods"); + private static final Path SRC_DIR = Paths.get("src"); + private static final String M1_MAIN = "m1/p1.C1"; + private static final String M3_MAIN = "m3/p3.C3"; + + @BeforeTest + public void setup() throws Exception { + ModuleSourceBuilder builder = new ModuleSourceBuilder(SRC_DIR); + builder.writeJavaFiles("m1", + "module m1 { }", + "package p1; public class C1 { " + + " public static void main(String... args) {}" + + "}"); + + builder.writeJavaFiles("m2", + "module m2 { requires m1; exports p2; }", + "package p2; public class C2 { private p1.C1 c1; }"); + + builder.writeJavaFiles("m3", + "module m3 { requires m2; }", + "package p3; class C3 { " + + " p1.C1 c; " + + " public static void main(String... args) { new p2.C2(); }" + + "}"); + + builder.compile("m1", MODS_DIR); + builder.compile("m2", MODS_DIR, "--add-exports", "m1/p1=m2"); + builder.compile("m3", MODS_DIR, "--add-exports", "m1/p1=m3"); + } + + + @DataProvider(name = "goodcases") + public Object[][] goodCases() { + return new Object[][]{ + + // empty items + { "m1/p1=,m2,m3", null }, + { "m1/p1=m2,,m3", null }, + { "m1/p1=m2,m3,", null }, + + // duplicates + { "m1/p1=m2,m2,m3,,", null }, + + }; + } + + + @Test(dataProvider = "goodcases") + public void test(String value, String ignore) throws Exception { + testNoWarning(value); + } + + + @DataProvider(name = "illFormedAddExports") + public Object[][] illFormedAddExports() { + return new Object[][]{ + { "m1", "Unable to parse --add-exports =: m1"}, + + // missing source part + { "=m2", "Unable to parse --add-exports =: =m2"}, + { "/=m2", "Unable to parse --add-exports /: /" }, + { "m1=m2", "Unable to parse --add-exports /: m1" }, + { "/p1=m2", "Unable to parse --add-exports /: /p1" }, + { "m1p1=m2", "Unable to parse --add-exports /: m1p1" }, + + // empty list, missing target + { "m1/p1=", "Unable to parse --add-exports =: m1/p1=" }, + { "m1/p1=,,", "Target must be specified: --add-exports m1/p1=,," }, + }; + } + + @Test(dataProvider = "illFormedAddExports") + public void testIllFormedAddExports(String value, String msg) throws Exception { + testError(value, msg); + } + + + @DataProvider(name = "unknownNames") + public Object[][] unknownNames() { + return new Object[][]{ + + // source not found + {"DoesNotExist/p=m1", "WARNING: Unknown module: DoesNotExist specified in --add-exports"}, + {"m1/DoesNotExist=m2", "WARNING: package DoesNotExist not in m1"}, + + // target not found + {"m1/p1=DoesNotExist", "WARNING: Unknown module: DoesNotExist specified in --add-exports"}, + + // bad names + {"m*/p1=m2", "WARNING: Unknown module: m* specified in --add-exports"}, + {"m1/p!=m2", "WARNING: package p! not in m1"}, + {"m1/p1=m!", "WARNING: Unknown module: m! specified in --add-exports"}, + + }; + } + + + @Test(dataProvider = "unknownNames") + public void testUnknownNames(String value, String msg) throws Exception { + testWarning(value, msg); + } + + + @DataProvider(name = "missingArguments") + public Object[][] missingArguments() { + return new Object[][]{ + { new String[] { "--add-exports" }, + "Error: --add-exports requires modules to be specified"}, + + { new String[] { "--add-exports=" }, + "Error: --add-exports= requires modules to be specified" }, + + { new String[] { "--add-exports", "" }, + "Error: --add-exports requires modules to be specified"} + + }; + } + + + @Test(dataProvider = "missingArguments") + public void testMissingArguments(String[] options, String msg) throws Exception { + String[] args = Stream.concat(Arrays.stream(options), + Stream.of("-version")) + .toArray(String[]::new); + int exitValue = executeTestJava(args) + .outputTo(System.out) + .errorTo(System.out) + .shouldContain(msg) + .getExitValue(); + + assertTrue(exitValue != 0); + } + + private void testWarning(String value, String msg) throws Exception { + int exitValue = + executeTestJava("--add-exports", value, + "--module-path", MODS_DIR.toString(), + "-m", M1_MAIN) + .outputTo(System.out) + .errorTo(System.out) + .shouldContain(msg) + .getExitValue(); + + assertTrue(exitValue == 0); + } + + private void testError(String value, String msg) throws Exception { + int exitValue = + executeTestJava("--add-exports", value, + "--module-path", MODS_DIR.toString(), + "-m", M1_MAIN) + .outputTo(System.out) + .errorTo(System.out) + .shouldContain(msg) + .getExitValue(); + + assertTrue(exitValue != 0); + } + + private void testNoWarning(String value) throws Exception { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + PrintStream ps = new PrintStream(new BufferedOutputStream(baos)); + OutputAnalyzer outputAnalyzer = + executeTestJava("--add-exports", value, + "--module-path", MODS_DIR.toString(), + "-m", M3_MAIN) + .outputTo(ps) + .errorTo(ps); + + assertTrue(outputAnalyzer.getExitValue() == 0); + + System.out.println(baos.toString()); + String[] output = baos.toString().split("\\R"); + assertFalse(Arrays.stream(output) + .filter(s -> !s.matches("WARNING: Module name .* may soon be illegal")) + .filter(s -> s.startsWith("WARNING:")) + .findAny().isPresent()); + + } +} diff -r e5d5f0f2d40d -r 0d1409532a41 jdk/test/tools/launcher/modules/addreads/AddReadsTestWarningError.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/tools/launcher/modules/addreads/AddReadsTestWarningError.java Mon Dec 19 15:33:32 2016 -0800 @@ -0,0 +1,224 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @bug 8168836 + * @summary Basic argument validation for --add-reads + * @library /lib/testlibrary + * @modules jdk.compiler + * @build AddReadsTestWarningError CompilerUtils ModuleSourceBuilder + * @build jdk.testlibrary.* + * @run testng AddReadsTestWarningError + */ + +import java.io.BufferedOutputStream; +import java.io.ByteArrayOutputStream; +import java.io.PrintStream; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Arrays; +import java.util.stream.Stream; + +import jdk.testlibrary.OutputAnalyzer; +import static jdk.testlibrary.ProcessTools.*; + +import org.testng.annotations.BeforeTest; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; +import static org.testng.Assert.*; + + +@Test +public class AddReadsTestWarningError { + + private static final Path MODS_DIR = Paths.get("mods"); + private static final Path SRC_DIR = Paths.get("src"); + private static final String M1_MAIN = "m1/p1.C1"; + private static final String M4_MAIN = "m4/p4.C4"; + + @BeforeTest + public void setup() throws Exception { + ModuleSourceBuilder builder = new ModuleSourceBuilder(SRC_DIR); + builder.writeJavaFiles("m1", + "module m1 { requires m4; }", + "package p1; public class C1 { " + + " public static void main(String... args) {" + + " p2.C2 c2 = new p2.C2();" + + " p3.C3 c3 = new p3.C3();" + + " }" + + "}" + ); + + builder.writeJavaFiles("m2", + "module m2 { exports p2; }", + "package p2; public class C2 { }" + ); + + builder.writeJavaFiles("m3", + "module m3 { exports p3; }", + "package p3; public class C3 { }" + ); + + builder.writeJavaFiles("m4", + "module m4 { requires m2; requires m3; }", + "package p4; public class C4 { " + + " public static void main(String... args) {}" + + "}" + ); + + builder.compile("m2", MODS_DIR); + builder.compile("m3", MODS_DIR); + builder.compile("m4", MODS_DIR); + builder.compile("m1", MODS_DIR, "--add-reads", "m1=m2,m3"); + } + + + @DataProvider(name = "goodcases") + public Object[][] goodCases() { + return new Object[][]{ + // empty items + { "m1=,m2,m3", null }, + { "m1=m2,,m3", null }, + { "m1=m2,m3,", null }, + + // duplicates + { "m1=m2,m2,m3,,", null }, + + }; + } + + + @Test(dataProvider = "goodcases") + public void test(String value, String ignore) throws Exception { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + PrintStream ps = new PrintStream(new BufferedOutputStream(baos)); + OutputAnalyzer outputAnalyzer = + executeTestJava("--add-reads", value, + "--module-path", MODS_DIR.toString(), + "-m", M1_MAIN) + .outputTo(ps) + .errorTo(ps); + + assertTrue(outputAnalyzer.getExitValue() == 0); + + System.out.println(baos.toString()); + String[] output = baos.toString().split("\\R"); + assertFalse(Arrays.stream(output) + .filter(s -> !s.matches("WARNING: Module name .* may soon be illegal")) + .filter(s -> s.startsWith("WARNING:")) + .findAny().isPresent()); + } + + + @DataProvider(name = "illFormedAddReads") + public Object[][] illFormedAddReads() { + return new Object[][]{ + { "m1", "Unable to parse --add-reads =: m1" }, + + // missing source part + { "=m2", "Unable to parse --add-reads =: =m2" }, + + // empty list, missing target + { "m1=", "Unable to parse --add-reads =: m1=" }, + + // empty list + { "m1=,,", "Target must be specified: --add-reads m1=,," }, + }; + } + + + @Test(dataProvider = "illFormedAddReads") + public void testIllFormedAddReads(String value, String msg) throws Exception { + int exitValue = + executeTestJava("--add-reads", value, + "--module-path", MODS_DIR.toString(), + "-m", M4_MAIN) + .outputTo(System.out) + .errorTo(System.out) + .shouldContain(msg) + .getExitValue(); + + assertTrue(exitValue != 0); + } + + + @DataProvider(name = "unknownNames") + public Object[][] unknownNames() { + return new Object[][]{ + + // source not found + {"DoesNotExist=m2", "WARNING: Unknown module: DoesNotExist specified in --add-reads"}, + + // target not found + {"m2=DoesNotExist", "WARNING: Unknown module: DoesNotExist specified in --add-reads"}, + + // bad names + {"m*=m2", "WARNING: Unknown module: m* specified in --add-reads"}, + {"m2=m!", "WARNING: Unknown module: m! specified in --add-reads"}, + + }; + } + + @Test(dataProvider = "unknownNames") + public void testUnknownNames(String value, String msg) throws Exception { + int exitValue = + executeTestJava("--add-reads", value, + "--module-path", MODS_DIR.toString(), + "-m", M4_MAIN) + .outputTo(System.out) + .errorTo(System.out) + .shouldContain(msg) + .getExitValue(); + + assertTrue(exitValue == 0); + } + + + @DataProvider(name = "missingArguments") + public Object[][] missingArguments() { + return new Object[][]{ + { new String[] {"--add-reads" }, + "Error: --add-reads requires modules to be specified"}, + + { new String[] { "--add-reads=" }, + "Error: --add-reads= requires modules to be specified"}, + + { new String[] { "--add-reads", "" }, + "Error: --add-reads requires modules to be specified"}, + }; + } + + @Test(dataProvider = "missingArguments") + public void testEmptyArgument(String[] options, String msg) throws Exception { + String[] args = Stream.concat(Arrays.stream(options), Stream.of("-version")) + .toArray(String[]::new); + int exitValue = executeTestJava(args) + .outputTo(System.out) + .errorTo(System.out) + .shouldContain(msg) + .getExitValue(); + + assertTrue(exitValue != 0); + } +} diff -r e5d5f0f2d40d -r 0d1409532a41 jdk/test/tools/launcher/modules/patch/basic/PatchTestWarningError.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/tools/launcher/modules/patch/basic/PatchTestWarningError.java Mon Dec 19 15:33:32 2016 -0800 @@ -0,0 +1,220 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @bug 8168836 + * @summary Basic argument validation for --patch-module + * @library /lib/testlibrary + * @modules jdk.compiler + * @build PatchTestWarningError CompilerUtils JarUtils jdk.testlibrary.* + * @run testng PatchTestWarningError + */ + +import java.io.File; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import static jdk.testlibrary.ProcessTools.*; + +import org.testng.annotations.BeforeTest; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; +import static org.testng.Assert.*; + + +/** + * This test + * See PatchTestWarningError for test description. + */ + +@Test +public class PatchTestWarningError { + + // top-level source directory + private static final String TEST_SRC = System.getProperty("test.src"); + + // source/destination tree for the test module + private static final Path SRC_DIR = Paths.get(TEST_SRC, "src"); + private static final Path MODS_DIR = Paths.get("mods"); + + // source/destination tree for patch tree 1 + private static final Path SRC1_DIR = Paths.get(TEST_SRC, "src1"); + private static final Path PATCHES1_DIR = Paths.get("patches1"); + + // source/destination tree for patch tree 2 + private static final Path SRC2_DIR = Paths.get(TEST_SRC, "src2"); + private static final Path PATCHES2_DIR = Paths.get("patches2"); + + // patch path for java.base + private static final String PATCHES_PATH = + PATCHES1_DIR.resolve("java.base") + File.pathSeparator + + PATCHES2_DIR.resolve("java.base"); + + // the classes overridden or added with --patch-module + private static final String[] CLASSES = { + + // java.base = boot loader + "java.base/java.text.Annotation", // override class + "java.base/java.text.AnnotationBuddy", // add class to package + "java.base/java.lang2.Object", // new package + + }; + + + @BeforeTest + public void setup() throws Exception { + + // javac -d mods/test src/test/** + boolean compiled= CompilerUtils.compile(SRC_DIR.resolve("test"), + MODS_DIR.resolve("test")); + assertTrue(compiled, "classes did not compile"); + + // javac -Xmodule:$MODULE -d patches1/$MODULE patches1/$MODULE/** + Path src = SRC1_DIR.resolve("java.base"); + Path output = PATCHES1_DIR.resolve(src.getFileName()); + Files.createDirectories(output); + String mn = src.getFileName().toString(); + compiled = CompilerUtils.compile(src, output, "-Xmodule:" + mn); + assertTrue(compiled, "classes did not compile"); + + // javac -Xmodule:$MODULE -d patches2/$MODULE patches2/$MODULE/** + src = SRC2_DIR.resolve("java.base"); + output = PATCHES2_DIR.resolve(src.getFileName()); + Files.createDirectories(output); + mn = src.getFileName().toString(); + compiled = CompilerUtils.compile(src, output, "-Xmodule:" + mn); + assertTrue(compiled, "classes did not compile"); + + } + + /** + * Test with --patch-module options patching the same module + */ + public void testDuplicateModule() throws Exception { + int exitValue = + executeTestJava("--patch-module", "java.base=" + PATCHES1_DIR.resolve("java.base"), + "--patch-module", "java.base=" + PATCHES2_DIR.resolve("java.base"), + "--module-path", MODS_DIR.toString(), + "-m", "test/jdk.test.Main") + .outputTo(System.out) + .errorTo(System.out) + // error output by VM + .shouldContain("Cannot specify java.base more than once to --patch-module") + .getExitValue(); + + assertTrue(exitValue != 0); + } + + @DataProvider(name = "emptyItem") + public Object[][] emptyItems() { + String patch1 = PATCHES1_DIR.resolve("java.base").toString(); + String patch2 = PATCHES2_DIR.resolve("java.base").toString(); + String pathSep = File.pathSeparator; + return new Object[][]{ + + { "java.base="+ pathSep + patch1 + pathSep + patch2, null }, + { "java.base="+ patch1 + pathSep + pathSep + patch2, null }, + { "java.base="+ patch1 + pathSep + patch2 + pathSep + pathSep, null }, + }; + } + + /** + * Empty item in a non-empty path list + */ + @Test(dataProvider = "emptyItem") + public void testEmptyItem(String value, String msg) throws Exception { + // the argument to the test is the list of classes overridden or added + String arg = Stream.of(CLASSES).collect(Collectors.joining(",")); + + int exitValue = + executeTestJava("--patch-module", value, + "--add-exports", "java.base/java.lang2=test", + "--module-path", MODS_DIR.toString(), + "-m", "test/jdk.test.Main", arg) + .outputTo(System.out) + .errorTo(System.out) + .getExitValue(); + + assertTrue(exitValue == 0); + } + + /** + * Test bad module name that should emit a warning + */ + public void testBadName() throws Exception { + // the argument to the test is the list of classes overridden or added + String arg = Stream.of(CLASSES).collect(Collectors.joining(",")); + + int exitValue = + executeTestJava("--patch-module", "DoesNotExist=tmp", + "--patch-module", "java.base=" + PATCHES_PATH, + "--add-exports", "java.base/java.lang2=test", + "--module-path", MODS_DIR.toString(), + "-m", "test/jdk.test.Main", arg) + .outputTo(System.out) + .errorTo(System.out) + .shouldContain("WARNING: Unknown module: DoesNotExist specified in --patch-module") + .getExitValue(); + + assertTrue(exitValue == 0); + } + + @DataProvider(name = "badArguments") + public Object[][] badArguments() { + return new Object[][]{ + + // source not found + { "=tmp", "Unable to parse --patch-module =: =tmp" }, + + // target not found: check by VM + { "java.base", "Missing '=' in --patch-module specification" }, + { "foo", "Missing '=' in --patch-module specification" }, + + // target not found + { "java.base=", "Unable to parse --patch-module =: java.base=" }, + { "java.base=" + File.pathSeparator, + "Target must be specified: --patch-module java.base=" + File.pathSeparator } + }; + } + + /** + * Test ill-formed argument to --patch-module + */ + @Test(dataProvider = "badArguments") + public void testBadArgument(String value, String msg) throws Exception { + int exitValue = + executeTestJava("--patch-module", value, + "--module-path", MODS_DIR.toString(), + "-m", "test/jdk.test.Main") + .outputTo(System.out) + .errorTo(System.out) + .shouldContain(msg) + .getExitValue(); + + assertTrue(exitValue != 0); + } +} diff -r e5d5f0f2d40d -r 0d1409532a41 jdk/test/tools/launcher/modules/patch/systemmodules/src1/java.base/jdk/internal/modules/SystemModules.java --- a/jdk/test/tools/launcher/modules/patch/systemmodules/src1/java.base/jdk/internal/modules/SystemModules.java Mon Dec 19 09:16:40 2016 -0800 +++ b/jdk/test/tools/launcher/modules/patch/systemmodules/src1/java.base/jdk/internal/modules/SystemModules.java Mon Dec 19 15:33:32 2016 -0800 @@ -29,4 +29,8 @@ */ public final class SystemModules { public static final String[] MODULE_NAMES = new String[0]; + + public static boolean hasSplitPackages() { + return true; + } }