1 /* 2 * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 import java.io.ByteArrayInputStream; 24 import java.io.ByteArrayOutputStream; 25 import java.io.IOException; 26 import java.io.UncheckedIOException; 27 import java.lang.ref.Reference; 28 import java.security.Permission; 29 import java.security.Policy; 30 import java.security.ProtectionDomain; 31 import java.util.ArrayList; 32 import java.util.List; 33 import java.util.Objects; 34 import java.util.Properties; 35 import java.util.concurrent.CopyOnWriteArrayList; 36 import java.util.concurrent.atomic.AtomicLong; 37 import java.util.logging.Handler; 38 import java.util.logging.Level; 39 import java.util.logging.LogManager; 40 import java.util.logging.LogRecord; 41 import java.util.logging.Logger; 42 import java.util.stream.Collectors; 43 import java.util.stream.Stream; 44 import sun.util.logging.PlatformLogger; 45 46 47 /** 48 * @test 49 * @bug 8159245 50 * @summary Tests configuration of loggers. 51 * @modules java.logging/sun.util.logging.internal java.base/sun.util.logging 52 * @run main/othervm SystemLoggerConfigTest NOSECURITY 53 * @run main/othervm SystemLoggerConfigTest WITHSECURITY 54 * 55 * @author danielfuchs 56 */ 57 public class SystemLoggerConfigTest { 58 59 static Logger createSystemLogger(String name) { 60 return sun.util.logging.internal.LoggingProviderImpl.getLogManagerAccess() 61 .demandLoggerFor(LogManager.getLogManager(), name, 62 Thread.class.getModule()); 63 } 64 65 static PlatformLogger createPlatformLogger(String name) { 66 return PlatformLogger.getLogger(name); 67 } 68 69 private static void assertFalse(boolean value, String msg) { 70 assertEquals(false, value, msg); 71 } 72 private static void assertEquals(boolean expected, boolean actual, String msg) { 73 if (expected != actual) { 74 throw new AssertionError(msg+": expected: " + expected + " actual: " + actual); 75 } 76 } 77 private static void assertEquals(int expected, int actual, String msg) { 78 if (expected != actual) { 79 throw new AssertionError(msg+": expected: " + expected + " actual: " + actual); 80 } 81 } 82 private static void assertEquals(long expected, long actual, String msg) { 83 if (expected != actual) { 84 throw new AssertionError(msg+": expected: " + expected + " actual: " + actual); 85 } 86 } 87 private static void assertEquals(Object expected, Object actual, String msg) { 88 if (!Objects.equals(expected, actual)) { 89 throw new AssertionError(msg+": expected: " + expected + " actual: " + actual); 90 } 91 } 92 93 static class TestHandler extends Handler { 94 private final List<LogRecord> records = new CopyOnWriteArrayList<>(); 95 public TestHandler() { 96 super(); 97 setLevel(Level.ALL); 98 } 99 100 @Override 101 public void publish(LogRecord lr) { 102 records.add(lr); 103 } 104 105 public List<LogRecord> drain() { 106 List<LogRecord> list = new ArrayList<>(records); 107 records.clear(); 108 return list; 109 } 110 111 public void close() { 112 records.clear(); 113 } 114 115 public void flush() { 116 } 117 118 } 119 120 public static class TestHandler1 extends TestHandler { 121 final static AtomicLong COUNT = new AtomicLong(); 122 public TestHandler1() { 123 COUNT.incrementAndGet(); 124 } 125 } 126 127 public static class TestHandler2 extends TestHandler { 128 final static AtomicLong COUNT = new AtomicLong(); 129 public TestHandler2() { 130 COUNT.incrementAndGet(); 131 } 132 } 133 134 static enum TestCase { WITHSECURITY, NOSECURITY } 135 136 public static void main(String[] args) { 137 if (args == null || args.length == 0) { 138 args = Stream.of(TestCase.values()) 139 .map(String::valueOf) 140 .collect(Collectors.toList()) 141 .toArray(new String[0]); 142 } 143 Stream.of(args) 144 .map(TestCase::valueOf) 145 .forEach(SystemLoggerConfigTest::launch); 146 } 147 148 public static void launch(TestCase test) { 149 switch(test) { 150 case WITHSECURITY: 151 Policy.setPolicy(new Policy() { 152 @Override 153 public boolean implies(ProtectionDomain domain, Permission permission) { 154 return true; 155 } 156 }); 157 System.setSecurityManager(new SecurityManager()); 158 break; 159 case NOSECURITY: 160 break; 161 default: 162 throw new InternalError("Unexpected enum: " + test); 163 } 164 try { 165 test(test.name(), ".1", ".child"); 166 test(test.name(), ".2", ""); 167 testUpdateConfiguration(test.name(), ".3"); 168 testSetPlatformLevel(test.name(), ".4"); 169 } catch (IOException io) { 170 throw new UncheckedIOException(io); 171 } 172 } 173 174 public static void test(String name, String step, String ext) 175 throws IOException { 176 177 System.out.println("\n*** Testing " + name + step + ext); 178 179 final String systemName1a = "system.logger.one.a." + name + step + ext; 180 final String systemName1b = "system.logger.one.b." + name + step + ext; 181 final String appName1a = "system.logger.one.a." + name + step; 182 final String appName1b = "system.logger.one.b." + name + step; 183 final String msg1a = "logger name: " + systemName1a; 184 final String msg1b = "logger name: " + systemName1b; 185 final String systemName2 = "system.logger.two." + name + step + ext; 186 final String appName2 = "system.logger.two." + name + step; 187 final String msg2 = "logger name: " + systemName2; 188 final String systemName3 = "system.logger.three." + name + step + ext; 189 final String appName3 = "system.logger.three." + name + step; 190 final String msg3 = "logger name: " + systemName3; 191 List<LogRecord> records; 192 193 System.out.println("\n[Case #1] Creating platform logger: " + systemName1a); 194 PlatformLogger system1a = createPlatformLogger(systemName1a); 195 System.out.println(" Creating platform logger: " + systemName1b); 196 PlatformLogger system1b = createPlatformLogger(systemName1b); 197 System.out.println(" Adding handler on root logger..."); 198 TestHandler test1 = new TestHandler(); 199 Logger.getLogger("").addHandler(test1); 200 System.out.println(" Creating and configuring app logger: " + appName1a 201 + ", " + appName1b); 202 Logger.getLogger(appName1a).setLevel(Level.INFO); 203 Logger.getLogger(appName1b).setLevel(Level.INFO); 204 assertFalse(system1a.isLoggable(PlatformLogger.Level.FINEST), 205 "Unexpected level for " + system1a); 206 System.out.println(" Configuring root logger..."); 207 Logger.getLogger("").setLevel(Level.FINEST); 208 System.out.println(" Logging through system logger: " + systemName1a); 209 system1a.finest(msg1a); 210 records = test1.drain(); 211 assertEquals(0, records.size(), "Unexpected size for " + records.toString()); 212 System.out.println(" Logging through system logger: " + systemName1b); 213 system1b.finest(msg1b); 214 records = test1.drain(); 215 assertEquals(0, records.size(), "Unexpected size for " + records.toString()); 216 Logger.getLogger("system.logger.one.a").finest("system.logger.one.a"); 217 records = test1.drain(); 218 assertEquals("system.logger.one.a", records.get(0).getMessage(), "Unexpected message: "); 219 Logger.getLogger("").setLevel(Level.INFO); 220 Logger.getLogger("system.logger.one.a").finest("system.logger.one.a"); 221 records = test1.drain(); 222 assertEquals(0, records.size(), "Unexpected size for " + records.toString()); 223 Reference.reachabilityFence(system1a); 224 Reference.reachabilityFence(system1b); 225 226 System.out.println("\n[Case #2] Creating system logger: " + systemName2); 227 Logger system2 = createSystemLogger(systemName2); 228 System.out.println(" Creating app logger: " + appName2); 229 Logger app2 = Logger.getLogger(appName2); 230 System.out.println(" Configuring app logger..."); 231 TestHandler test2 = new TestHandler(); 232 app2.setLevel(Level.ALL); 233 app2.setUseParentHandlers(false); 234 app2.addHandler(test2); 235 System.out.println(" Logging through system logger: " + systemName2); 236 system2.finest(msg2); 237 records = test2.drain(); 238 assertEquals(1, records.size(), "Unexpected size for " + records.toString()); 239 assertEquals(msg2, records.get(0).getMessage(), "Unexpected message: "); 240 records = test1.drain(); 241 assertEquals(0, records.size(), "Unexpected size for " + records.toString()); 242 243 Reference.reachabilityFence(app2); 244 Reference.reachabilityFence(system2); 245 246 System.out.println("\n[Case #3] Creating app logger: " + appName3); 247 Logger app3 = Logger.getLogger(appName3); 248 System.out.println(" Configuring app logger..."); 249 TestHandler test3 = new TestHandler(); 250 app3.setLevel(Level.ALL); 251 app3.setUseParentHandlers(false); 252 app3.addHandler(test3); 253 System.out.println(" Creating system logger: " + systemName3); 254 Logger system3 = createSystemLogger(systemName3); 255 System.out.println(" Logging through system logger: " + systemName3); 256 system3.finest(msg3); 257 records = test3.drain(); 258 assertEquals(1, records.size(), "Unexpected size for " + records.toString()); 259 assertEquals(msg3, records.get(0).getMessage(), "Unexpected message: "); 260 records = test1.drain(); 261 assertEquals(0, records.size(), "Unexpected size for " + records.toString()); 262 263 Reference.reachabilityFence(app3); 264 Reference.reachabilityFence(system3); 265 System.gc(); 266 267 } 268 269 @SuppressWarnings("deprecated") 270 static void setPlatformLevel(PlatformLogger logger, PlatformLogger.Level level) { 271 logger.setLevel(level); 272 } 273 274 public static void testSetPlatformLevel(String name, String step) { 275 System.out.println("\n*** Testing PlatformLogger.setLevel " + name + step); 276 277 System.out.println("\n[Case #5] Creating app logger: " + name + step); 278 // this should return named logger in the global context 279 Logger foo = Logger.getLogger(name + step); 280 foo.setLevel(Level.FINE); 281 282 System.out.println(" Creating platform logger: " + name + step); 283 PlatformLogger foo1 = PlatformLogger.getLogger(name + step); 284 System.out.println(" Configuring platform logger..."); 285 setPlatformLevel(foo1, PlatformLogger.Level.INFO); 286 287 System.out.println(" Checking levels..."); 288 assertEquals(foo.getName(), foo1.getName(), "Bad logger names"); 289 // both logger share the same config 290 assertEquals(foo.getLevel(), Level.INFO, "Bad level for user logger"); 291 assertEquals(foo1.level(), PlatformLogger.Level.INFO, 292 "Bad level for platform logger"); 293 294 } 295 296 static void updateConfiguration(Properties props) throws IOException { 297 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 298 props.store(baos, ""); 299 ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); 300 LogManager.getLogManager().updateConfiguration(bais, (k) -> (o,n) -> n != null ? n : o); 301 } 302 303 static void readConfiguration(Properties props) throws IOException { 304 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 305 props.store(baos, ""); 306 ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); 307 LogManager.getLogManager().readConfiguration(bais); 308 } 309 310 // Tests that though two loggers exist, only one handler is created for the 311 // pair when reading configuration. 312 // 313 public static void testUpdateConfiguration(String name, String step) throws IOException { 314 315 System.out.println("\n*** Testing LogManager.updateConfiguration " + name + step); 316 317 final String name1a = "system.logger.one.a." + name + step; 318 final String name1b = "system.logger.one.b." + name + step; 319 final String msg1a = "logger name: " + name1a; 320 final String msg1b = "logger name: " + name1b; 321 List<LogRecord> records; 322 323 TestHandler1.COUNT.set(0); 324 TestHandler2.COUNT.set(0); 325 Properties props = new Properties(); 326 props.setProperty(name1a+".handlers", TestHandler1.class.getName()); 327 updateConfiguration(props); 328 assertEquals(0, TestHandler1.COUNT.get(), "Bad instance count for " 329 + TestHandler1.class.getName()); 330 assertEquals(0, TestHandler2.COUNT.get(), "Bad instance count for " 331 + TestHandler2.class.getName()); 332 333 System.out.println("\n[Case #4] Creating app logger: " + name1a); 334 Logger app1a = Logger.getLogger(name1a); 335 System.out.println(" Configuring app logger..."); 336 TestHandler test1 = new TestHandler(); 337 app1a.setLevel(Level.ALL); 338 app1a.setUseParentHandlers(false); 339 app1a.addHandler(test1); 340 assertEquals(1, TestHandler1.COUNT.get(), "Bad instance count for " 341 + TestHandler1.class.getName()); 342 assertEquals(0, TestHandler2.COUNT.get(), "Bad instance count for " 343 + TestHandler2.class.getName()); 344 345 System.out.println(" Creating system logger: " + name1a); 346 Logger system1a = createSystemLogger(name1a); 347 assertEquals(Level.ALL, system1a.getLevel(), "Bad level for system logger " + name1a); 348 System.out.println(" Logging through system logger: " + name1a); 349 system1a.finest(msg1a); 350 records = test1.drain(); 351 assertEquals(1, records.size(), "Unexpected size for " + records.toString()); 352 assertEquals(msg1a, records.get(0).getMessage(), "Unexpected message: "); 353 records = test1.drain(); 354 assertEquals(0, records.size(), "Unexpected size for " + records.toString()); 355 356 assertEquals(1, TestHandler1.COUNT.get(), "Bad instance count for " 357 + TestHandler1.class.getName()); 358 assertEquals(0, TestHandler2.COUNT.get(), "Bad instance count for " 359 + TestHandler2.class.getName()); 360 361 props.setProperty(name1a+".handlers", TestHandler2.class.getName()); 362 updateConfiguration(props); 363 364 assertEquals(1, TestHandler1.COUNT.get(), "Bad instance count for " 365 + TestHandler1.class.getName()); 366 assertEquals(1, TestHandler2.COUNT.get(), "Bad instance count for " 367 + TestHandler2.class.getName()); 368 369 updateConfiguration(props); 370 371 assertEquals(1, TestHandler1.COUNT.get(), "Bad instance count for " 372 + TestHandler1.class.getName()); 373 assertEquals(1, TestHandler2.COUNT.get(), "Bad instance count for " 374 + TestHandler2.class.getName()); 375 376 readConfiguration(props); 377 378 assertEquals(1, TestHandler1.COUNT.get(), "Bad instance count for " 379 + TestHandler1.class.getName()); 380 // readConfiguration reset handlers but does not recreate them 381 assertEquals(1, TestHandler2.COUNT.get(), "Bad instance count for " 382 + TestHandler2.class.getName()); 383 384 updateConfiguration(props); 385 386 assertEquals(1, TestHandler1.COUNT.get(), "Bad instance count for " 387 + TestHandler1.class.getName()); 388 assertEquals(1, TestHandler2.COUNT.get(), "Bad instance count for " 389 + TestHandler2.class.getName()); 390 391 LogManager.getLogManager().reset(); 392 updateConfiguration(props); 393 394 assertEquals(1, TestHandler1.COUNT.get(), "Bad instance count for " 395 + TestHandler1.class.getName()); 396 assertEquals(2, TestHandler2.COUNT.get(), "Bad instance count for " 397 + TestHandler2.class.getName()); 398 399 props.setProperty(name1a+".handlers", 400 TestHandler2.class.getName() + "," + TestHandler1.class.getName()); 401 updateConfiguration(props); 402 403 assertEquals(2, TestHandler1.COUNT.get(), "Bad instance count for " 404 + TestHandler1.class.getName()); 405 assertEquals(3, TestHandler2.COUNT.get(), "Bad instance count for " 406 + TestHandler2.class.getName()); 407 408 Reference.reachabilityFence(app1a); 409 Reference.reachabilityFence(system1a); 410 411 LogManager.getLogManager().readConfiguration(); 412 System.gc(); 413 } 414 415 416 417 }