From 3545dc8f375305c78bcdfd1abfbcac7c4264bc1a Mon Sep 17 00:00:00 2001 From: dfuchs Date: Wed, 16 Oct 2013 20:47:30 +0200 Subject: [PATCH] 8013839: Enhance Logger API for handling of resource bundles 4814565: (rb) add method to get basename from a ResourceBundle Summary: adds Logger.setResourceBundle(ResourceBundle) and ResourceBundle.getBaseBundleName() Reviewed-by: mchung, naoto --- .../classes/java/util/ResourceBundle.java | 18 + .../classes/java/util/logging/Logger.java | 260 ++++++++++-- .../TestGetBaseBundleName.java | 144 +++++++ .../resources/ListBundle.java | 41 ++ .../resources/ListBundle_fr.java | 41 ++ .../resources/PropertyBundle.properties | 24 ++ .../resources/PropertyBundle_fr.properties | 24 ++ .../Logger/logrb/TestLogrbResourceBundle.java | 381 +++++++++++++++++ .../Logger/logrb/resources/ListBundle.java | 41 ++ .../Logger/logrb/resources/ListBundle_fr.java | 41 ++ .../logrb/resources/PropertyBundle.properties | 24 ++ .../resources/PropertyBundle_fr.properties | 24 ++ .../TestSetResourceBundle.java | 393 ++++++++++++++++++ .../resources/ListBundle.java | 41 ++ .../resources/ListBundle_fr.java | 41 ++ .../resources/PropertyBundle.properties | 24 ++ .../resources/PropertyBundle_fr.properties | 24 ++ 17 files changed, 1560 insertions(+), 26 deletions(-) create mode 100644 test/java/util/ResourceBundle/getBaseBundleName/TestGetBaseBundleName.java create mode 100644 test/java/util/ResourceBundle/getBaseBundleName/resources/ListBundle.java create mode 100644 test/java/util/ResourceBundle/getBaseBundleName/resources/ListBundle_fr.java create mode 100644 test/java/util/ResourceBundle/getBaseBundleName/resources/PropertyBundle.properties create mode 100644 test/java/util/ResourceBundle/getBaseBundleName/resources/PropertyBundle_fr.properties create mode 100644 test/java/util/logging/Logger/logrb/TestLogrbResourceBundle.java create mode 100644 test/java/util/logging/Logger/logrb/resources/ListBundle.java create mode 100644 test/java/util/logging/Logger/logrb/resources/ListBundle_fr.java create mode 100644 test/java/util/logging/Logger/logrb/resources/PropertyBundle.properties create mode 100644 test/java/util/logging/Logger/logrb/resources/PropertyBundle_fr.properties create mode 100644 test/java/util/logging/Logger/setResourceBundle/TestSetResourceBundle.java create mode 100644 test/java/util/logging/Logger/setResourceBundle/resources/ListBundle.java create mode 100644 test/java/util/logging/Logger/setResourceBundle/resources/ListBundle_fr.java create mode 100644 test/java/util/logging/Logger/setResourceBundle/resources/PropertyBundle.properties create mode 100644 test/java/util/logging/Logger/setResourceBundle/resources/PropertyBundle_fr.properties diff --git a/src/share/classes/java/util/ResourceBundle.java b/src/share/classes/java/util/ResourceBundle.java index b16174d30..c2900fa3c 100644 --- a/src/share/classes/java/util/ResourceBundle.java +++ b/src/share/classes/java/util/ResourceBundle.java @@ -310,6 +310,24 @@ public abstract class ResourceBundle { */ private static final ReferenceQueue referenceQueue = new ReferenceQueue<>(); + /** + * Returns the base name of this bundle, if known, or {@code null} if unknown. + * + * If not null, then this is the value of the {@code baseName} parameter + * that was passed to the {@code ResourceBundle.getBundle(...)} method + * when the resource bundle was loaded. + * + * @return The base name of the resource bundle, as provided to and expected + * by the {@code ResourceBundle.getBundle(...)} methods. + * + * @see #getBundle(java.lang.String, java.util.Locale, java.lang.ClassLoader) + * + * @since 1.8 + */ + public String getBaseBundleName() { + return name; + } + /** * The parent bundle of this bundle. * The parent bundle is searched by {@link #getObject getObject} diff --git a/src/share/classes/java/util/logging/Logger.java b/src/share/classes/java/util/logging/Logger.java index 19e31352c..d67391769 100644 --- a/src/share/classes/java/util/logging/Logger.java +++ b/src/share/classes/java/util/logging/Logger.java @@ -88,17 +88,21 @@ import sun.reflect.Reflection; * the LogRecord to its output Handlers. By default, loggers also * publish to their parent's Handlers, recursively up the tree. *

- * Each Logger may have a ResourceBundle name associated with it. - * The named bundle will be used for localizing logging messages. - * If a Logger does not have its own ResourceBundle name, then - * it will inherit the ResourceBundle name from its parent, - * recursively up the tree. + * Each Logger may have a {@code ResourceBundle} associated with it. + * The {@code ResourceBundle} may be specified by name, using the + * {@link #getLogger(java.lang.String, java.lang.String)} factory + * method, or by value - using the {@link + * #setResourceBundle(java.util.ResourceBundle) setResourceBundle} method. + * This bundle will be used for localizing logging messages. + * If a Logger does not have its own {@code ResourceBundle} or resource bundle + * name, then it will inherit the {@code ResourceBundle} or resource bundle name + * from its parent, recursively up the tree. *

* Most of the logger output methods take a "msg" argument. This * msg argument may be either a raw value or a localization key. * During formatting, if the logger has (or inherits) a localization - * ResourceBundle and if the ResourceBundle has a mapping for the msg - * string, then the msg string is replaced by the localized value. + * {@code ResourceBundle} and if the {@code ResourceBundle} has a mapping for + * the msg string, then the msg string is replaced by the localized value. * Otherwise the original msg string is used. Typically, formatters use * java.text.MessageFormat style formatting to format parameters, so * for example a format string "{0} {1}" would format two parameters @@ -131,10 +135,30 @@ import sun.reflect.Reflection; logger.log(Level.FINER, DiagnosisMessages::systemHealthStatus); *

- * When mapping ResourceBundle names to ResourceBundles, the Logger - * will first try to use the Thread's ContextClassLoader. If that - * is null it will try the - * {@linkplain java.lang.ClassLoader#getSystemClassLoader() system ClassLoader} instead. + * When looking for a {@code ResourceBundle}, the logger will first look at + * whether a bundle was specified using {@link + * #setResourceBundle(java.util.ResourceBundle) setResourceBundle}, and then + * only whether a resource bundle name was specified through the {@link + * #getLogger(java.lang.String, java.lang.String) getLogger} factory method. + * If no {@code ResourceBundle} or no resource bundle name is found, + * then it will use the nearest {@code ResourceBundle} or resource bundle + * name inherited from its parent tree.
+ * When a {@code ResourceBundle} was inherited or specified through the + * {@link + * #setResourceBundle(java.util.ResourceBundle) setResourceBundle} method, then + * that {@code ResourceBundle} will be used. Otherwise if the logger only + * has or inherited a resource bundle name, then that resource bundle name + * will be mapped to a {@code ResourceBundle} object, using the default Locale + * at the time of logging. + *
When mapping resource bundle names to + * {@code ResourceBundle} objects, the logger will first try to use the + * Thread's {@linkplain java.lang.Thread#getContextClassLoader() context class + * loader} to map the given resource bundle name to a {@code ResourceBundle}. + * If the thread context class loader is {@code null}, it will try the + * {@linkplain java.lang.ClassLoader#getSystemClassLoader() system class loader} + * instead. If the {@code ResourceBundle} is still not found, it will use the + * class loader of the first caller of the {@link + * #getLogger(java.lang.String, java.lang.String) getLogger} factory method. *

* Formatting (including localization) is the responsibility of * the output Handler, which will typically call a Formatter. @@ -154,7 +178,7 @@ import sun.reflect.Reflection; *

  • * There are a set of "logrb" method (for "log with resource bundle") * that are like the "logp" method, but also take an explicit resource - * bundle name for use in localizing the log message. + * bundle object for use in localizing the log message. *

  • * There are convenience methods for tracing method entries (the * "entering" methods), method returns (the "exiting" methods) and @@ -198,18 +222,20 @@ public class Logger { private String name; private final CopyOnWriteArrayList handlers = new CopyOnWriteArrayList<>(); - private String resourceBundleName; + private String resourceBundleName; // Base name of the bundle. + private ResourceBundle userBundle; // Bundle set through setResourceBundle. private volatile boolean useParentHandlers = true; private volatile Filter filter; private boolean anonymous; + // Cache to speed up behavior of findResourceBundle: private ResourceBundle catalog; // Cached resource bundle private String catalogName; // name associated with catalog private Locale catalogLocale; // locale associated with catalog // The fields relating to parent-child relationships and levels // are managed under a separate lock, the treeLock. - private static Object treeLock = new Object(); + private static final Object treeLock = new Object(); // We keep weak references from parents to children, but strong // references from children to parents. private volatile Logger parent; // our nearest parent. @@ -372,6 +398,7 @@ public class Logger { static boolean disableCallerCheck = getBooleanProperty("sun.util.logging.disableCallerCheck"); private static boolean getBooleanProperty(final String key) { String s = AccessController.doPrivileged(new PrivilegedAction() { + @Override public String run() { return System.getProperty(key); } @@ -579,11 +606,18 @@ public class Logger { /** * Retrieve the localization resource bundle for this - * logger for the current default locale. Note that if - * the result is null, then the Logger will use a resource - * bundle inherited from its parent. + * logger. + * This method will return a {@code ResourceBundle} that was either + * set by the {@link + * #setResourceBundle(java.util.ResourceBundle) setResourceBundle} method or + * mapped from the + * the resource bundle name set via the {@link + * Logger#getLogger(java.lang.String, java.lang.String) getLogger} factory + * method for the current default locale. + *
    Note that if the result is {@code null}, then the Logger will use a resource + * bundle or resource bundle name inherited from its parent. * - * @return localization bundle (may be null) + * @return localization bundle (may be {@code null}) */ public ResourceBundle getResourceBundle() { return findResourceBundle(getResourceBundleName(), true); @@ -591,10 +625,16 @@ public class Logger { /** * Retrieve the localization resource bundle name for this - * logger. Note that if the result is null, then the Logger - * will use a resource bundle name inherited from its parent. + * logger. + * This is either the name specified through the {@link + * #getLogger(java.lang.String, java.lang.String) getLogger} factory method, + * or the {@linkplain ResourceBundle#getBaseBundleName() base name} of the + * ResourceBundle set through {@link + * #setResourceBundle(java.util.ResourceBundle) setResourceBundle} method. + *
    Note that if the result is {@code null}, then the Logger will use a resource + * bundle or resource bundle name inherited from its parent. * - * @return localization bundle name (may be null) + * @return localization bundle name (may be {@code null}) */ public String getResourceBundleName() { return resourceBundleName; @@ -665,10 +705,11 @@ public class Logger { // resource bundle and then call "void log(LogRecord)". private void doLog(LogRecord lr) { lr.setLoggerName(name); - String ebname = getEffectiveResourceBundleName(); - if (ebname != null && !ebname.equals(SYSTEM_LOGGER_RB_NAME)) { + final ResourceBundle bundle = getEffectiveResourceBundle(); + final String ebname = getEffectiveResourceBundleName(); + if (ebname != null && bundle != null) { lr.setResourceBundleName(ebname); - lr.setResourceBundle(findResourceBundle(ebname, true)); + lr.setResourceBundle(bundle); } log(lr); } @@ -1000,6 +1041,16 @@ public class Logger { log(lr); } + // Private support method for logging for "logrb" methods. + private void doLog(LogRecord lr, ResourceBundle rb) { + lr.setLoggerName(name); + if (rb != null) { + lr.setResourceBundleName(rb.getBaseBundleName()); + lr.setResourceBundle(rb); + } + log(lr); + } + /** * Log a message, specifying source class, method, and resource bundle name * with no arguments. @@ -1018,7 +1069,11 @@ public class Logger { * @param bundleName name of resource bundle to localize msg, * can be null * @param msg The string message (or a key in the message catalog) + * @deprecated Use {@link #logrb(java.util.logging.Level, java.lang.String, + * java.lang.String, java.util.ResourceBundle, java.lang.String, + * java.lang.Object...)} instead. */ + @Deprecated public void logrb(Level level, String sourceClass, String sourceMethod, String bundleName, String msg) { if (!isLoggable(level)) { @@ -1049,7 +1104,11 @@ public class Logger { * can be null * @param msg The string message (or a key in the message catalog) * @param param1 Parameter to the log message. + * @deprecated Use {@link #logrb(java.util.logging.Level, java.lang.String, + * java.lang.String, java.util.ResourceBundle, java.lang.String, + * java.lang.Object...)} instead */ + @Deprecated public void logrb(Level level, String sourceClass, String sourceMethod, String bundleName, String msg, Object param1) { if (!isLoggable(level)) { @@ -1082,7 +1141,11 @@ public class Logger { * can be null. * @param msg The string message (or a key in the message catalog) * @param params Array of parameters to the message + * @deprecated Use {@link #logrb(java.util.logging.Level, java.lang.String, + * java.lang.String, java.util.ResourceBundle, java.lang.String, + * java.lang.Object...)} instead. */ + @Deprecated public void logrb(Level level, String sourceClass, String sourceMethod, String bundleName, String msg, Object params[]) { if (!isLoggable(level)) { @@ -1095,6 +1158,41 @@ public class Logger { doLog(lr, bundleName); } + /** + * Log a message, specifying source class, method, and resource bundle, + * with an optional list of message parameters. + *

    + * If the logger is currently enabled for the given message + * level then a corresponding LogRecord is created and forwarded + * to all the registered output Handler objects. + *

    + * The {@code msg} string is localized using the given resource bundle. + * If the resource bundle is {@code null}, then the {@code msg} string is not + * localized. + *

    + * @param level One of the message level identifiers, e.g., SEVERE + * @param sourceClass Name of the class that issued the logging request + * @param sourceMethod Name of the method that issued the logging request + * @param bundle Resource bundle to localize {@code msg}, + * can be {@code null}. + * @param msg The string message (or a key in the message catalog) + * @param params Parameters to the message (optional, may be none). + * @since 1.8 + */ + public void logrb(Level level, String sourceClass, String sourceMethod, + ResourceBundle bundle, String msg, Object... params) { + if (!isLoggable(level)) { + return; + } + LogRecord lr = new LogRecord(level, msg); + lr.setSourceClassName(sourceClass); + lr.setSourceMethodName(sourceMethod); + if (params != null && params.length != 0) { + lr.setParameters(params); + } + doLog(lr, bundle); + } + /** * Log a message, specifying source class, method, and resource bundle name, * with associated Throwable information. @@ -1119,7 +1217,11 @@ public class Logger { * can be null * @param msg The string message (or a key in the message catalog) * @param thrown Throwable associated with log message. + * @deprecated Use {@link #logrb(java.util.logging.Level, java.lang.String, + * java.lang.String, java.util.ResourceBundle, java.lang.String, + * java.lang.Throwable)} instead. */ + @Deprecated public void logrb(Level level, String sourceClass, String sourceMethod, String bundleName, String msg, Throwable thrown) { if (!isLoggable(level)) { @@ -1132,6 +1234,43 @@ public class Logger { doLog(lr, bundleName); } + /** + * Log a message, specifying source class, method, and resource bundle, + * with associated Throwable information. + *

    + * If the logger is currently enabled for the given message + * level then the given arguments are stored in a LogRecord + * which is forwarded to all registered output handlers. + *

    + * The {@code msg} string is localized using the given resource bundle. + * If the resource bundle is {@code null}, then the {@code msg} string is not + * localized. + *

    + * Note that the thrown argument is stored in the LogRecord thrown + * property, rather than the LogRecord parameters property. Thus it is + * processed specially by output Formatters and is not treated + * as a formatting parameter to the LogRecord message property. + *

    + * @param level One of the message level identifiers, e.g., SEVERE + * @param sourceClass Name of the class that issued the logging request + * @param sourceMethod Name of the method that issued the logging request + * @param bundle Resource bundle to localize {@code msg}, + * can be {@code null} + * @param msg The string message (or a key in the message catalog) + * @param thrown Throwable associated with the log message. + * @since 1.8 + */ + public void logrb(Level level, String sourceClass, String sourceMethod, + ResourceBundle bundle, String msg, Throwable thrown) { + if (!isLoggable(level)) { + return; + } + LogRecord lr = new LogRecord(level, msg); + lr.setSourceClassName(sourceClass); + lr.setSourceMethodName(sourceMethod); + lr.setThrown(thrown); + doLog(lr, bundle); + } //====================================================================== // Start of convenience methods for logging method entries and returns. @@ -1610,6 +1749,7 @@ public class Logger { private static ResourceBundle findSystemResourceBundle(final Locale locale) { // the resource bundle is in a restricted package return AccessController.doPrivileged(new PrivilegedAction() { + @Override public ResourceBundle run() { try { return ResourceBundle.getBundle(SYSTEM_LOGGER_RB_NAME, @@ -1650,7 +1790,10 @@ public class Logger { Locale currentLocale = Locale.getDefault(); // Normally we should hit on our simple one entry cache. - if (catalog != null && currentLocale.equals(catalogLocale) + if (userBundle != null && + name.equals(resourceBundleName)) { + return userBundle; + } else if (catalog != null && currentLocale.equals(catalogLocale) && name.equals(catalogName)) { return catalog; } @@ -1737,6 +1880,45 @@ public class Logger { resourceBundleName = name; } + /** + * Sets a resource bundle on this logger. + * All messages will be logged using the given resource bundle for its + * specific {@linkplain ResourceBundle#getLocale locale}. + * @param bundle The resource bundle that this logger shall use. + * @throws NullPointerException if the given bundle is {@code null}. + * @throws IllegalArgumentException if the given bundle doesn't have a + * {@linkplain ResourceBundle#getBaseBundleName base name}, + * or if this logger already has a resource bundle set but + * the given bundle has a different base name. + * @throws SecurityException if a security manager exists and if + * the caller does not have LoggingPermission("control"). + * @since 1.8 + */ + public void setResourceBundle(ResourceBundle bundle) { + checkPermission(); + + // Will throw NPE if bundle is null. + final String baseName = bundle.getBaseBundleName(); + + // bundle must have a name + if (baseName == null || baseName.isEmpty()) { + throw new IllegalArgumentException("resource bundle must have a name"); + } + + synchronized (this) { + final boolean canReplaceResourceBundle = resourceBundleName == null + || resourceBundleName.equals(baseName); + + if (!canReplaceResourceBundle) { + throw new IllegalArgumentException("can't replace resource bundle"); + } + + + userBundle = bundle; + resourceBundleName = baseName; + } + } + /** * Return the parent for this Logger. *

    @@ -1813,7 +1995,7 @@ public class Logger { // we didn't have a previous parent ref = manager.new LoggerWeakRef(this); } - ref.setParentRef(new WeakReference(parent)); + ref.setParentRef(new WeakReference<>(parent)); parent.kids.add(ref); // As a result of the reparenting, the effective level @@ -1895,4 +2077,30 @@ public class Logger { } + private ResourceBundle getEffectiveResourceBundle() { + Logger target = this; + if (SYSTEM_LOGGER_RB_NAME.equals(resourceBundleName)) return null; + ResourceBundle localRB = getResourceBundle(); + if (localRB != null) { + return localRB; + } + + while (target != null) { + final ResourceBundle rb = target.userBundle; + if (rb != null) { + return rb; + } + final String rbn = target.getResourceBundleName(); + if (rbn != null) { + if (!SYSTEM_LOGGER_RB_NAME.equals(rbn)) { + return findResourceBundle(rbn, true); + } else { + return null; + } + } + target = target.getParent(); + } + return null; + } + } diff --git a/test/java/util/ResourceBundle/getBaseBundleName/TestGetBaseBundleName.java b/test/java/util/ResourceBundle/getBaseBundleName/TestGetBaseBundleName.java new file mode 100644 index 000000000..aca4017c7 --- /dev/null +++ b/test/java/util/ResourceBundle/getBaseBundleName/TestGetBaseBundleName.java @@ -0,0 +1,144 @@ +/* + * Copyright (c) 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. + */ +import java.util.Collections; +import java.util.Enumeration; +import java.util.Locale; +import java.util.MissingResourceException; +import java.util.PropertyResourceBundle; +import java.util.ResourceBundle; + +/** + * @test + * @bug 4814565 + * @summary tests ResourceBundle.getBaseBundleName(); + * @build TestGetBaseBundleName resources.ListBundle resources.ListBundle_fr + * @run main TestGetBaseBundleName + * @author danielfuchs + */ +public class TestGetBaseBundleName { + + final static String PROPERTY_BUNDLE_NAME = "resources/PropertyBundle"; + final static String LIST_BUNDLE_NAME = "resources.ListBundle"; + + public static String getBaseName(ResourceBundle bundle) { + return bundle == null ? null : bundle.getBaseBundleName(); + } + + public static void main(String... args) throws Exception { + + Locale defaultLocale = Locale.getDefault(); + System.out.println("Default locale is: " + defaultLocale); + for (String baseName : new String[] { + PROPERTY_BUNDLE_NAME, + LIST_BUNDLE_NAME + }) { + ResourceBundle bundle = ResourceBundle.getBundle(baseName); + System.out.println(getBaseName(bundle)); + if (!Locale.ROOT.equals(bundle.getLocale())) { + throw new RuntimeException("Unexpected locale: " + + bundle.getLocale()); + } + if (!baseName.equals(getBaseName(bundle))) { + throw new RuntimeException("Unexpected base name: " + + getBaseName(bundle)); + } + Locale.setDefault(Locale.FRENCH); + try { + ResourceBundle bundle_fr = ResourceBundle.getBundle(baseName); + if (!Locale.FRENCH.equals(bundle_fr.getLocale())) { + throw new RuntimeException("Unexpected locale: " + + bundle_fr.getLocale()); + } + if (!baseName.equals(getBaseName(bundle_fr))) { + throw new RuntimeException("Unexpected base name: " + + getBaseName(bundle_fr)); + } + } finally { + Locale.setDefault(defaultLocale); + } + } + + final ResourceBundle bundle = new ResourceBundle() { + @Override + protected Object handleGetObject(String key) { + if ("dummy".equals(key)) return "foo"; + throw new MissingResourceException("Missing key", + this.getClass().getName(), key); + } + @Override + public Enumeration getKeys() { + return Collections.enumeration(java.util.Arrays.asList( + new String[] {"dummy"})); + } + }; + + if (getBaseName(bundle) != null) { + throw new RuntimeException("Expected null baseName, got " + + getBaseName(bundle)); + } + + final ResourceBundle bundle2 = new ResourceBundle() { + @Override + protected Object handleGetObject(String key) { + if ("dummy".equals(key)) return "foo"; + throw new MissingResourceException("Missing key", + this.getClass().getName(), key); + } + @Override + public Enumeration getKeys() { + return Collections.enumeration(java.util.Arrays.asList( + new String[] {"dummy"})); + } + + @Override + public String getBaseBundleName() { + return this.getClass().getName(); + } + + + }; + + if (!bundle2.getClass().getName().equals(getBaseName(bundle2))) { + throw new RuntimeException("Expected " + + bundle2.getClass().getName() + ", got " + + getBaseName(bundle2)); + } + + ResourceBundle propertyBundle = new PropertyResourceBundle( + TestGetBaseBundleName.class.getResourceAsStream( + PROPERTY_BUNDLE_NAME+".properties")); + + if (getBaseName(propertyBundle) != null) { + throw new RuntimeException("Expected null baseName, got " + + getBaseName(propertyBundle)); + } + + ResourceBundle listBundle = new resources.ListBundle_fr(); + if (getBaseName(listBundle) != null) { + throw new RuntimeException("Expected null baseName, got " + + getBaseName(listBundle)); + } + + + } +} diff --git a/test/java/util/ResourceBundle/getBaseBundleName/resources/ListBundle.java b/test/java/util/ResourceBundle/getBaseBundleName/resources/ListBundle.java new file mode 100644 index 000000000..121db2914 --- /dev/null +++ b/test/java/util/ResourceBundle/getBaseBundleName/resources/ListBundle.java @@ -0,0 +1,41 @@ +/* + * Copyright (c) 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 resources; + +import java.util.ListResourceBundle; + +/** + * + * @author danielfuchs + */ +public class ListBundle extends ListResourceBundle { + + @Override + protected Object[][] getContents() { + return new Object[][] { + { "dummy", "foo" }, + }; + + } + +} diff --git a/test/java/util/ResourceBundle/getBaseBundleName/resources/ListBundle_fr.java b/test/java/util/ResourceBundle/getBaseBundleName/resources/ListBundle_fr.java new file mode 100644 index 000000000..b168bf7ab --- /dev/null +++ b/test/java/util/ResourceBundle/getBaseBundleName/resources/ListBundle_fr.java @@ -0,0 +1,41 @@ +/* + * Copyright (c) 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 resources; + +import java.util.ListResourceBundle; + +/** + * + * @author danielfuchs + */ +public class ListBundle_fr extends ListResourceBundle { + + @Override + protected Object[][] getContents() { + return new Object[][] { + { "dummy", "toto" }, + }; + + } + +} diff --git a/test/java/util/ResourceBundle/getBaseBundleName/resources/PropertyBundle.properties b/test/java/util/ResourceBundle/getBaseBundleName/resources/PropertyBundle.properties new file mode 100644 index 000000000..343c64825 --- /dev/null +++ b/test/java/util/ResourceBundle/getBaseBundleName/resources/PropertyBundle.properties @@ -0,0 +1,24 @@ +# +# Copyright (c) 20013, 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. +# +dummy=foo + diff --git a/test/java/util/ResourceBundle/getBaseBundleName/resources/PropertyBundle_fr.properties b/test/java/util/ResourceBundle/getBaseBundleName/resources/PropertyBundle_fr.properties new file mode 100644 index 000000000..312027104 --- /dev/null +++ b/test/java/util/ResourceBundle/getBaseBundleName/resources/PropertyBundle_fr.properties @@ -0,0 +1,24 @@ +# +# Copyright (c) 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. +# +dummy=toto + diff --git a/test/java/util/logging/Logger/logrb/TestLogrbResourceBundle.java b/test/java/util/logging/Logger/logrb/TestLogrbResourceBundle.java new file mode 100644 index 000000000..f47219492 --- /dev/null +++ b/test/java/util/logging/Logger/logrb/TestLogrbResourceBundle.java @@ -0,0 +1,381 @@ +/* + * Copyright (c) 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. + */ +import java.util.Arrays; +import java.util.Locale; +import java.util.Objects; +import java.util.ResourceBundle; +import java.util.logging.Handler; +import java.util.logging.Level; +import java.util.logging.LogRecord; +import java.util.logging.Logger; +import resources.ListBundle; + +/** + * @test + * @bug 8013839 + * @summary tests Logger.logrb(..., ResourceBundle); + * @build TestLogrbResourceBundle resources.ListBundle resources.ListBundle_fr + * @run main TestLogrbResourceBundle + * @author danielfuchs + */ +public class TestLogrbResourceBundle { + + final static String LIST_BUNDLE_NAME = "resources.ListBundle"; + final static String PROPERTY_BUNDLE_NAME = "resources.PropertyBundle"; + + /** + * A dummy handler class that we can use to check the bundle/bundle name + * that was present in the last LogRecord instance published. + */ + static final class TestHandler extends Handler { + ResourceBundle lastBundle = null; + String lastBundleName = null; + Object[] lastParams = null; + Throwable lastThrown = null; + String lastMessage = null; + @Override + public void publish(LogRecord record) { + lastBundle = record.getResourceBundle(); + lastBundleName = record.getResourceBundleName(); + lastParams = record.getParameters(); + lastThrown = record.getThrown(); + lastMessage = record.getMessage(); + } + + @Override + public void flush() { + } + + @Override + public void close() throws SecurityException { + } + } + + /** + * We're going to do the same test with each of the different new logrb + * forms. + *

      + *
    • LOGRB_NO_ARGS: calling logrb with no message argument. + *
    • LOGRB_SINGLE_ARG: calling logrb with a single message argument. + *
    • LOGRB_ARG_ARRAY: calling logrb with an array of message arguments. + *
    • LOGRB_VARARGS: calling logrb with a variable list of message arguments. + *
    • LOGRB_THROWABLE: calling logrb with an exception. + *
    + */ + private static enum TestCase { + LOGRB_NO_ARGS, LOGRB_SINGLE_ARG, LOGRB_ARG_ARRAY, LOGRB_VARARGS, LOGRB_THROWABLE; + + public void logrb(Logger logger, ResourceBundle bundle) { + switch(this) { + case LOGRB_NO_ARGS: + logger.logrb(Level.CONFIG, + TestLogrbResourceBundle.class.getName(), + "main", bundle, "dummy"); + break; + case LOGRB_SINGLE_ARG: + logger.logrb(Level.CONFIG, + TestLogrbResourceBundle.class.getName(), + "main", bundle, "dummy", "bar"); + break; + case LOGRB_ARG_ARRAY: + logger.logrb(Level.CONFIG, + TestLogrbResourceBundle.class.getName(), + "main", bundle, "dummy", + new Object[] { "bar", "baz"} ); + break; + case LOGRB_VARARGS: + logger.logrb(Level.CONFIG, + TestLogrbResourceBundle.class.getName(), + "main", bundle, "dummy", + "bar", "baz" ); + break; + case LOGRB_THROWABLE: + logger.logrb(Level.CONFIG, + TestLogrbResourceBundle.class.getName(), + "main", bundle, "dummy", + new Exception("dummy exception") ); + break; + default: + } + } + + /** + * Checks that the last published logged record had the expected data. + * @param handler the TestHandler through which the record was published. + */ + public void checkLogged(TestHandler handler) { + checkLogged(handler.lastMessage, handler.lastParams, handler.lastThrown); + } + + private void checkLogged(String message, Object[] parameters, Throwable thrown) { + switch(this) { + case LOGRB_NO_ARGS: + if ("dummy".equals(message) && thrown == null + && (parameters == null || parameters.length == 0)) { + return; // OK: all was as expected. + } + break; + case LOGRB_SINGLE_ARG: + if ("dummy".equals(message) && thrown == null + && parameters != null + && parameters.length == 1 + && "bar".equals(parameters[0])) { + return; // OK: all was as expected. + } + break; + case LOGRB_VARARGS: + case LOGRB_ARG_ARRAY: + if ("dummy".equals(message) && thrown == null + && parameters != null + && parameters.length > 1 + && Arrays.deepEquals(new Object[] { "bar", "baz"}, + parameters)) { + return; // OK: all was as expected. + } + break; + case LOGRB_THROWABLE: + if ("dummy".equals(message) && thrown != null + && thrown.getClass() == Exception.class + && "dummy exception".equals(thrown.getMessage())) { + return; // OK: all was as expected. + } + break; + default: + } + + // We had some unexpected stuff: throw exception. + throw new RuntimeException(this + ": " + + "Unexpected content in last published log record: " + + "\n\tmessage=\"" + message + "\"" + + "\n\tparameters=" + Arrays.toString(parameters) + + "\n\tthrown=" + thrown); + } + } + + static String getBaseName(ResourceBundle bundle) { + return bundle == null ? null : bundle.getBaseBundleName(); + } + + public static void main(String... args) throws Exception { + + Locale defaultLocale = Locale.getDefault(); + + final ResourceBundle bundle = ResourceBundle.getBundle(LIST_BUNDLE_NAME); + final ResourceBundle bundle_fr = + ResourceBundle.getBundle(LIST_BUNDLE_NAME, Locale.FRENCH); + final ResourceBundle propertyBundle = ResourceBundle.getBundle(PROPERTY_BUNDLE_NAME); + final ResourceBundle propertyBundle_fr = + ResourceBundle.getBundle(PROPERTY_BUNDLE_NAME, Locale.FRENCH); + Logger foobar = Logger.getLogger("foo.bar"); + final TestHandler handler = new TestHandler(); + foobar.addHandler(handler); + foobar.setLevel(Level.CONFIG); + + final ResourceBundle anonBundle = new ListBundle(); + try { + // First we're going to call logrb on a logger that + // has no bundle set... + + // For each possible logrb form... + for (TestCase test : TestCase.values()) { + // For various resource bundles + for (ResourceBundle b : new ResourceBundle[] { + anonBundle, bundle, bundle_fr, propertyBundle, + anonBundle, null, propertyBundle_fr, + }) { + // Prints the resource bundle base name (can be null, + // we don't enforce non-null names in logrb. + final String baseName = getBaseName(b); + System.out.println("Testing " + test + " with " + baseName); + + // log in the 'foobar' logger using bundle 'b' + test.logrb(foobar, b); + + // check that the correct bundle was set in the published + // LogRecord + if (handler.lastBundle != b) { + throw new RuntimeException("Unexpected bundle: " + + handler.lastBundle); + } + + // check that the correct bundle name was set in the published + // LogRecord + if (!Objects.equals(handler.lastBundleName, baseName)) { + throw new RuntimeException("Unexpected bundle name: " + + handler.lastBundleName); + } + + // check that calling foobar.logrb() had no side effect on + // the bundle used by foobar. foobar should still have no + // bundle set. + if (foobar.getResourceBundle() != null) { + throw new RuntimeException("Unexpected bundle: " + + foobar.getResourceBundle()); + } + if (foobar.getResourceBundleName() != null) { + throw new RuntimeException("Unexpected bundle: " + + foobar.getResourceBundleName()); + } + + // Test that the last published log record had all the + // data that this test case had logged (message, parameters, + // thrown... + test.checkLogged(handler); + } + } + + // No we're going to set a resource bundle on the foobar logger + // and do it all again... + + // For the same bundle in two different locales + for (ResourceBundle propBundle : new ResourceBundle[] { + propertyBundle, propertyBundle_fr, + }) { + + // set the bundle on foobar... + foobar.setResourceBundle(propBundle); + + // check the bundle was correctly set... + if (!propBundle.equals(foobar.getResourceBundle())) { + throw new RuntimeException("Unexpected bundle: " + + foobar.getResourceBundle()); + } + if (!Objects.equals(getBaseName(propBundle), foobar.getResourceBundleName())) { + throw new RuntimeException("Unexpected bundle name: " + + foobar.getResourceBundleName()); + } + + System.out.println("Configuring " + foobar.getName() + " with " + + propBundle); + + // for each possible logrb form... + for (TestCase test : TestCase.values()) { + + // for various resource bundles + for (ResourceBundle b : new ResourceBundle[] { + anonBundle, bundle, null, bundle_fr, propertyBundle, + anonBundle, propertyBundle_fr, + }) { + + final String baseName = getBaseName(b); + System.out.println("Testing " + test + " with " + baseName); + + // call foobar.logrb + test.logrb(foobar, b); + + // check which resource bundle was used (should be + // the one passed to logrb) + if (handler.lastBundle != b) { + throw new RuntimeException("Unexpected bundle: " + + handler.lastBundle); + } + if (!Objects.equals(handler.lastBundleName, baseName)) { + throw new RuntimeException("Unexpected bundle name: " + + handler.lastBundleName); + } + + // Verify there was no side effect on the bundle that + // had been previously set on the logger... + if (foobar.getResourceBundle() != propBundle) { + throw new RuntimeException("Unexpected bundle: " + + foobar.getResourceBundle()); + } + if (!Objects.equals(getBaseName(propBundle), + foobar.getResourceBundleName())) { + throw new RuntimeException("Unexpected bundle name: " + + foobar.getResourceBundleName()); + } + + // Checked that the published LogRecord had the + // expected content logged by this test case. + test.checkLogged(handler); + } + } + } + + // Now we're going to the same thing, but with a logger which + // has an inherited resource bundle. + Logger foobaz = Logger.getLogger("foo.bar.baz"); + + // check that foobaz has no bundle set locally. + if (foobaz.getResourceBundle() != null) { + throw new RuntimeException("Unexpected bundle: " + + foobaz.getResourceBundle()); + } + if (foobaz.getResourceBundleName() != null) { + throw new RuntimeException("Unexpected bundle: " + + foobaz.getResourceBundle()); + } + + // The current locale should have no effect on logrb. + Locale.setDefault(Locale.GERMAN); // shouldn't change anything... + + // for each possible logrb form + for (TestCase test : TestCase.values()) { + + // for various resource bundle + for (ResourceBundle b : new ResourceBundle[] { + anonBundle, bundle, bundle_fr, propertyBundle, null, + anonBundle, propertyBundle_fr, + }) { + final String baseName = getBaseName(b); + System.out.println("Testing " + test + " with " + + foobaz.getName() + " and " + + baseName); + + // call foobaz.logrb with the bundle + test.logrb(foobaz, b); + + // check that the bundle passed to logrb was used. + if (handler.lastBundle != b) { + throw new RuntimeException("Unexpected bundle: " + + handler.lastBundle); + } + if (!Objects.equals(handler.lastBundleName, baseName)) { + throw new RuntimeException("Unexpected bundle name: " + + handler.lastBundleName); + } + + // check that there was no effect on the bundle set + // on foobaz: it should still be null. + if (foobaz.getResourceBundle() != null) { + throw new RuntimeException("Unexpected bundle: " + + foobaz.getResourceBundle()); + } + if (foobaz.getResourceBundleName() != null) { + throw new RuntimeException("Unexpected bundle: " + + foobaz.getResourceBundleName()); + } + + // check that the last published log record had all the + // data that was logged by this testcase. + test.checkLogged(handler); + } + } + + } finally { + Locale.setDefault(defaultLocale); + } + + } +} diff --git a/test/java/util/logging/Logger/logrb/resources/ListBundle.java b/test/java/util/logging/Logger/logrb/resources/ListBundle.java new file mode 100644 index 000000000..121db2914 --- /dev/null +++ b/test/java/util/logging/Logger/logrb/resources/ListBundle.java @@ -0,0 +1,41 @@ +/* + * Copyright (c) 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 resources; + +import java.util.ListResourceBundle; + +/** + * + * @author danielfuchs + */ +public class ListBundle extends ListResourceBundle { + + @Override + protected Object[][] getContents() { + return new Object[][] { + { "dummy", "foo" }, + }; + + } + +} diff --git a/test/java/util/logging/Logger/logrb/resources/ListBundle_fr.java b/test/java/util/logging/Logger/logrb/resources/ListBundle_fr.java new file mode 100644 index 000000000..b168bf7ab --- /dev/null +++ b/test/java/util/logging/Logger/logrb/resources/ListBundle_fr.java @@ -0,0 +1,41 @@ +/* + * Copyright (c) 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 resources; + +import java.util.ListResourceBundle; + +/** + * + * @author danielfuchs + */ +public class ListBundle_fr extends ListResourceBundle { + + @Override + protected Object[][] getContents() { + return new Object[][] { + { "dummy", "toto" }, + }; + + } + +} diff --git a/test/java/util/logging/Logger/logrb/resources/PropertyBundle.properties b/test/java/util/logging/Logger/logrb/resources/PropertyBundle.properties new file mode 100644 index 000000000..343c64825 --- /dev/null +++ b/test/java/util/logging/Logger/logrb/resources/PropertyBundle.properties @@ -0,0 +1,24 @@ +# +# Copyright (c) 20013, 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. +# +dummy=foo + diff --git a/test/java/util/logging/Logger/logrb/resources/PropertyBundle_fr.properties b/test/java/util/logging/Logger/logrb/resources/PropertyBundle_fr.properties new file mode 100644 index 000000000..312027104 --- /dev/null +++ b/test/java/util/logging/Logger/logrb/resources/PropertyBundle_fr.properties @@ -0,0 +1,24 @@ +# +# Copyright (c) 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. +# +dummy=toto + diff --git a/test/java/util/logging/Logger/setResourceBundle/TestSetResourceBundle.java b/test/java/util/logging/Logger/setResourceBundle/TestSetResourceBundle.java new file mode 100644 index 000000000..3ba69e7af --- /dev/null +++ b/test/java/util/logging/Logger/setResourceBundle/TestSetResourceBundle.java @@ -0,0 +1,393 @@ +/* + * Copyright (c) 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. + */ +import java.security.AccessControlException; +import java.security.Permission; +import java.security.Permissions; +import java.security.Policy; +import java.security.ProtectionDomain; +import java.util.Locale; +import java.util.Objects; +import java.util.PropertyPermission; +import java.util.ResourceBundle; +import java.util.logging.Handler; +import java.util.logging.Level; +import java.util.logging.LogManager; +import java.util.logging.LogRecord; +import java.util.logging.Logger; +import java.util.logging.LoggingPermission; +import resources.ListBundle; + +/** + * @test + * @bug 8013839 + * @summary tests Logger.setResourceBundle; + * @build TestSetResourceBundle resources.ListBundle resources.ListBundle_fr + * @run main/othervm TestSetResourceBundle UNSECURE + * @run main/othervm TestSetResourceBundle PERMISSION + * @run main/othervm TestSetResourceBundle SECURE + * @author danielfuchs + */ +public class TestSetResourceBundle { + + final static String LIST_BUNDLE_NAME = "resources.ListBundle"; + final static String PROPERTY_BUNDLE_NAME = "resources.PropertyBundle"; + + /** + * A dummy handler class that we can use to check the bundle/bundle name + * that was present in the last LogRecord instance published. + */ + static final class TestHandler extends Handler { + ResourceBundle lastBundle = null; + String lastBundleName = null; + @Override + public void publish(LogRecord record) { + lastBundle = record.getResourceBundle(); + lastBundleName = record.getResourceBundleName(); + } + + @Override + public void flush() { + } + + @Override + public void close() throws SecurityException { + } + } + + /** + * We will test setResourceBundle() in 3 configurations. + * UNSECURE: No security manager. + * SECURE: With the security manager present - and the required + * LoggingPermission("control") granted. + * PERMISSION: With the security manager present - and the required + * LoggingPermission("control") *not* granted. Here we will + * test that the expected security permission is thrown. + */ + public static enum TestCase { + UNSECURE, SECURE, PERMISSION; + public void run(String name) throws Exception { + System.out.println("Running test case: " + name()); + switch (this) { + case UNSECURE: + testUnsecure(name); + break; + case SECURE: + testSecure(name); + break; + case PERMISSION: + testPermission(name); + break; + default: + throw new Error("Unknown test case: "+this); + } + } + public String loggerName(String name) { + return name().toLowerCase(Locale.ROOT) + "." + name; + } + } + + public static void main(String... args) throws Exception { + + Locale defaultLocale = Locale.getDefault(); + + if (args == null || args.length == 0) { + args = new String[] { + TestCase.UNSECURE.name(), + TestCase.SECURE.name() + }; + } + + for (String testName : args) { + TestCase test = TestCase.valueOf(testName); + try { + test.run(test.loggerName("foo.bar")); + } finally { + Locale.setDefault(defaultLocale); + } + } + } + + /** + * Test without security manager. + * @param loggerName The logger to use. + * @throws Exception if the test fails. + */ + public static void testUnsecure(String loggerName) throws Exception { + if (System.getSecurityManager() != null) { + throw new Error("Security manager is set"); + } + test(loggerName); + } + + /** + * Test with security manager. + * @param loggerName The logger to use. + * @throws Exception if the test fails. + */ + public static void testSecure(String loggerName) throws Exception { + if (System.getSecurityManager() != null) { + throw new Error("Security manager is already set"); + } + Policy.setPolicy(new SimplePolicy(TestCase.SECURE)); + System.setSecurityManager(new SecurityManager()); + test(loggerName); + } + + /** + * Test the LoggingPermission("control") is required. + * @param loggerName The logger to use. + */ + public static void testPermission(String loggerName) { + if (System.getSecurityManager() != null) { + throw new Error("Security manager is already set"); + } + Policy.setPolicy(new SimplePolicy(TestCase.PERMISSION)); + System.setSecurityManager(new SecurityManager()); + final ResourceBundle bundle = ResourceBundle.getBundle(LIST_BUNDLE_NAME); + Logger foobar = Logger.getLogger(loggerName); + try { + foobar.setResourceBundle(bundle); + throw new RuntimeException("Permission not checked!"); + } catch (AccessControlException x) { + if (x.getPermission() instanceof LoggingPermission) { + if ("control".equals(x.getPermission().getName())) { + System.out.println("Got expected exception: " + x); + return; + } + } + throw new RuntimeException("Unexpected exception: "+x, x); + } + + } + + static String getBaseName(ResourceBundle bundle) { + return bundle == null ? null : bundle.getBaseBundleName(); + } + + public static void test(String loggerName) throws Exception { + + final ResourceBundle bundle = ResourceBundle.getBundle(LIST_BUNDLE_NAME); + Logger foobar = Logger.getLogger(loggerName); + + // Checks that IAE is thrown if the bundle has a null base name. + try { + foobar.setResourceBundle(new ListBundle()); + throw new RuntimeException("Expected exception not raised!"); + } catch (IllegalArgumentException x) { + System.out.println("Got expected exception: " + x); + } + + // Verify that resource bundle was not set. + if (foobar.getResourceBundle() != null) { + throw new RuntimeException("Unexpected bundle: " + + foobar.getResourceBundle()); + } + if (foobar.getResourceBundleName() != null) { + throw new RuntimeException("Unexpected bundle: " + + foobar.getResourceBundleName()); + } + + // Set acceptable resource bundle on logger. + foobar.setResourceBundle(bundle); + + // check that the bundle has been set correctly + if (bundle != foobar.getResourceBundle()) { + throw new RuntimeException("Unexpected bundle: " + + foobar.getResourceBundle()); + } + if (!Objects.equals(getBaseName(bundle), foobar.getResourceBundleName())) { + throw new RuntimeException("Unexpected bundle name: " + + foobar.getResourceBundleName()); + } + + // Check that we can replace the bundle with a bundle of the same name. + final ResourceBundle bundle_fr = + ResourceBundle.getBundle(LIST_BUNDLE_NAME, Locale.FRENCH); + foobar.setResourceBundle(bundle_fr); + + if (bundle_fr != foobar.getResourceBundle()) { + throw new RuntimeException("Unexpected bundle: " + + foobar.getResourceBundle()); + } + if (!Objects.equals(getBaseName(bundle_fr), foobar.getResourceBundleName())) { + throw new RuntimeException("Unexpected bundle name: " + + foobar.getResourceBundleName()); + } + + // Create a child logger + Logger foobaz = Logger.getLogger(loggerName + ".baz"); + + // Check that the child logger does not have a bundle set locally + if (foobaz.getResourceBundle() != null) { + throw new RuntimeException("Unexpected bundle: " + + foobar.getResourceBundle()); + } + if (foobaz.getResourceBundleName() != null) { + throw new RuntimeException("Unexpected bundle: " + + foobar.getResourceBundleName()); + } + + + // Add a handler on the child logger. + final TestHandler handler = new TestHandler(); + foobaz.addHandler(handler); + + // log a message on the child logger + foobaz.severe("dummy"); + + // checks that the message has been logged with the bundle + // inherited from the parent logger + if (!LIST_BUNDLE_NAME.equals(handler.lastBundleName)) { + throw new RuntimeException("Unexpected bundle name: " + + handler.lastBundleName); + } + if (!bundle_fr.equals(handler.lastBundle)) { + throw new RuntimeException("Unexpected bundle: " + + handler.lastBundle); + } + + // Check that we can get set a bundle on the child logger + // using Logger.getLogger. + foobaz = Logger.getLogger(loggerName + ".baz", PROPERTY_BUNDLE_NAME); + + // check that the child logger has the correct bundle. + // it should no longer inherit it from its parent. + if (!PROPERTY_BUNDLE_NAME.equals(foobaz.getResourceBundleName())) { + throw new RuntimeException("Unexpected bundle name: " + + foobaz.getResourceBundleName()); + } + if (!PROPERTY_BUNDLE_NAME.equals(foobaz.getResourceBundle().getBaseBundleName())) { + throw new RuntimeException("Unexpected bundle name: " + + foobaz.getResourceBundle().getBaseBundleName()); + } + + // log a message on the child logger + foobaz.severe("dummy"); + + // check that the last published log record has the appropriate + // bundle. + if (!PROPERTY_BUNDLE_NAME.equals(handler.lastBundleName)) { + throw new RuntimeException("Unexpected bundle name: " + + handler.lastBundleName); + } + if (foobaz.getResourceBundle() != handler.lastBundle) { + throw new RuntimeException("Unexpected bundle: " + + handler.lastBundle); + } + + // try to set a bundle that has a different name, and checks that + // it fails in IAE. + try { + foobaz.setResourceBundle(bundle_fr); + throw new RuntimeException("Expected exception not raised!"); + } catch (IllegalArgumentException x) { + System.out.println("Got expected exception: " + x); + } + + // Test with a subclass of logger which overrides + // getResourceBundle() and getResourceBundleName() + Logger customLogger = new Logger(foobar.getName()+".bie", null) { + @Override + public ResourceBundle getResourceBundle() { + return bundle_fr; + } + + @Override + public String getResourceBundleName() { + return PROPERTY_BUNDLE_NAME; + } + }; + + final TestHandler handler2 = new TestHandler(); + customLogger.addHandler(handler2); + customLogger.setLevel(Level.FINE); + LogManager.getLogManager().addLogger(customLogger); + + Logger l = Logger.getLogger(customLogger.getName()); + if (l != customLogger) { + throw new RuntimeException("Wrong logger: " + l); + } + + // log on the custom logger. + customLogger.fine("dummy"); + + // check that the log record had the correct bundle. + if (! PROPERTY_BUNDLE_NAME.equals(handler2.lastBundleName)) { + throw new RuntimeException("Unexpected bundle name: " + + handler2.lastBundleName); + } + if (! PROPERTY_BUNDLE_NAME.equals(customLogger.getResourceBundleName())) { + throw new RuntimeException("Unexpected bundle name: " + + customLogger.getResourceBundleName()); + } + if (bundle_fr != handler2.lastBundle) { + throw new RuntimeException("Unexpected bundle: " + + handler2.lastBundle); + } + if (bundle_fr != customLogger.getResourceBundle()) { + throw new RuntimeException("Unexpected bundle: " + + customLogger.getResourceBundle()); + } + + // Do the same thing again with a child of the custom logger. + Logger biebar = Logger.getLogger(customLogger.getName() + ".bar"); + biebar.fine("dummy"); + + // because getResourceBundleName() is called on parent logger + // we will have handler2.lastBundleName = PROPERTY_BUNDLE_NAME + if (!PROPERTY_BUNDLE_NAME.equals(handler2.lastBundleName)) { + throw new RuntimeException("Unexpected bundle name: " + + handler2.lastBundleName); + } + // because getResourceBundle() is not called on parent logger + // we will have getBaseName(handler2.lastBundle) = PROPERTY_BUNDLE_NAME + // and not handler2.lastBundle = bundle_fr + if (handler2.lastBundle == null) { + throw new RuntimeException("Unexpected bundle: " + + handler2.lastBundle); + } + if (!PROPERTY_BUNDLE_NAME.equals(getBaseName(handler2.lastBundle))) { + throw new RuntimeException("Unexpected bundle name: " + + getBaseName(handler2.lastBundle)); + } + } + + public static class SimplePolicy extends Policy { + + final Permissions permissions; + public SimplePolicy(TestCase test) { + permissions = new Permissions(); + if (test != TestCase.PERMISSION) { + permissions.add(new LoggingPermission("control", null)); + } + // required for calling Locale.setDefault in the test. + permissions.add(new PropertyPermission("user.language", "write")); + } + + @Override + public boolean implies(ProtectionDomain domain, Permission permission) { + return permissions.implies(permission); + } + } + +} diff --git a/test/java/util/logging/Logger/setResourceBundle/resources/ListBundle.java b/test/java/util/logging/Logger/setResourceBundle/resources/ListBundle.java new file mode 100644 index 000000000..121db2914 --- /dev/null +++ b/test/java/util/logging/Logger/setResourceBundle/resources/ListBundle.java @@ -0,0 +1,41 @@ +/* + * Copyright (c) 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 resources; + +import java.util.ListResourceBundle; + +/** + * + * @author danielfuchs + */ +public class ListBundle extends ListResourceBundle { + + @Override + protected Object[][] getContents() { + return new Object[][] { + { "dummy", "foo" }, + }; + + } + +} diff --git a/test/java/util/logging/Logger/setResourceBundle/resources/ListBundle_fr.java b/test/java/util/logging/Logger/setResourceBundle/resources/ListBundle_fr.java new file mode 100644 index 000000000..b168bf7ab --- /dev/null +++ b/test/java/util/logging/Logger/setResourceBundle/resources/ListBundle_fr.java @@ -0,0 +1,41 @@ +/* + * Copyright (c) 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 resources; + +import java.util.ListResourceBundle; + +/** + * + * @author danielfuchs + */ +public class ListBundle_fr extends ListResourceBundle { + + @Override + protected Object[][] getContents() { + return new Object[][] { + { "dummy", "toto" }, + }; + + } + +} diff --git a/test/java/util/logging/Logger/setResourceBundle/resources/PropertyBundle.properties b/test/java/util/logging/Logger/setResourceBundle/resources/PropertyBundle.properties new file mode 100644 index 000000000..343c64825 --- /dev/null +++ b/test/java/util/logging/Logger/setResourceBundle/resources/PropertyBundle.properties @@ -0,0 +1,24 @@ +# +# Copyright (c) 20013, 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. +# +dummy=foo + diff --git a/test/java/util/logging/Logger/setResourceBundle/resources/PropertyBundle_fr.properties b/test/java/util/logging/Logger/setResourceBundle/resources/PropertyBundle_fr.properties new file mode 100644 index 000000000..312027104 --- /dev/null +++ b/test/java/util/logging/Logger/setResourceBundle/resources/PropertyBundle_fr.properties @@ -0,0 +1,24 @@ +# +# Copyright (c) 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. +# +dummy=toto + -- GitLab