8026863: regression in anonymous Logger.setParent method
Summary: restore behaviour of setParent in anonymous logger and clarifies the spec with respect to security permissions.
Reviewed-by: mchung, prr
--- a/jdk/src/share/classes/java/util/logging/Logger.java Fri Oct 25 14:53:34 2013 -0700
+++ b/jdk/src/share/classes/java/util/logging/Logger.java Mon Oct 28 10:52:07 2013 +0100
@@ -555,7 +555,9 @@
* Even although the new logger is anonymous, it is configured
* to have the root logger ("") as its parent. This means that
* by default it inherits its effective level and handlers
- * from the root logger.
+ * from the root logger. Changing its parent via the
+ * {@link #setParent(java.util.logging.Logger) setParent} method
+ * will still require the security permission specified by that method.
* <p>
*
* @return a newly created private Logger
@@ -579,7 +581,9 @@
* Even although the new logger is anonymous, it is configured
* to have the root logger ("") as its parent. This means that
* by default it inherits its effective level and handlers
- * from the root logger.
+ * from the root logger. Changing its parent via the
+ * {@link #setParent(java.util.logging.Logger) setParent} method
+ * will still require the security permission specified by that method.
* <p>
* @param resourceBundleName name of ResourceBundle to be used for localizing
* messages for this logger.
@@ -648,8 +652,9 @@
* be published.
*
* @param newFilter a filter object (may be null)
- * @exception SecurityException if a security manager exists and if
- * the caller does not have LoggingPermission("control").
+ * @throws SecurityException if a security manager exists,
+ * this logger is not anonymous, and the caller
+ * does not have LoggingPermission("control").
*/
public void setFilter(Filter newFilter) throws SecurityException {
checkPermission();
@@ -1629,8 +1634,9 @@
* (non-null) level value.
*
* @param newLevel the new value for the log level (may be null)
- * @exception SecurityException if a security manager exists and if
- * the caller does not have LoggingPermission("control").
+ * @throws SecurityException if a security manager exists,
+ * this logger is not anonymous, and the caller
+ * does not have LoggingPermission("control").
*/
public void setLevel(Level newLevel) throws SecurityException {
checkPermission();
@@ -1686,8 +1692,9 @@
* that essentially act as default handlers for all loggers.
*
* @param handler a logging Handler
- * @exception SecurityException if a security manager exists and if
- * the caller does not have LoggingPermission("control").
+ * @throws SecurityException if a security manager exists,
+ * this logger is not anonymous, and the caller
+ * does not have LoggingPermission("control").
*/
public void addHandler(Handler handler) throws SecurityException {
// Check for null handler
@@ -1702,8 +1709,9 @@
* Returns silently if the given Handler is not found or is null
*
* @param handler a logging Handler
- * @exception SecurityException if a security manager exists and if
- * the caller does not have LoggingPermission("control").
+ * @throws SecurityException if a security manager exists,
+ * this logger is not anonymous, and the caller
+ * does not have LoggingPermission("control").
*/
public void removeHandler(Handler handler) throws SecurityException {
checkPermission();
@@ -1730,8 +1738,9 @@
*
* @param useParentHandlers true if output is to be sent to the
* logger's parent.
- * @exception SecurityException if a security manager exists and if
- * the caller does not have LoggingPermission("control").
+ * @throws SecurityException if a security manager exists,
+ * this logger is not anonymous, and the caller
+ * does not have LoggingPermission("control").
*/
public void setUseParentHandlers(boolean useParentHandlers) {
checkPermission();
@@ -1894,8 +1903,9 @@
* {@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").
+ * @throws SecurityException if a security manager exists,
+ * this logger is not anonymous, and the caller
+ * does not have LoggingPermission("control").
* @since 1.8
*/
public void setResourceBundle(ResourceBundle bundle) {
@@ -1952,14 +1962,20 @@
* It should not be called from application code.
* <p>
* @param parent the new parent logger
- * @exception SecurityException if a security manager exists and if
- * the caller does not have LoggingPermission("control").
+ * @throws SecurityException if a security manager exists and if
+ * the caller does not have LoggingPermission("control").
*/
public void setParent(Logger parent) {
if (parent == null) {
throw new NullPointerException();
}
- checkPermission();
+
+ // check permission for all loggers, including anonymous loggers
+ if (manager == null) {
+ manager = LogManager.getLogManager();
+ }
+ manager.checkPermission();
+
doSetParent(parent);
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/logging/AnonymousLogger/TestAnonymousLogger.java Mon Oct 28 10:52:07 2013 +0100
@@ -0,0 +1,133 @@
+/*
+ * 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.Collections;
+import java.util.Enumeration;
+import java.util.LinkedHashSet;
+import java.util.ResourceBundle;
+import java.util.Set;
+import java.util.logging.Filter;
+import java.util.logging.Handler;
+import java.util.logging.Level;
+import java.util.logging.LogRecord;
+import java.util.logging.Logger;
+import java.util.logging.SimpleFormatter;
+
+/**
+ * @test
+ * @bug 8026863
+ * @summary checks that anonymous logger setters work as expected when a
+ * security manager is set, and checks that getters return expected
+ * values.
+ * @run main/othervm TestAnonymousLogger
+ */
+public class TestAnonymousLogger {
+
+ final public static class TestHandler extends Handler {
+ @Override
+ public void publish(LogRecord record) {
+ System.out.println(new SimpleFormatter().format(record));
+ }
+ @Override
+ public void flush() {
+ System.out.flush();
+ }
+ @Override
+ public void close() {
+ flush();
+ }
+ }
+
+ final public static class TestFilter implements Filter {
+ @Override
+ public boolean isLoggable(LogRecord record) {
+ return true;
+ }
+ }
+
+ final public static class TestBundle extends ResourceBundle {
+ Set<String> keys = Collections.synchronizedSet(new LinkedHashSet<>());
+ @Override
+ protected Object handleGetObject(String key) {
+ keys.add(key);
+ return "[LOCALIZED] "+key;
+ }
+ @Override
+ public Enumeration<String> getKeys() {
+ return Collections.enumeration(keys);
+ }
+ }
+
+ public static void main(String[] args) {
+ System.setSecurityManager(new SecurityManager());
+ Logger anonymous = Logger.getAnonymousLogger();
+
+ final TestHandler handler = new TestHandler();
+ final TestFilter filter = new TestFilter();
+ final ResourceBundle bundle = ResourceBundle.getBundle(TestBundle.class.getName());
+ anonymous.setLevel(Level.FINEST);
+ anonymous.addHandler(handler);
+ anonymous.setFilter(filter);
+ anonymous.setUseParentHandlers(true);
+ anonymous.setResourceBundle(bundle);
+
+ if (anonymous.getLevel() != Level.FINEST) {
+ throw new RuntimeException("Unexpected level: " + anonymous.getLevel());
+ } else {
+ System.out.println("Got expected level: " + anonymous.getLevel());
+ }
+ if (!Arrays.asList(anonymous.getHandlers()).contains(handler)) {
+ throw new RuntimeException("Expected handler not found in: "
+ + Arrays.asList(anonymous.getHandlers()));
+ } else {
+ System.out.println("Got expected handler in: " + Arrays.asList(anonymous.getHandlers()));
+ }
+ if (anonymous.getFilter() != filter) {
+ throw new RuntimeException("Unexpected filter: " + anonymous.getFilter());
+ } else {
+ System.out.println("Got expected filter: " + anonymous.getFilter());
+ }
+ if (!anonymous.getUseParentHandlers()) {
+ throw new RuntimeException("Unexpected flag: " + anonymous.getUseParentHandlers());
+ } else {
+ System.out.println("Got expected flag: " + anonymous.getUseParentHandlers());
+ }
+ if (anonymous.getResourceBundle() != bundle) {
+ throw new RuntimeException("Unexpected bundle: " + anonymous.getResourceBundle());
+ } else {
+ System.out.println("Got expected bundle: " + anonymous.getResourceBundle());
+ }
+ try {
+ anonymous.setParent(Logger.getLogger("foo.bar"));
+ throw new RuntimeException("Expected SecurityException not raised!");
+ } catch (SecurityException x) {
+ System.out.println("Got expected exception: " + x);
+ }
+ if (anonymous.getParent() != Logger.getLogger("")) {
+ throw new RuntimeException("Unexpected parent: " + anonymous.getParent());
+ } else {
+ System.out.println("Got expected parent: " + anonymous.getParent());
+ }
+ }
+
+}