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 */ 23import java.io.ByteArrayInputStream; 24import java.io.ByteArrayOutputStream; 25import java.io.IOException; 26import java.io.UncheckedIOException; 27import java.lang.ref.Reference; 28import java.security.Permission; 29import java.security.Policy; 30import java.security.ProtectionDomain; 31import java.util.ArrayList; 32import java.util.List; 33import java.util.Objects; 34import java.util.Properties; 35import java.util.concurrent.CopyOnWriteArrayList; 36import java.util.concurrent.atomic.AtomicLong; 37import java.util.logging.Handler; 38import java.util.logging.Level; 39import java.util.logging.LogManager; 40import java.util.logging.LogRecord; 41import java.util.logging.Logger; 42import java.util.stream.Collectors; 43import java.util.stream.Stream; 44import 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 */ 57public 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 201 System.out.println(" Creating and configuring app logger: " + appName1a 202 + ", " + appName1b); 203 Logger app1a = Logger.getLogger(appName1a); 204 app1a.setLevel(Level.INFO); 205 Logger app1b = Logger.getLogger(appName1b); 206 app1b.setLevel(Level.INFO); 207 assertFalse(system1a.isLoggable(PlatformLogger.Level.FINEST), 208 "Unexpected level for " + system1a); 209 System.out.println(" Configuring root logger..."); 210 Logger.getLogger("").setLevel(Level.FINEST); 211 System.out.println(" Logging through system logger: " + systemName1a); 212 system1a.finest(msg1a); 213 Reference.reachabilityFence(app1a); 214 records = test1.drain(); 215 assertEquals(0, records.size(), "Unexpected size for " + records.toString()); 216 System.out.println(" Logging through system logger: " + systemName1b); 217 system1b.finest(msg1b); 218 Reference.reachabilityFence(app1b); 219 records = test1.drain(); 220 assertEquals(0, records.size(), "Unexpected size for " + records.toString()); 221 Logger.getLogger("system.logger.one.a").finest("system.logger.one.a"); 222 records = test1.drain(); 223 assertEquals("system.logger.one.a", records.get(0).getMessage(), "Unexpected message: "); 224 Logger.getLogger("").setLevel(Level.INFO); 225 Logger.getLogger("system.logger.one.a").finest("system.logger.one.a"); 226 records = test1.drain(); 227 assertEquals(0, records.size(), "Unexpected size for " + records.toString()); 228 229 Reference.reachabilityFence(system1a); 230 Reference.reachabilityFence(system1b); 231 232 System.out.println("\n[Case #2] Creating system logger: " + systemName2); 233 Logger system2 = createSystemLogger(systemName2); 234 System.out.println(" Creating app logger: " + appName2); 235 Logger app2 = Logger.getLogger(appName2); 236 System.out.println(" Configuring app logger..."); 237 TestHandler test2 = new TestHandler(); 238 app2.setLevel(Level.ALL); 239 app2.setUseParentHandlers(false); 240 app2.addHandler(test2); 241 System.out.println(" Logging through system logger: " + systemName2); 242 system2.finest(msg2); 243 records = test2.drain(); 244 assertEquals(1, records.size(), "Unexpected size for " + records.toString()); 245 assertEquals(msg2, records.get(0).getMessage(), "Unexpected message: "); 246 records = test1.drain(); 247 assertEquals(0, records.size(), "Unexpected size for " + records.toString()); 248 249 Reference.reachabilityFence(app2); 250 Reference.reachabilityFence(system2); 251 252 System.out.println("\n[Case #3] Creating app logger: " + appName3); 253 Logger app3 = Logger.getLogger(appName3); 254 System.out.println(" Configuring app logger..."); 255 TestHandler test3 = new TestHandler(); 256 app3.setLevel(Level.ALL); 257 app3.setUseParentHandlers(false); 258 app3.addHandler(test3); 259 System.out.println(" Creating system logger: " + systemName3); 260 Logger system3 = createSystemLogger(systemName3); 261 System.out.println(" Logging through system logger: " + systemName3); 262 system3.finest(msg3); 263 records = test3.drain(); 264 assertEquals(1, records.size(), "Unexpected size for " + records.toString()); 265 assertEquals(msg3, records.get(0).getMessage(), "Unexpected message: "); 266 records = test1.drain(); 267 assertEquals(0, records.size(), "Unexpected size for " + records.toString()); 268 269 Reference.reachabilityFence(app3); 270 Reference.reachabilityFence(system3); 271 System.gc(); 272 273 } 274 275 @SuppressWarnings("deprecated") 276 static void setPlatformLevel(PlatformLogger logger, PlatformLogger.Level level) { 277 logger.setLevel(level); 278 } 279 280 public static void testSetPlatformLevel(String name, String step) { 281 System.out.println("\n*** Testing PlatformLogger.setLevel " + name + step); 282 283 System.out.println("\n[Case #5] Creating app logger: " + name + step); 284 // this should return named logger in the global context 285 Logger foo = Logger.getLogger(name + step); 286 foo.setLevel(Level.FINE); 287 288 System.out.println(" Creating platform logger: " + name + step); 289 PlatformLogger foo1 = PlatformLogger.getLogger(name + step); 290 System.out.println(" Configuring platform logger..."); 291 setPlatformLevel(foo1, PlatformLogger.Level.INFO); 292 293 System.out.println(" Checking levels..."); 294 assertEquals(foo.getName(), foo1.getName(), "Bad logger names"); 295 // both logger share the same config 296 assertEquals(foo.getLevel(), Level.INFO, "Bad level for user logger"); 297 assertEquals(foo1.level(), PlatformLogger.Level.INFO, 298 "Bad level for platform logger"); 299 300 } 301 302 static void updateConfiguration(Properties props) throws IOException { 303 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 304 props.store(baos, ""); 305 ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); 306 LogManager.getLogManager().updateConfiguration(bais, (k) -> (o,n) -> n != null ? n : o); 307 } 308 309 static void readConfiguration(Properties props) throws IOException { 310 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 311 props.store(baos, ""); 312 ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); 313 LogManager.getLogManager().readConfiguration(bais); 314 } 315 316 // Tests that though two loggers exist, only one handler is created for the 317 // pair when reading configuration. 318 // 319 public static void testUpdateConfiguration(String name, String step) throws IOException { 320 321 System.out.println("\n*** Testing LogManager.updateConfiguration " + name + step); 322 323 final String name1a = "system.logger.one.a." + name + step; 324 final String name1b = "system.logger.one.b." + name + step; 325 final String msg1a = "logger name: " + name1a; 326 final String msg1b = "logger name: " + name1b; 327 List<LogRecord> records; 328 329 TestHandler1.COUNT.set(0); 330 TestHandler2.COUNT.set(0); 331 Properties props = new Properties(); 332 props.setProperty(name1a+".handlers", TestHandler1.class.getName()); 333 updateConfiguration(props); 334 assertEquals(0, TestHandler1.COUNT.get(), "Bad instance count for " 335 + TestHandler1.class.getName()); 336 assertEquals(0, TestHandler2.COUNT.get(), "Bad instance count for " 337 + TestHandler2.class.getName()); 338 339 System.out.println("\n[Case #4] Creating app logger: " + name1a); 340 Logger app1a = Logger.getLogger(name1a); 341 System.out.println(" Configuring app logger..."); 342 TestHandler test1 = new TestHandler(); 343 app1a.setLevel(Level.ALL); 344 app1a.setUseParentHandlers(false); 345 app1a.addHandler(test1); 346 assertEquals(1, TestHandler1.COUNT.get(), "Bad instance count for " 347 + TestHandler1.class.getName()); 348 assertEquals(0, TestHandler2.COUNT.get(), "Bad instance count for " 349 + TestHandler2.class.getName()); 350 351 System.out.println(" Creating system logger: " + name1a); 352 Logger system1a = createSystemLogger(name1a); 353 assertEquals(Level.ALL, system1a.getLevel(), "Bad level for system logger " + name1a); 354 System.out.println(" Logging through system logger: " + name1a); 355 system1a.finest(msg1a); 356 records = test1.drain(); 357 assertEquals(1, records.size(), "Unexpected size for " + records.toString()); 358 assertEquals(msg1a, records.get(0).getMessage(), "Unexpected message: "); 359 records = test1.drain(); 360 assertEquals(0, records.size(), "Unexpected size for " + records.toString()); 361 362 assertEquals(1, TestHandler1.COUNT.get(), "Bad instance count for " 363 + TestHandler1.class.getName()); 364 assertEquals(0, TestHandler2.COUNT.get(), "Bad instance count for " 365 + TestHandler2.class.getName()); 366 367 props.setProperty(name1a+".handlers", TestHandler2.class.getName()); 368 updateConfiguration(props); 369 370 assertEquals(1, TestHandler1.COUNT.get(), "Bad instance count for " 371 + TestHandler1.class.getName()); 372 assertEquals(1, TestHandler2.COUNT.get(), "Bad instance count for " 373 + TestHandler2.class.getName()); 374 375 updateConfiguration(props); 376 377 assertEquals(1, TestHandler1.COUNT.get(), "Bad instance count for " 378 + TestHandler1.class.getName()); 379 assertEquals(1, TestHandler2.COUNT.get(), "Bad instance count for " 380 + TestHandler2.class.getName()); 381 382 readConfiguration(props); 383 384 assertEquals(1, TestHandler1.COUNT.get(), "Bad instance count for " 385 + TestHandler1.class.getName()); 386 // readConfiguration reset handlers but does not recreate them 387 assertEquals(1, TestHandler2.COUNT.get(), "Bad instance count for " 388 + TestHandler2.class.getName()); 389 390 updateConfiguration(props); 391 392 assertEquals(1, TestHandler1.COUNT.get(), "Bad instance count for " 393 + TestHandler1.class.getName()); 394 assertEquals(1, TestHandler2.COUNT.get(), "Bad instance count for " 395 + TestHandler2.class.getName()); 396 397 LogManager.getLogManager().reset(); 398 updateConfiguration(props); 399 400 assertEquals(1, TestHandler1.COUNT.get(), "Bad instance count for " 401 + TestHandler1.class.getName()); 402 assertEquals(2, TestHandler2.COUNT.get(), "Bad instance count for " 403 + TestHandler2.class.getName()); 404 405 props.setProperty(name1a+".handlers", 406 TestHandler2.class.getName() + "," + TestHandler1.class.getName()); 407 updateConfiguration(props); 408 409 assertEquals(2, TestHandler1.COUNT.get(), "Bad instance count for " 410 + TestHandler1.class.getName()); 411 assertEquals(3, TestHandler2.COUNT.get(), "Bad instance count for " 412 + TestHandler2.class.getName()); 413 414 Reference.reachabilityFence(app1a); 415 Reference.reachabilityFence(system1a); 416 417 LogManager.getLogManager().readConfiguration(); 418 System.gc(); 419 } 420 421 422 423} 424