This commit is contained in:
Phil Race
2016-12-19 15:33:32 -08:00
29 changed files with 1335 additions and 440 deletions

View File

@@ -602,12 +602,8 @@ public final class Layer {
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);
}
@@ -656,27 +652,6 @@ public final class Layer {
sm.checkPermission(SecurityConstants.GET_CLASSLOADER_PERMISSION);
}
/**
* 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<String, String> 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.

View File

@@ -60,7 +60,6 @@ import java.security.PrivilegedExceptionAction;
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 @@ import static sun.security.util.SecurityConstants.GET_CLASSLOADER_PERMISSION;
* <li>{@code ResourceBundle.Control} is <em>not</em> 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.
* </li>
* </ul>
*
@@ -264,17 +261,6 @@ import static sun.security.util.SecurityConstants.GET_CLASSLOADER_PERMISSION;
* {@link #getBundle(String, Locale, ClassLoader, Control) getBundle}
* factory method for details.
*
* <p><a name="modify_default_behavior">For the {@code getBundle} factory</a>
* methods that take no {@link Control} instance, their <a
* href="#default_behavior"> default behavior</a> of resource bundle loading
* can be modified with <em>installed</em> {@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.
*
* <h3>Cache Management</h3>
*
* Resource bundle instances created by the <code>getBundle</code> factory
@@ -469,21 +455,6 @@ public abstract class ResourceBundle {
*/
private volatile Set<String> keySet;
private static final List<ResourceBundleControlProvider> providers;
static {
List<ResourceBundleControlProvider> list = null;
ServiceLoader<ResourceBundleControlProvider> 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 @@ public abstract class ResourceBundle {
{
Class<?> caller = Reflection.getCallerClass();
return getBundleImpl(baseName, Locale.getDefault(),
caller, getDefaultControl(caller, baseName));
caller, Control.INSTANCE);
}
/**
@@ -1022,7 +993,7 @@ public abstract class ResourceBundle {
{
Class<?> caller = Reflection.getCallerClass();
return getBundleImpl(baseName, locale,
caller, getDefaultControl(caller, baseName));
caller, Control.INSTANCE);
}
/**
@@ -1163,10 +1134,7 @@ public abstract class ResourceBundle {
*
* <p>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 <a href="#modify_default_behavior">modifying the default
* behavior</a>.
* default instance of {@link Control}.
*
* <p><a name="default_behavior">The following describes the default
* behavior</a>.
@@ -1364,7 +1332,7 @@ public abstract class ResourceBundle {
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 @@ public abstract class ResourceBundle {
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 @@ public abstract class ResourceBundle {
* @apiNote <a name="note">{@code ResourceBundle.Control} is not supported
* in named modules.</a> 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

View File

@@ -35,21 +35,19 @@ import java.util.ResourceBundle;
* no {@link java.util.ResourceBundle.Control} instance can be modified with {@code
* ResourceBundleControlProvider} implementations.
*
* <p>Provider implementations must be packaged using the <a
* href="../../../../technotes/guides/extensions/index.html">Java Extension
* Mechanism</a> 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.
*
* <p>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

View File

@@ -306,8 +306,32 @@ public final class ModuleBootstrap {
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<String, String> 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 @@ public final class ModuleBootstrap {
String mn = e.getKey();
Optional<Module> om = bootLayer.findModule(mn);
if (!om.isPresent()) {
warn("Unknown module: " + mn);
warnUnknownModule(ADD_READS, mn);
continue;
}
Module m = om.get();
@@ -478,7 +502,7 @@ public final class ModuleBootstrap {
if (om.isPresent()) {
Modules.addReads(m, om.get());
} else {
warn("Unknown module: " + name);
warnUnknownModule(ADD_READS, name);
}
}
}
@@ -510,24 +534,25 @@ public final class ModuleBootstrap {
Map<String, List<String>> map,
boolean opens)
{
String option = opens ? ADD_OPENS : ADD_EXPORTS;
for (Map.Entry<String, List<String>> 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 <module>/<package>: " + key);
fail(unableToParse(option, "<module>/<package>", 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, "<module>/<package>", key));
// The exporting module is in the boot layer
Module m;
Optional<Module> om = bootLayer.findModule(mn);
if (!om.isPresent()) {
warn("Unknown module: " + mn);
warnUnknownModule(option, mn);
continue;
}
@@ -549,7 +574,7 @@ public final class ModuleBootstrap {
if (om.isPresent()) {
other = om.get();
} else {
warn("Unknown module: " + name);
warnUnknownModule(option, name);
continue;
}
}
@@ -593,24 +618,30 @@ public final class ModuleBootstrap {
int pos = value.indexOf('=');
if (pos == -1)
fail("Unable to parse as <module>=<value>: " + value);
fail(unableToParse(option(prefix), "<module>=<value>", value));
if (pos == 0)
fail("Missing module name in: " + value);
fail(unableToParse(option(prefix), "<module>=<value>", value));
// key is <module> or <module>/<package>
String key = value.substring(0, pos);
String rhs = value.substring(pos+1);
if (rhs.isEmpty())
fail("Unable to parse as <module>=<value>: " + value);
fail(unableToParse(option(prefix), "<module>=<value>", value));
// value is <module>(,<module>)* or <file>(<pathsep><file>)*
if (!allowDuplicates && map.containsKey(key))
fail(key + " specified more than once");
fail(key + " specified more than once in " + option(prefix));
List<String> 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 @@ public final class ModuleBootstrap {
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

View File

@@ -175,6 +175,12 @@ public final class ModulePatcher {
return map.isEmpty();
}
/*
* Returns the names of the patched modules.
*/
Set<String> patchedModules() {
return map.keySet();
}
/**
* A ModuleReader that reads resources from a patched module.

View File

@@ -56,6 +56,14 @@ public final class SystemModules {
*/
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.
*

View File

@@ -573,6 +573,17 @@ IsModuleOption(const char* name) {
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 @@ ParseArguments(int *pargc, char ***pargv,
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 @@ ParseArguments(int *pargc, char ***pargv,
/*
* 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
*/

View File

@@ -1,5 +1,4 @@
#
# Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
# 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
@@ -22,42 +21,16 @@
# 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.
#
# Makefile for building a ResourceBundleControlProvider jar file for testing.
# You may also select a JVM in an arbitrary location with the
# "-XXaltjvm=<jvm_dir>" option, but that too is unsupported
# and may not be available in a future release.
#
# 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
-server KNOWN
-client KNOWN
-minimal KNOWN

View File

@@ -34,6 +34,7 @@ import java.util.ArrayList;
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 @@ public final class SystemModulesPlugin implements Plugin {
*
* static Map<String, ModuleDescriptor> 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 @@ public final class SystemModulesPlugin implements Plugin {
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 final class SystemModulesPlugin implements Plugin {
*/
public ClassWriter getClassWriter() {
int numModules = moduleInfos.size();
int numPackages = 0;
Set<String> 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();

View File

@@ -292,8 +292,6 @@ com/sun/jdi/sde/SourceDebugExtensionTest.java 8158066 windows-
# jdk_util
java/util/spi/ResourceBundleControlProvider/UserDefaultControlTest.java 8062512 generic-all
java/util/BitSet/BitSetStreamTest.java 8079538 generic-all

View File

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

View File

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

View File

@@ -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<String> 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<String> getKeys() {
// Not implemented
return null;
}
}
}

View File

@@ -1,40 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
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.
-->
<!---->
<!-- DTD for properties -->
<!DOCTYPE properties [
<!ELEMENT properties ( comment?, entry* ) >
<!ATTLIST properties version CDATA #FIXED "1.0">
<!ELEMENT comment (#PCDATA) >
<!ELEMENT entry (#PCDATA) >
<!ATTLIST entry key CDATA #REQUIRED>
]>
<properties>
<comment>Test data for UserDefaultControlTest.java</comment>
<entry key="type">XML</entry>
</properties>

View File

@@ -1,40 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
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.
-->
<!---->
<!-- DTD for properties -->
<!DOCTYPE properties [
<!ELEMENT properties ( comment?, entry* ) >
<!ATTLIST properties version CDATA #FIXED "1.0">
<!ELEMENT comment (#PCDATA) >
<!ELEMENT entry (#PCDATA) >
<!ATTLIST entry key CDATA #REQUIRED>
]>
<properties>
<comment>Test data for UserDefaultControlTest.java</comment>
<entry key="type"></entry>
</properties>

View File

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

View File

@@ -56,8 +56,6 @@ public class CustomLauncherTest {
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 @@ public class CustomLauncherTest {
ARCH = osarch;
}
}
LIBARCH = ARCH.equals("i586") ? "i386" : ARCH;
}
public static void main(String[] args) throws Exception {
@@ -184,15 +181,12 @@ public class CustomLauncherTest {
}
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;

View File

@@ -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<String> 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<String> args = new ArrayList<>();
args.add("-verbose");
args.add("-verify");
args.add(signedJarName);
return jarsigner(args);
}
private static OutputAnalyzer jarsigner(List<String> 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);
}
}
}
}

View File

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

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
* 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
@@ -21,23 +21,14 @@
* questions.
*/
package com.foo;
package version;
import java.util.ResourceBundle;
import java.util.spi.ResourceBundleControlProvider;
import java.security.Permission;
public class UserControlProvider implements ResourceBundleControlProvider {
static final ResourceBundle.Control XMLCONTROL = new UserXMLControl();
public class Main {
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;
public static void main(String[] args) {
Version v = new Version();
System.out.println("I am running on version " + v.getVersion());
}
}

View File

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

View File

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

View File

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

View File

@@ -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 <module>=<value>: m1"},
// missing source part
{ "=m2", "Unable to parse --add-exports <module>=<value>: =m2"},
{ "/=m2", "Unable to parse --add-exports <module>/<package>: /" },
{ "m1=m2", "Unable to parse --add-exports <module>/<package>: m1" },
{ "/p1=m2", "Unable to parse --add-exports <module>/<package>: /p1" },
{ "m1p1=m2", "Unable to parse --add-exports <module>/<package>: m1p1" },
// empty list, missing target
{ "m1/p1=", "Unable to parse --add-exports <module>=<value>: 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());
}
}

View File

@@ -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 <module>=<value>: m1" },
// missing source part
{ "=m2", "Unable to parse --add-reads <module>=<value>: =m2" },
// empty list, missing target
{ "m1=", "Unable to parse --add-reads <module>=<value>: 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);
}
}

View File

@@ -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 <module>=<value>: =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 <module>=<value>: 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);
}
}

View File

@@ -29,4 +29,8 @@ package jdk.internal.module;
*/
public final class SystemModules {
public static final String[] MODULE_NAMES = new String[0];
public static boolean hasSplitPackages() {
return true;
}
}