From 599a23703d0ade30238b109ecc523b1e7ba05110 Mon Sep 17 00:00:00 2001 From: jgish Date: Thu, 25 Oct 2012 15:04:09 -0700 Subject: [PATCH] 7159567: inconsistent configuration of MemoryHandler Reviewed-by: mchung, alanb --- .../java/util/logging/ConsoleHandler.java | 35 ++-- .../java/util/logging/FileHandler.java | 61 ++++--- .../java/util/logging/MemoryHandler.java | 65 +++++--- .../java/util/logging/SocketHandler.java | 42 +++-- .../java/util/logging/StreamHandler.java | 36 ++-- test/java/util/logging/MemoryHandlerTest.java | 156 ++++++++++++++++++ .../java/util/logging/MemoryHandlerTest.props | 9 + 7 files changed, 321 insertions(+), 83 deletions(-) create mode 100644 test/java/util/logging/MemoryHandlerTest.java create mode 100644 test/java/util/logging/MemoryHandlerTest.props diff --git a/src/share/classes/java/util/logging/ConsoleHandler.java b/src/share/classes/java/util/logging/ConsoleHandler.java index 8cbff2001..e0e70a5e6 100644 --- a/src/share/classes/java/util/logging/ConsoleHandler.java +++ b/src/share/classes/java/util/logging/ConsoleHandler.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2003, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 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 @@ -35,26 +35,39 @@ import java.net.*; *

* Configuration: * By default each ConsoleHandler is initialized using the following - * LogManager configuration properties. If properties are not defined + * LogManager configuration properties where + * refers to the fully-qualified class name of the handler. + * If properties are not defined * (or have invalid values) then the specified default values are used. *

+ *

+ * For example, the properties for {@code ConsoleHandler} would be: + *

+ *

+ * For a custom handler, e.g. com.foo.MyHandler, the properties would be: + *

*

