--- /dev/null 2014-09-11 18:03:58.000000000 +0200 +++ new/test/java/util/logging/TestConfigurationListeners.java 2014-09-11 18:03:57.000000000 +0200 @@ -0,0 +1,398 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +import java.io.ByteArrayInputStream; +import java.io.FilePermission; +import java.io.IOException; +import java.security.AccessControlException; +import java.security.CodeSource; +import java.security.Permission; +import java.security.PermissionCollection; +import java.security.Permissions; +import java.security.Policy; +import java.security.ProtectionDomain; +import java.util.Enumeration; +import java.util.PropertyPermission; +import java.util.concurrent.atomic.AtomicLong; +import java.util.logging.LogManager; +import java.util.logging.LoggingPermission; + +/** + * @test + * @bug 8043306 + * @summary tests LogManager.addConfigurationListener and + * LogManager.removeConfigurationListener; + * @build TestConfigurationListeners + * @run main/othervm TestConfigurationListeners UNSECURE + * @run main/othervm TestConfigurationListeners PERMISSION + * @run main/othervm TestConfigurationListeners SECURE + * @author danielfuchs + */ +public class TestConfigurationListeners { + + /** + * We will test add and remove ConfigurationListeners 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; + } + } + + public static void main(String... args) throws Exception { + + + if (args == null || args.length == 0) { + args = new String[] { + TestCase.UNSECURE.name(), + TestCase.SECURE.name(), + }; + } + + for (String testName : args) { + TestCase test = TestCase.valueOf(testName); + test.run(test.loggerName("foo.bar")); + } + } + + /** + * 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) { + TestConfigurationListener run = new TestConfigurationListener( + TestCase.PERMISSION.toString()); + if (System.getSecurityManager() != null) { + throw new Error("Security manager is already set"); + } + Policy.setPolicy(new SimplePolicy(TestCase.PERMISSION)); + System.setSecurityManager(new SecurityManager()); + + try { + run = new TestConfigurationListener("[Should Be Denied]"); + throw new RuntimeException("ConfigurationListener constructor: Permission not checked!"); + } catch (AccessControlException x) { + boolean ok = false; + if (x.getPermission() instanceof LoggingPermission) { + if ("control".equals(x.getPermission().getName())) { + System.out.println("ConfigurationListener constructor: Got expected exception: " + x); + ok = true; + } + } + if (!ok) { + throw new RuntimeException("ConfigurationListener constructor: Unexpected exception: "+x, x); + } + } + try { + LogManager.getLogManager().addConfigurationListener(run); + throw new RuntimeException("addConfigurationListener: Permission not checked!"); + } catch (AccessControlException x) { + boolean ok = false; + if (x.getPermission() instanceof LoggingPermission) { + if ("control".equals(x.getPermission().getName())) { + System.out.println("addConfigurationListener: Got expected exception: " + x); + ok = true; + } + } + if (!ok) { + throw new RuntimeException("addConfigurationListener: Unexpected exception: "+x, x); + } + } + + try { + LogManager.getLogManager().removeConfigurationListener(run); + throw new RuntimeException("removeConfigurationListener: Permission not checked!"); + } catch (AccessControlException x) { + boolean ok = false; + if (x.getPermission() instanceof LoggingPermission) { + if ("control".equals(x.getPermission().getName())) { + System.out.println("removeConfigurationListener: Got expected exception: " + x); + ok = true; + } + } + if (!ok) { + throw new RuntimeException("removeConfigurationListener: Unexpected exception: "+x, x); + } + } + try { + LogManager.getLogManager().addConfigurationListener(null); + throw new RuntimeException( + "addConfigurationListener(null): Expected NPE not thrown."); + } catch (NullPointerException npe) { + System.out.println("Got expected NPE: "+npe); + } + + try { + LogManager.getLogManager().removeConfigurationListener(null); + throw new RuntimeException( + "removeConfigurationListener(null): Expected NPE not thrown."); + } catch (NullPointerException npe) { + System.out.println("Got expected NPE: "+npe); + } + + + } + + + static class TestConfigurationListener implements Runnable { + final AtomicLong count = new AtomicLong(0); + final String name; + TestConfigurationListener(String name) { + this.name = name; + } + @Override + public void run() { + final long times = count.incrementAndGet(); + System.out.println("Configured \"" + name + "\": " + times); + } + } + + private static void expect(TestConfigurationListener listener, long value) { + final long got = listener.count.longValue(); + if (got != value) { + throw new RuntimeException(listener.name + " expected " + value +", got " + got); + } + + } + + public interface ThrowingConsumer { + public void accept(T t) throws I; + } + + public static class ReadConfiguration implements ThrowingConsumer { + + @Override + public void accept(LogManager t) throws IOException { + t.readConfiguration(); + } + + } + + public static void test(String loggerName) throws Exception { + System.out.println("Starting test for " + loggerName); + test("m.readConfiguration()", (m) -> m.readConfiguration()); + test("m.readConfiguration(new ByteArrayInputStream(new byte[0]))", + (m) -> m.readConfiguration(new ByteArrayInputStream(new byte[0]))); + System.out.println("Test passed for " + loggerName); + } + + public static void test(String testName, + ThrowingConsumer readConfiguration) throws Exception { + + + System.out.println("\nBEGIN " + testName); + LogManager m = LogManager.getLogManager(); + + final TestConfigurationListener l1 = new TestConfigurationListener("l#1"); + final TestConfigurationListener l2 = new TestConfigurationListener("l#2"); + m.addConfigurationListener(l1); + m.addConfigurationListener(l2); + expect(l1, 0); + expect(l2, 0); + + readConfiguration.accept(m); + expect(l1, 1); + expect(l2, 1); + m.addConfigurationListener(l1); + expect(l1, 1); + expect(l2, 1); + readConfiguration.accept(m); + expect(l1, 2); + expect(l2, 2); + m.removeConfigurationListener(l1); + expect(l1, 2); + expect(l2, 2); + readConfiguration.accept(m); + expect(l1, 2); + expect(l2, 3); + m.removeConfigurationListener(l1); + expect(l1, 2); + expect(l2, 3); + readConfiguration.accept(m); + expect(l1, 2); + expect(l2, 4); + m.removeConfigurationListener(l2); + expect(l1, 2); + expect(l2, 4); + readConfiguration.accept(m); + expect(l1, 2); + expect(l2, 4); + + // l1 and l2 should no longer be present: this should not fail... + m.removeConfigurationListener(l1); + m.removeConfigurationListener(l1); + m.removeConfigurationListener(l2); + m.removeConfigurationListener(l2); + expect(l1, 2); + expect(l2, 4); + + readConfiguration.accept(m); + expect(l1, 2); + expect(l2, 4); + + // add back l1 and l2 + m.addConfigurationListener(l1); + m.addConfigurationListener(l2); + expect(l1, 2); + expect(l2, 4); + + readConfiguration.accept(m); + expect(l1, 3); + expect(l2, 5); + + m.removeConfigurationListener(l1); + m.removeConfigurationListener(l2); + expect(l1, 3); + expect(l2, 5); + + readConfiguration.accept(m); + expect(l1, 3); + expect(l2, 5); + + try { + m.addConfigurationListener(null); + throw new RuntimeException( + "addConfigurationListener(null): Expected NPE not thrown."); + } catch (NullPointerException npe) { + System.out.println("Got expected NPE: "+npe); + } + + try { + m.removeConfigurationListener(null); + throw new RuntimeException( + "removeConfigurationListener(null): Expected NPE not thrown."); + } catch (NullPointerException npe) { + System.out.println("Got expected NPE: "+npe); + } + + System.out.println("END " + testName+"\n"); + + } + + + final static class PermissionsBuilder { + final Permissions perms; + public PermissionsBuilder() { + this(new Permissions()); + } + public PermissionsBuilder(Permissions perms) { + this.perms = perms; + } + public PermissionsBuilder add(Permission p) { + perms.add(p); + return this; + } + public PermissionsBuilder addAll(PermissionCollection col) { + if (col != null) { + for (Enumeration e = col.elements(); e.hasMoreElements(); ) { + perms.add(e.nextElement()); + } + } + return this; + } + public Permissions toPermissions() { + final PermissionsBuilder builder = new PermissionsBuilder(); + builder.addAll(perms); + return builder.perms; + } + } + + 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)); + permissions.add(new PropertyPermission("java.util.logging.config.class", "read")); + permissions.add(new PropertyPermission("java.util.logging.config.file", "read")); + permissions.add(new PropertyPermission("java.home", "read")); + permissions.add(new FilePermission("<>", "read")); + } + } + + @Override + public boolean implies(ProtectionDomain domain, Permission permission) { + return permissions.implies(permission); + } + + @Override + public PermissionCollection getPermissions(CodeSource codesource) { + return new PermissionsBuilder().addAll(permissions).toPermissions(); + } + + @Override + public PermissionCollection getPermissions(ProtectionDomain domain) { + return new PermissionsBuilder().addAll(permissions).toPermissions(); + } + } + +}