* @since 1.4 */ - public class ConsoleHandler extends StreamHandler { // Private method to configure a ConsoleHandler from LogManager // properties and/or default values as specified in the class diff --git a/src/share/classes/java/util/logging/FileHandler.java b/src/share/classes/java/util/logging/FileHandler.java index fb3b67c4d..4602fb565 100644 --- a/src/share/classes/java/util/logging/FileHandler.java +++ b/src/share/classes/java/util/logging/FileHandler.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 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 @@ -48,45 +48,58 @@ import java.security.*; *

* Configuration: * By default each FileHandler is initialized using the following - * LogManager configuration properties. If properties are not defined + * LogManager configuration properties where <handler-name> + * refers to the fully-qualified class name of the handler. + * If properties are not defined * (or have invalid values) then the specified default values are used. *

*

+ * For example, the properties for {@code FileHandler} would be: + *

+ *

+ * For a custom handler, e.g. com.foo.MyHandler, the properties would be: + *

*

* A pattern consists of a string that includes the following special * components that will be replaced at runtime: *

* If no "%g" field has been specified and the file count is greater * than one, then the generation number will be added to the end of diff --git a/src/share/classes/java/util/logging/MemoryHandler.java b/src/share/classes/java/util/logging/MemoryHandler.java index 2c297301d..df6382eb2 100644 --- a/src/share/classes/java/util/logging/MemoryHandler.java +++ b/src/share/classes/java/util/logging/MemoryHandler.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2004, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 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 @@ -39,36 +39,50 @@ package java.util.logging; * *

* Configuration: * By default each MemoryHandler is initialized using the following - * LogManager configuration properties. If properties are not defined + * LogManager configuration properties where <handler-name> + * refers to the fully-qualified class name of the handler. + * If properties are not defined * (or have invalid values) then the specified default values are used. * If no default value is defined then a RuntimeException is thrown. *

- * + *

+ * For example, the properties for {@code MemoryHandler} would be: + *

+ *

+ * For a custom handler, e.g. com.foo.MyHandler, the properties would be: + *

+ *

* @since 1.4 */ @@ -80,7 +94,7 @@ public class MemoryHandler extends Handler { private LogRecord buffer[]; int start, count; - // Private method to configure a ConsoleHandler from LogManager + // Private method to configure a MemoryHandler from LogManager // properties and/or default values as specified in the class // javadoc. private void configure() { @@ -106,14 +120,19 @@ public class MemoryHandler extends Handler { configure(); sealed = true; - String name = "???"; + LogManager manager = LogManager.getLogManager(); + String handlerName = getClass().getName(); + String targetName = manager.getProperty(handlerName+".target"); + if (targetName == null) { + throw new RuntimeException("The handler " + handlerName + + " does not specify a target"); + } + Class clz; try { - LogManager manager = LogManager.getLogManager(); - name = manager.getProperty("java.util.logging.MemoryHandler.target"); - Class clz = ClassLoader.getSystemClassLoader().loadClass(name); + clz = ClassLoader.getSystemClassLoader().loadClass(targetName); target = (Handler) clz.newInstance(); - } catch (Exception ex) { - throw new RuntimeException("MemoryHandler can't load handler \"" + name + "\"" , ex); + } catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) { + throw new RuntimeException("MemoryHandler can't load handler target \"" + targetName + "\"" , e); } init(); } diff --git a/src/share/classes/java/util/logging/SocketHandler.java b/src/share/classes/java/util/logging/SocketHandler.java index f2e796d61..d7f2f31ad 100644 --- a/src/share/classes/java/util/logging/SocketHandler.java +++ b/src/share/classes/java/util/logging/SocketHandler.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2003, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 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 @@ -37,25 +37,39 @@ import java.net.*; *

* Configuration: * By default each SocketHandler is initialized using the following - * LogManager configuration properties. If properties are not defined + * LogManager configuration properties where <handler-name> + * refers to the fully-qualified class name of the handler. + * If properties are not defined * (or have invalid values) then the specified default values are used. *

+ *

+ * For example, the properties for {@code SocketHandler} would be: + *

+ *

+ * For a custom handler, e.g. com.foo.MyHandler, the properties would be: + *

*

* The output IO stream is buffered, but is flushed after each diff --git a/src/share/classes/java/util/logging/StreamHandler.java b/src/share/classes/java/util/logging/StreamHandler.java index 9ed9e57b7..a8b74c422 100644 --- a/src/share/classes/java/util/logging/StreamHandler.java +++ b/src/share/classes/java/util/logging/StreamHandler.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 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 @@ -38,23 +38,37 @@ import java.io.*; *

* Configuration: * By default each StreamHandler is initialized using the following - * LogManager configuration properties. If properties are not defined + * LogManager configuration properties where <handler-name> + * refers to the fully-qualified class name of the handler. + * If properties are not defined * (or have invalid values) then the specified default values are used. *

- * + *

+ * For example, the properties for {@code StreamHandler} would be: + *

+ *

+ * For a custom handler, e.g. com.foo.MyHandler, the properties would be: + *

+ *

* @since 1.4 */ diff --git a/test/java/util/logging/MemoryHandlerTest.java b/test/java/util/logging/MemoryHandlerTest.java new file mode 100644 index 000000000..026e57185 --- /dev/null +++ b/test/java/util/logging/MemoryHandlerTest.java @@ -0,0 +1,156 @@ +/* + * 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 7159567 + * @summary Test of configuring a MemoryHandler sub-class handler target via logging.properties + * @run main/othervm MemoryHandlerTest + */ +import java.io.File; +import java.io.IOException; +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.MemoryHandler; + +public class MemoryHandlerTest { + + static final String CFG_FILE_PROP = "java.util.logging.config.file"; + static final String LM_PROP_FNAME = "MemoryHandlerTest.props"; + static Logger logger; + + public static void main(String... args) throws IOException { + // load logging.propertes for the test + String tstSrc = System.getProperty("test.src", "."); + File fname = new File(tstSrc, LM_PROP_FNAME); + String prop = fname.getCanonicalPath(); + System.setProperty(CFG_FILE_PROP, prop); + LogManager logMgr = LogManager.getLogManager(); + // create a logger + logger = Logger.getLogger(MemoryHandlerTest.class.getName()); + // don't have parent handlers get log messages + logger.setUseParentHandlers(false); + // + // Test 1,2: create a CustomMemoryHandler which in the config has + // specified a target of CustomTargetHandler. (1) Make sure that it + // is created and (2) that the target handler is loaded. + // + CustomMemoryHandler cmh = new CustomMemoryHandler(); + try { + logger.addHandler(cmh); + } catch (RuntimeException rte) { + throw new RuntimeException( + "Test Failed: did not load java.util.logging.ConsoleHandler as expected", + rte); + } + // if we get here and our config has been processed properly, then we + // should have loaded our target handler + if (CustomTargetHandler.numLoaded !=1) { + throw new RuntimeException( + "Test failed: did not load CustomTargetHandler as expected"); + } + // + // Test 3: try to add a handler with no target. This should fail with + // an exception + CustomMemoryHandlerNoTarget cmhnt = null; + try { + cmhnt = new CustomMemoryHandlerNoTarget(); + } catch (RuntimeException re) { + // expected -- no target specified + System.out.println("Info: " + re.getMessage() + " as expected."); + } + if (cmhnt != null) { + throw new RuntimeException( + "Test Failed: erroneously loaded CustomMemoryHandlerNoTarget"); + } + + // Test 4: log a message and check that the target handler is actually used + logger.log(Level.WARNING, "Unused"); + if (CustomTargetHandler.numPublished != 1) { + throw new RuntimeException("Test failed: CustomTargetHandler was not used"); + } + + // Test 5: make sure that SimpleTargetHandler hasn't been erroneously called + if (SimpleTargetHandler.numPublished != 0) { + throw new RuntimeException("Test failed: SimpleTargetHandler has been used"); + } + + // Test 6: try using SimpleTargetHanlder via standard MemoryHandler + // (which has target set to SimpleTargetHandler) + MemoryHandler mh = new MemoryHandler(); + mh.publish(new LogRecord(Level.INFO, "Unused msg to MemoryHandler")); + // see if it made it to the SimpleTargetHandler + if (SimpleTargetHandler.numPublished != 1) { + throw new RuntimeException("Test failed: SimpleTargetHandler was not used"); + } + } + + public static class CustomMemoryHandler extends MemoryHandler { + } + + public static class CustomMemoryHandlerNoTarget extends MemoryHandler { + } + + public static class CustomTargetHandler extends Handler { + + public static int numPublished; + public static int numLoaded; + + public CustomTargetHandler() { + numLoaded++; + } + + @Override + public void publish(LogRecord unused) { + numPublished++; + } + + @Override + public void flush() { + } + + @Override + public void close() throws SecurityException { + } + } + + public static class SimpleTargetHandler extends Handler { + public static int numPublished; + + @Override + public void publish(LogRecord unused) { + numPublished++; + } + + @Override + public void flush() { + } + + @Override + public void close() throws SecurityException { + } + } +} diff --git a/test/java/util/logging/MemoryHandlerTest.props b/test/java/util/logging/MemoryHandlerTest.props new file mode 100644 index 000000000..4860569eb --- /dev/null +++ b/test/java/util/logging/MemoryHandlerTest.props @@ -0,0 +1,9 @@ +.level= INFO +MemoryHandlerTest$CustomMemoryHandler.push=WARNING +MemoryHandlerTest$CustomMemoryHandlerNoTarget.push=WARNING +MemoryHandlerTest$CustomMemoryHandler.target=MemoryHandlerTest$CustomTargetHandler +handlers=java.util.logging.ConsoleHandler,MemoryHandlerTest$CustomMemoryHandler,MemoryHandlerTest$CustomMemoryHandlerNoTarget +java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter +java.util.logging.ConsoleHandler.level = INFO +java.util.logging.MemoryHandler.target=MemoryHandlerTest$SimpleTargetHandler +java.util.logging.MemoryHandler.push = INFO -- GitLab