1 /* 2 * Copyright (c) 2015, 2018, 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.ByteArrayOutputStream; 24 import java.io.IOException; 25 import java.io.PrintStream; 26 import java.io.UncheckedIOException; 27 import java.security.AccessControlException; 28 import java.security.CodeSource; 29 import java.security.Permission; 30 import java.security.PermissionCollection; 31 import java.security.Permissions; 32 import java.security.Policy; 33 import java.security.ProtectionDomain; 34 import java.util.Collections; 35 import java.util.Enumeration; 36 import java.util.HashMap; 37 import java.util.Map; 38 import java.util.ResourceBundle; 39 import java.util.stream.Stream; 40 import java.util.concurrent.ConcurrentHashMap; 41 import java.util.concurrent.atomic.AtomicBoolean; 42 import java.util.concurrent.atomic.AtomicLong; 43 import java.util.function.Supplier; 44 import java.lang.System.LoggerFinder; 45 import java.lang.System.Logger; 46 import java.lang.System.Logger.Level; 47 import java.security.AccessController; 48 import java.security.PrivilegedAction; 49 import java.util.EnumSet; 50 import java.util.Iterator; 51 import java.util.Locale; 52 import java.util.ServiceConfigurationError; 53 import java.util.ServiceLoader; 54 import java.util.concurrent.atomic.AtomicReference; 55 import jdk.internal.logger.SimpleConsoleLogger; 56 57 /** 58 * @test 59 * @bug 8140364 8189291 60 * @summary JDK implementation specific unit test for LoggerFinderLoader. 61 * Tests the behavior of LoggerFinderLoader with respect to the 62 * value of the internal diagnosability switches. Also test the 63 * DefaultLoggerFinder and SimpleConsoleLogger implementation. 64 * @modules java.base/sun.util.logging 65 * java.base/jdk.internal.logger 66 * @build AccessSystemLogger LoggerFinderLoaderTest CustomSystemClassLoader BaseLoggerFinder BaseLoggerFinder2 67 * @run driver AccessSystemLogger 68 * @run main/othervm -Xbootclasspath/a:boot -Djava.system.class.loader=CustomSystemClassLoader LoggerFinderLoaderTest NOSECURITY 69 * @run main/othervm -Xbootclasspath/a:boot -Djava.system.class.loader=CustomSystemClassLoader LoggerFinderLoaderTest NOPERMISSIONS 70 * @run main/othervm -Xbootclasspath/a:boot -Djava.system.class.loader=CustomSystemClassLoader LoggerFinderLoaderTest WITHPERMISSIONS 71 * @run main/othervm -Xbootclasspath/a:boot -Djava.system.class.loader=CustomSystemClassLoader -Dtest.fails=true LoggerFinderLoaderTest NOSECURITY 72 * @run main/othervm -Xbootclasspath/a:boot -Djava.system.class.loader=CustomSystemClassLoader -Dtest.fails=true LoggerFinderLoaderTest NOPERMISSIONS 73 * @run main/othervm -Xbootclasspath/a:boot -Djava.system.class.loader=CustomSystemClassLoader -Dtest.fails=true LoggerFinderLoaderTest WITHPERMISSIONS 74 * @run main/othervm -Xbootclasspath/a:boot -Djava.system.class.loader=CustomSystemClassLoader -Dtest.fails=true -Djdk.logger.finder.error=ERROR LoggerFinderLoaderTest NOSECURITY 75 * @run main/othervm -Xbootclasspath/a:boot -Djava.system.class.loader=CustomSystemClassLoader -Dtest.fails=true -Djdk.logger.finder.error=ERROR LoggerFinderLoaderTest NOPERMISSIONS 76 * @run main/othervm -Xbootclasspath/a:boot -Djava.system.class.loader=CustomSystemClassLoader -Dtest.fails=true -Djdk.logger.finder.error=ERROR LoggerFinderLoaderTest WITHPERMISSIONS 77 * @run main/othervm -Xbootclasspath/a:boot -Djava.system.class.loader=CustomSystemClassLoader -Dtest.fails=true -Djdk.logger.finder.error=DEBUG LoggerFinderLoaderTest NOSECURITY 78 * @run main/othervm -Xbootclasspath/a:boot -Djava.system.class.loader=CustomSystemClassLoader -Dtest.fails=true -Djdk.logger.finder.error=DEBUG LoggerFinderLoaderTest NOPERMISSIONS 79 * @run main/othervm -Xbootclasspath/a:boot -Djava.system.class.loader=CustomSystemClassLoader -Dtest.fails=true -Djdk.logger.finder.error=DEBUG LoggerFinderLoaderTest WITHPERMISSIONS 80 * @run main/othervm -Xbootclasspath/a:boot -Djava.system.class.loader=CustomSystemClassLoader -Dtest.fails=true -Djdk.logger.finder.error=QUIET LoggerFinderLoaderTest NOSECURITY 81 * @run main/othervm -Xbootclasspath/a:boot -Djava.system.class.loader=CustomSystemClassLoader -Dtest.fails=true -Djdk.logger.finder.error=QUIET LoggerFinderLoaderTest NOPERMISSIONS 82 * @run main/othervm -Xbootclasspath/a:boot -Djava.system.class.loader=CustomSystemClassLoader -Dtest.fails=true -Djdk.logger.finder.error=QUIET LoggerFinderLoaderTest WITHPERMISSIONS 83 * @run main/othervm -Xbootclasspath/a:boot -Djava.system.class.loader=CustomSystemClassLoader -Djdk.logger.finder.singleton=true LoggerFinderLoaderTest NOSECURITY 84 * @run main/othervm -Xbootclasspath/a:boot -Djava.system.class.loader=CustomSystemClassLoader -Djdk.logger.finder.singleton=true LoggerFinderLoaderTest NOPERMISSIONS 85 * @run main/othervm -Xbootclasspath/a:boot -Djava.system.class.loader=CustomSystemClassLoader -Djdk.logger.finder.singleton=true LoggerFinderLoaderTest WITHPERMISSIONS 86 * @run main/othervm -Xbootclasspath/a:boot -Djava.system.class.loader=CustomSystemClassLoader -Djdk.logger.finder.singleton=true -Djdk.logger.finder.error=ERROR LoggerFinderLoaderTest NOSECURITY 87 * @run main/othervm -Xbootclasspath/a:boot -Djava.system.class.loader=CustomSystemClassLoader -Djdk.logger.finder.singleton=true -Djdk.logger.finder.error=ERROR LoggerFinderLoaderTest NOPERMISSIONS 88 * @run main/othervm -Xbootclasspath/a:boot -Djava.system.class.loader=CustomSystemClassLoader -Djdk.logger.finder.singleton=true -Djdk.logger.finder.error=ERROR LoggerFinderLoaderTest WITHPERMISSIONS 89 * @run main/othervm -Xbootclasspath/a:boot -Djava.system.class.loader=CustomSystemClassLoader -Djdk.logger.finder.singleton=true -Djdk.logger.finder.error=DEBUG LoggerFinderLoaderTest NOSECURITY 90 * @run main/othervm -Xbootclasspath/a:boot -Djava.system.class.loader=CustomSystemClassLoader -Djdk.logger.finder.singleton=true -Djdk.logger.finder.error=DEBUG LoggerFinderLoaderTest NOPERMISSIONS 91 * @run main/othervm -Xbootclasspath/a:boot -Djava.system.class.loader=CustomSystemClassLoader -Djdk.logger.finder.singleton=true -Djdk.logger.finder.error=DEBUG LoggerFinderLoaderTest WITHPERMISSIONS 92 * @run main/othervm -Xbootclasspath/a:boot -Djava.system.class.loader=CustomSystemClassLoader -Djdk.logger.finder.singleton=true -Djdk.logger.finder.error=QUIET LoggerFinderLoaderTest NOSECURITY 93 * @run main/othervm -Xbootclasspath/a:boot -Djava.system.class.loader=CustomSystemClassLoader -Djdk.logger.finder.singleton=true -Djdk.logger.finder.error=QUIET LoggerFinderLoaderTest NOPERMISSIONS 94 * @run main/othervm -Xbootclasspath/a:boot -Djava.system.class.loader=CustomSystemClassLoader -Djdk.logger.finder.singleton=true -Djdk.logger.finder.error=QUIET LoggerFinderLoaderTest WITHPERMISSIONS 95 * @author danielfuchs 96 */ 97 public class LoggerFinderLoaderTest { 98 99 static final Policy DEFAULT_POLICY = Policy.getPolicy(); 100 static final RuntimePermission LOGGERFINDER_PERMISSION = 101 new RuntimePermission("loggerFinder"); 102 final static boolean VERBOSE = false; 103 static final ThreadLocal<AtomicBoolean> allowControl = new ThreadLocal<AtomicBoolean>() { 104 @Override 105 protected AtomicBoolean initialValue() { 106 return new AtomicBoolean(false); 107 } 108 }; 109 static final ThreadLocal<AtomicBoolean> allowAccess = new ThreadLocal<AtomicBoolean>() { 110 @Override 111 protected AtomicBoolean initialValue() { 112 return new AtomicBoolean(false); 113 } 114 }; 115 116 final static AccessSystemLogger accessSystemLogger = new AccessSystemLogger(); 117 static final Class<?>[] providerClass; 118 static { 119 try { 120 providerClass = new Class<?>[] { 121 ClassLoader.getSystemClassLoader().loadClass("BaseLoggerFinder"), 122 ClassLoader.getSystemClassLoader().loadClass("BaseLoggerFinder2") 123 }; 124 } catch (ClassNotFoundException ex) { 125 throw new ExceptionInInitializerError(ex); 126 } 127 } 128 129 /** 130 * What our test provider needs to implement. 131 */ 132 public static interface TestLoggerFinder { 133 public final static AtomicBoolean fails = new AtomicBoolean(); 134 public final static AtomicReference<String> conf = new AtomicReference<>(""); 135 public final static AtomicLong sequencer = new AtomicLong(); 136 public final ConcurrentHashMap<String, LoggerImpl> system = new ConcurrentHashMap<>(); 137 public final ConcurrentHashMap<String, LoggerImpl> user = new ConcurrentHashMap<>(); 138 139 public class LoggerImpl implements System.Logger { 140 final String name; 141 final Logger logger; 142 143 public LoggerImpl(String name, Logger logger) { 144 this.name = name; 145 this.logger = logger; 146 } 147 148 @Override 149 public String getName() { 150 return name; 151 } 152 153 @Override 154 public boolean isLoggable(Logger.Level level) { 155 return logger.isLoggable(level); 156 } 157 158 @Override 159 public void log(Logger.Level level, ResourceBundle bundle, String key, Throwable thrown) { 160 logger.log(level, bundle, key, thrown); 161 } 162 163 @Override 164 public void log(Logger.Level level, ResourceBundle bundle, String format, Object... params) { 165 logger.log(level, bundle, format, params); 166 } 167 168 } 169 170 public Logger getLogger(String name, Module caller); 171 public Logger getLocalizedLogger(String name, ResourceBundle bundle, Module caller); 172 } 173 174 public static class MyBundle extends ResourceBundle { 175 176 final ConcurrentHashMap<String,String> map = new ConcurrentHashMap<>(); 177 178 @Override 179 protected Object handleGetObject(String key) { 180 if (key.contains(" (translated)")) { 181 throw new RuntimeException("Unexpected key: " + key); 182 } 183 return map.computeIfAbsent(key, k -> k.toUpperCase(Locale.ROOT) + " (translated)"); 184 } 185 186 @Override 187 public Enumeration<String> getKeys() { 188 return Collections.enumeration(map.keySet()); 189 } 190 191 } 192 public static class MyLoggerBundle extends MyBundle { 193 194 } 195 196 static enum TestCases {NOSECURITY, NOPERMISSIONS, WITHPERMISSIONS}; 197 198 static void setSecurityManager() { 199 if (System.getSecurityManager() == null) { 200 Policy.setPolicy(new SimplePolicy(allowControl, allowAccess)); 201 System.setSecurityManager(new SecurityManager()); 202 } 203 } 204 205 static LoggerFinder getLoggerFinder(Class<?> expectedClass, 206 String errorPolicy, boolean singleton) { 207 LoggerFinder provider = null; 208 try { 209 TestLoggerFinder.sequencer.incrementAndGet(); 210 provider = LoggerFinder.getLoggerFinder(); 211 if (TestLoggerFinder.fails.get() || singleton) { 212 if ("ERROR".equals(errorPolicy.toUpperCase(Locale.ROOT))) { 213 throw new RuntimeException("Expected exception not thrown"); 214 } else if ("WARNING".equals(errorPolicy.toUpperCase(Locale.ROOT))) { 215 String warning = ErrorStream.errorStream.peek(); 216 if (!warning.contains("WARNING: Failed to instantiate LoggerFinder provider; Using default.")) { 217 throw new RuntimeException("Expected message not found. Error stream contained: " + warning); 218 } 219 } else if ("DEBUG".equals(errorPolicy.toUpperCase(Locale.ROOT))) { 220 String warning = ErrorStream.errorStream.peek(); 221 if (!warning.contains("WARNING: Failed to instantiate LoggerFinder provider; Using default.")) { 222 throw new RuntimeException("Expected message not found. Error stream contained: " + warning); 223 } 224 if (!warning.contains("WARNING: Exception raised trying to instantiate LoggerFinder")) { 225 throw new RuntimeException("Expected message not found. Error stream contained: " + warning); 226 } 227 if (TestLoggerFinder.fails.get()) { 228 if (!warning.contains("java.util.ServiceConfigurationError: java.lang.System$LoggerFinder: Provider BaseLoggerFinder could not be instantiated")) { 229 throw new RuntimeException("Expected message not found. Error stream contained: " + warning); 230 } 231 } else if (singleton) { 232 if (!warning.contains("java.util.ServiceConfigurationError: More than on LoggerFinder implementation")) { 233 throw new RuntimeException("Expected message not found. Error stream contained: " + warning); 234 } 235 } 236 } else if ("QUIET".equals(errorPolicy.toUpperCase(Locale.ROOT))) { 237 if (!ErrorStream.errorStream.peek().isEmpty()) { 238 throw new RuntimeException("Unexpected error message found: " 239 + ErrorStream.errorStream.peek()); 240 } 241 } 242 } 243 } catch(AccessControlException a) { 244 throw a; 245 } catch(Throwable t) { 246 if (TestLoggerFinder.fails.get() || singleton) { 247 // must check System.err 248 if ("ERROR".equals(errorPolicy.toUpperCase(Locale.ROOT))) { 249 provider = LoggerFinder.getLoggerFinder(); 250 } else { 251 Throwable orig = t.getCause(); 252 while (orig != null && orig.getCause() != null) orig = orig.getCause(); 253 if (orig != null) orig.printStackTrace(ErrorStream.err); 254 throw new RuntimeException("Unexpected exception: " + t, t); 255 } 256 } else { 257 throw new RuntimeException("Unexpected exception: " + t, t); 258 } 259 } 260 expectedClass.cast(provider); 261 ErrorStream.errorStream.store(); 262 System.out.println("*** Actual LoggerFinder class is: " + provider.getClass().getName()); 263 return provider; 264 } 265 266 267 static class ErrorStream extends PrintStream { 268 269 static AtomicBoolean forward = new AtomicBoolean(); 270 ByteArrayOutputStream out; 271 String saved = ""; 272 public ErrorStream(ByteArrayOutputStream out) { 273 super(out); 274 this.out = out; 275 } 276 277 @Override 278 public void write(int b) { 279 super.write(b); 280 if (forward.get()) err.write(b); 281 } 282 283 @Override 284 public void write(byte[] b) throws IOException { 285 super.write(b); 286 if (forward.get()) err.write(b); 287 } 288 289 @Override 290 public void write(byte[] buf, int off, int len) { 291 super.write(buf, off, len); 292 if (forward.get()) err.write(buf, off, len); 293 } 294 295 public String peek() { 296 flush(); 297 return out.toString(); 298 } 299 300 public String drain() { 301 flush(); 302 String res = out.toString(); 303 out.reset(); 304 return res; 305 } 306 307 public void store() { 308 flush(); 309 saved = out.toString(); 310 out.reset(); 311 } 312 313 public void restore() { 314 out.reset(); 315 try { 316 out.write(saved.getBytes()); 317 } catch(IOException io) { 318 throw new UncheckedIOException(io); 319 } 320 } 321 322 static final PrintStream err = System.err; 323 static final ErrorStream errorStream = new ErrorStream(new ByteArrayOutputStream()); 324 } 325 326 private static StringBuilder appendProperty(StringBuilder b, String name) { 327 String value = System.getProperty(name); 328 if (value == null) return b; 329 return b.append(name).append("=").append(value).append('\n'); 330 } 331 332 public static void main(String[] args) { 333 if (args.length == 0) { 334 args = new String[] { 335 "NOSECURITY", 336 "NOPERMISSIONS", 337 "WITHPERMISSIONS" 338 }; 339 } 340 Locale.setDefault(Locale.ENGLISH); 341 System.setErr(ErrorStream.errorStream); 342 System.setProperty("jdk.logger.packages", TestLoggerFinder.LoggerImpl.class.getName()); 343 //System.setProperty("jdk.logger.finder.error", "ERROR"); 344 //System.setProperty("jdk.logger.finder.singleton", "true"); 345 //System.setProperty("test.fails", "true"); 346 TestLoggerFinder.fails.set(Boolean.getBoolean("test.fails")); 347 StringBuilder c = new StringBuilder(); 348 appendProperty(c, "jdk.logger.packages"); 349 appendProperty(c, "jdk.logger.finder.error"); 350 appendProperty(c, "jdk.logger.finder.singleton"); 351 appendProperty(c, "test.fails"); 352 TestLoggerFinder.conf.set(c.toString()); 353 try { 354 test(args); 355 } finally { 356 try { 357 System.setErr(ErrorStream.err); 358 } catch (Error | RuntimeException x) { 359 x.printStackTrace(ErrorStream.err); 360 } 361 } 362 } 363 364 365 public static void test(String[] args) { 366 367 final String errorPolicy = System.getProperty("jdk.logger.finder.error", "WARNING"); 368 final Boolean ensureSingleton = Boolean.getBoolean("jdk.logger.finder.singleton"); 369 370 final Class<?> expectedClass = 371 TestLoggerFinder.fails.get() || ensureSingleton 372 ? jdk.internal.logger.DefaultLoggerFinder.class 373 : TestLoggerFinder.class; 374 375 System.out.println("Declared provider class: " + providerClass[0] 376 + "[" + providerClass[0].getClassLoader() + "]"); 377 378 if (!TestLoggerFinder.fails.get()) { 379 ServiceLoader<LoggerFinder> serviceLoader = 380 ServiceLoader.load(LoggerFinder.class, ClassLoader.getSystemClassLoader()); 381 Iterator<LoggerFinder> iterator = serviceLoader.iterator(); 382 Object firstProvider = iterator.next(); 383 if (!firstProvider.getClass().getName().equals("BaseLoggerFinder")) { 384 throw new RuntimeException("Unexpected provider: " + firstProvider.getClass().getName()); 385 } 386 if (!iterator.hasNext()) { 387 throw new RuntimeException("Expected two providers"); 388 } 389 } 390 391 Stream.of(args).map(TestCases::valueOf).forEach((testCase) -> { 392 LoggerFinder provider; 393 ErrorStream.errorStream.restore(); 394 switch (testCase) { 395 case NOSECURITY: 396 System.out.println("\n*** Without Security Manager\n"); 397 System.out.println(TestLoggerFinder.conf.get()); 398 provider = getLoggerFinder(expectedClass, errorPolicy, ensureSingleton); 399 test(provider, true); 400 System.out.println("Tetscase count: " + TestLoggerFinder.sequencer.get()); 401 break; 402 case NOPERMISSIONS: 403 System.out.println("\n*** With Security Manager, without permissions\n"); 404 System.out.println(TestLoggerFinder.conf.get()); 405 setSecurityManager(); 406 try { 407 provider = getLoggerFinder(expectedClass, errorPolicy, ensureSingleton); 408 throw new RuntimeException("Expected exception not raised"); 409 } catch (AccessControlException x) { 410 if (!LOGGERFINDER_PERMISSION.equals(x.getPermission())) { 411 throw new RuntimeException("Unexpected permission check", x); 412 } 413 final boolean control = allowControl.get().get(); 414 try { 415 allowControl.get().set(true); 416 provider = getLoggerFinder(expectedClass, errorPolicy, ensureSingleton); 417 } finally { 418 allowControl.get().set(control); 419 } 420 } 421 test(provider, false); 422 System.out.println("Tetscase count: " + TestLoggerFinder.sequencer.get()); 423 break; 424 case WITHPERMISSIONS: 425 System.out.println("\n*** With Security Manager, with control permission\n"); 426 System.out.println(TestLoggerFinder.conf.get()); 427 setSecurityManager(); 428 final boolean control = allowControl.get().get(); 429 try { 430 allowControl.get().set(true); 431 provider = getLoggerFinder(expectedClass, errorPolicy, ensureSingleton); 432 test(provider, true); 433 } finally { 434 allowControl.get().set(control); 435 } 436 break; 437 default: 438 throw new RuntimeException("Unknown test case: " + testCase); 439 } 440 }); 441 System.out.println("\nPASSED: Tested " + TestLoggerFinder.sequencer.get() + " cases."); 442 } 443 444 public static void test(LoggerFinder provider, boolean hasRequiredPermissions) { 445 446 ResourceBundle loggerBundle = ResourceBundle.getBundle(MyLoggerBundle.class.getName()); 447 final Map<Logger, String> loggerDescMap = new HashMap<>(); 448 449 System.Logger sysLogger = accessSystemLogger.getLogger("foo"); 450 loggerDescMap.put(sysLogger, "accessSystemLogger.getLogger(\"foo\")"); 451 System.Logger localizedSysLogger = accessSystemLogger.getLogger("fox", loggerBundle); 452 loggerDescMap.put(localizedSysLogger, "accessSystemLogger.getLogger(\"fox\", loggerBundle)"); 453 System.Logger appLogger = System.getLogger("bar"); 454 loggerDescMap.put(appLogger,"System.getLogger(\"bar\")"); 455 System.Logger localizedAppLogger = System.getLogger("baz", loggerBundle); 456 loggerDescMap.put(localizedAppLogger,"System.getLogger(\"baz\", loggerBundle)"); 457 458 testLogger(provider, loggerDescMap, "foo", null, sysLogger); 459 testLogger(provider, loggerDescMap, "foo", loggerBundle, localizedSysLogger); 460 testLogger(provider, loggerDescMap, "foo", null, appLogger); 461 testLogger(provider, loggerDescMap, "foo", loggerBundle, localizedAppLogger); 462 } 463 464 public static class Foo { 465 466 } 467 468 static void verbose(String msg) { 469 if (VERBOSE) { 470 System.out.println(msg); 471 } 472 } 473 474 // Calls the 8 methods defined on Logger and verify the 475 // parameters received by the underlying TestProvider.LoggerImpl 476 // logger. 477 private static void testLogger(LoggerFinder provider, 478 Map<Logger, String> loggerDescMap, 479 String name, 480 ResourceBundle loggerBundle, 481 Logger logger) { 482 483 System.out.println("Testing " + loggerDescMap.get(logger) + " [" + logger +"]"); 484 AtomicLong sequencer = TestLoggerFinder.sequencer; 485 486 Foo foo = new Foo(); 487 String fooMsg = foo.toString(); 488 for (Level loggerLevel : EnumSet.of(Level.INFO)) { 489 for (Level messageLevel : Level.values()) { 490 ErrorStream.errorStream.drain(); 491 String desc = "logger.log(messageLevel, foo): loggerLevel=" 492 + loggerLevel+", messageLevel="+messageLevel; 493 sequencer.incrementAndGet(); 494 logger.log(messageLevel, foo); 495 if (loggerLevel == Level.OFF || messageLevel == Level.OFF || messageLevel.compareTo(loggerLevel) < 0) { 496 if (!ErrorStream.errorStream.peek().isEmpty()) { 497 throw new RuntimeException("unexpected event in queue for " 498 + desc +": " + "\n\t" + ErrorStream.errorStream.drain()); 499 } 500 } else { 501 String logged = ErrorStream.errorStream.drain(); 502 if (!logged.contains("LoggerFinderLoaderTest testLogger") 503 || !logged.contains(messageLevel.getName() + ": " + fooMsg)) { 504 throw new RuntimeException("mismatch for " + desc 505 + "\n\texpected:" + "\n<<<<\n" 506 + "[date] LoggerFinderLoaderTest testLogger\n" 507 + messageLevel.getName() + " " + fooMsg 508 + "\n>>>>" 509 + "\n\t actual:" 510 + "\n<<<<\n" + logged + ">>>>\n"); 511 } else { 512 verbose("Got expected results for " 513 + desc + "\n<<<<\n" + logged + ">>>>\n"); 514 } 515 } 516 } 517 } 518 519 String msg = "blah"; 520 for (Level loggerLevel : EnumSet.of(Level.INFO)) { 521 for (Level messageLevel : Level.values()) { 522 String desc = "logger.log(messageLevel, \"blah\"): loggerLevel=" 523 + loggerLevel+", messageLevel="+messageLevel; 524 sequencer.incrementAndGet(); 525 logger.log(messageLevel, msg); 526 if (loggerLevel == Level.OFF || messageLevel == Level.OFF || messageLevel.compareTo(loggerLevel) < 0) { 527 if (!ErrorStream.errorStream.peek().isEmpty()) { 528 throw new RuntimeException("unexpected event in queue for " 529 + desc +": " + "\n\t" + ErrorStream.errorStream.drain()); 530 } 531 } else { 532 String logged = ErrorStream.errorStream.drain(); 533 String msgText = loggerBundle == null ? msg : loggerBundle.getString(msg); 534 if (!logged.contains("LoggerFinderLoaderTest testLogger") 535 || !logged.contains(messageLevel.getName() + ": " + msgText)) { 536 throw new RuntimeException("mismatch for " + desc 537 + "\n\texpected:" + "\n<<<<\n" 538 + "[date] LoggerFinderLoaderTest testLogger\n" 539 + messageLevel.getName() + " " + msgText 540 + "\n>>>>" 541 + "\n\t actual:" 542 + "\n<<<<\n" + logged + ">>>>\n"); 543 } else { 544 verbose("Got expected results for " 545 + desc + "\n<<<<\n" + logged + ">>>>\n"); 546 } 547 } 548 } 549 } 550 551 Supplier<String> fooSupplier = new Supplier<String>() { 552 @Override 553 public String get() { 554 return this.toString(); 555 } 556 }; 557 558 for (Level loggerLevel : EnumSet.of(Level.INFO)) { 559 for (Level messageLevel : Level.values()) { 560 String desc = "logger.log(messageLevel, fooSupplier): loggerLevel=" 561 + loggerLevel+", messageLevel="+messageLevel; 562 sequencer.incrementAndGet(); 563 logger.log(messageLevel, fooSupplier); 564 if (loggerLevel == Level.OFF || messageLevel == Level.OFF || messageLevel.compareTo(loggerLevel) < 0) { 565 if (!ErrorStream.errorStream.peek().isEmpty()) { 566 throw new RuntimeException("unexpected event in queue for " 567 + desc +": " + "\n\t" + ErrorStream.errorStream.drain()); 568 } 569 } else { 570 String logged = ErrorStream.errorStream.drain(); 571 if (!logged.contains("LoggerFinderLoaderTest testLogger") 572 || !logged.contains(messageLevel.getName() + ": " + fooSupplier.get())) { 573 throw new RuntimeException("mismatch for " + desc 574 + "\n\texpected:" + "\n<<<<\n" 575 + "[date] LoggerFinderLoaderTest testLogger\n" 576 + messageLevel.getName() + " " + fooSupplier.get() 577 + "\n>>>>" 578 + "\n\t actual:" 579 + "\n<<<<\n" + logged + ">>>>\n"); 580 } else { 581 verbose("Got expected results for " 582 + desc + "\n<<<<\n" + logged + ">>>>\n"); 583 } 584 } 585 } 586 } 587 588 589 String format = "two params [{1} {2}]"; 590 Object arg1 = foo; 591 Object arg2 = msg; 592 for (Level loggerLevel : EnumSet.of(Level.INFO)) { 593 for (Level messageLevel : Level.values()) { 594 String desc = "logger.log(messageLevel, format, params...): loggerLevel=" 595 + loggerLevel+", messageLevel="+messageLevel; 596 sequencer.incrementAndGet(); 597 logger.log(messageLevel, format, foo, msg); 598 if (loggerLevel == Level.OFF || messageLevel == Level.OFF || messageLevel.compareTo(loggerLevel) < 0) { 599 if (!ErrorStream.errorStream.peek().isEmpty()) { 600 throw new RuntimeException("unexpected event in queue for " 601 + desc +": " + "\n\t" + ErrorStream.errorStream.drain()); 602 } 603 } else { 604 String logged = ErrorStream.errorStream.drain(); 605 String msgFormat = loggerBundle == null ? format : loggerBundle.getString(format); 606 String text = java.text.MessageFormat.format(msgFormat, foo, msg); 607 if (!logged.contains("LoggerFinderLoaderTest testLogger") 608 || !logged.contains(messageLevel.getName() + ": " + text)) { 609 throw new RuntimeException("mismatch for " + desc 610 + "\n\texpected:" + "\n<<<<\n" 611 + "[date] LoggerFinderLoaderTest testLogger\n" 612 + messageLevel.getName() + " " + text 613 + "\n>>>>" 614 + "\n\t actual:" 615 + "\n<<<<\n" + logged + ">>>>\n"); 616 } else { 617 verbose("Got expected results for " 618 + desc + "\n<<<<\n" + logged + ">>>>\n"); 619 } 620 } 621 } 622 } 623 624 Throwable thrown = new Exception("OK: log me!"); 625 for (Level loggerLevel : EnumSet.of(Level.INFO)) { 626 for (Level messageLevel : Level.values()) { 627 String desc = "logger.log(messageLevel, \"blah\", thrown): loggerLevel=" 628 + loggerLevel+", messageLevel="+messageLevel; 629 sequencer.incrementAndGet(); 630 logger.log(messageLevel, msg, thrown); 631 if (loggerLevel == Level.OFF || messageLevel == Level.OFF || messageLevel.compareTo(loggerLevel) < 0) { 632 if (!ErrorStream.errorStream.peek().isEmpty()) { 633 throw new RuntimeException("unexpected event in queue for " 634 + desc +": " + "\n\t" + ErrorStream.errorStream.drain()); 635 } 636 } else { 637 String logged = ErrorStream.errorStream.drain(); 638 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 639 thrown.printStackTrace(new PrintStream(baos)); 640 String text = baos.toString(); 641 String msgText = loggerBundle == null ? msg : loggerBundle.getString(msg); 642 if (!logged.contains("LoggerFinderLoaderTest testLogger") 643 || !logged.contains(messageLevel.getName() + ": " + msgText) 644 || !logged.contains(text)) { 645 throw new RuntimeException("mismatch for " + desc 646 + "\n\texpected:" + "\n<<<<\n" 647 + "[date] LoggerFinderLoaderTest testLogger\n" 648 + messageLevel.getName() + " " + msgText +"\n" 649 + text 650 + ">>>>" 651 + "\n\t actual:" 652 + "\n<<<<\n" + logged + ">>>>\n"); 653 } else { 654 verbose("Got expected results for " 655 + desc + "\n<<<<\n" + logged + ">>>>\n"); 656 } 657 } 658 } 659 } 660 661 662 for (Level loggerLevel : EnumSet.of(Level.INFO)) { 663 for (Level messageLevel : Level.values()) { 664 String desc = "logger.log(messageLevel, thrown, fooSupplier): loggerLevel=" 665 + loggerLevel+", messageLevel="+messageLevel; 666 sequencer.incrementAndGet(); 667 logger.log(messageLevel, fooSupplier, thrown); 668 if (loggerLevel == Level.OFF || messageLevel == Level.OFF || messageLevel.compareTo(loggerLevel) < 0) { 669 if (!ErrorStream.errorStream.peek().isEmpty()) { 670 throw new RuntimeException("unexpected event in queue for " 671 + desc +": " + "\n\t" + ErrorStream.errorStream.drain()); 672 } 673 } else { 674 String logged = ErrorStream.errorStream.drain(); 675 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 676 thrown.printStackTrace(new PrintStream(baos)); 677 String text = baos.toString(); 678 if (!logged.contains("LoggerFinderLoaderTest testLogger") 679 || !logged.contains(messageLevel.getName() + ": " + fooSupplier.get()) 680 || !logged.contains(text)) { 681 throw new RuntimeException("mismatch for " + desc 682 + "\n\texpected:" + "\n<<<<\n" 683 + "[date] LoggerFinderLoaderTest testLogger\n" 684 + messageLevel.getName() + " " + fooSupplier.get() +"\n" 685 + text 686 + ">>>>" 687 + "\n\t actual:" 688 + "\n<<<<\n" + logged + ">>>>\n"); 689 } else { 690 verbose("Got expected results for " 691 + desc + "\n<<<<\n" + logged + ">>>>\n"); 692 } 693 } 694 } 695 } 696 697 ResourceBundle bundle = ResourceBundle.getBundle(MyBundle.class.getName()); 698 for (Level loggerLevel : EnumSet.of(Level.INFO)) { 699 for (Level messageLevel : Level.values()) { 700 String desc = "logger.log(messageLevel, bundle, format, params...): loggerLevel=" 701 + loggerLevel+", messageLevel="+messageLevel; 702 sequencer.incrementAndGet(); 703 logger.log(messageLevel, bundle, format, foo, msg); 704 if (loggerLevel == Level.OFF || messageLevel == Level.OFF || messageLevel.compareTo(loggerLevel) < 0) { 705 if (!ErrorStream.errorStream.peek().isEmpty()) { 706 throw new RuntimeException("unexpected event in queue for " 707 + desc +": " + "\n\t" + ErrorStream.errorStream.drain()); 708 } 709 } else { 710 String logged = ErrorStream.errorStream.drain(); 711 String text = java.text.MessageFormat.format(bundle.getString(format), foo, msg); 712 if (!logged.contains("LoggerFinderLoaderTest testLogger") 713 || !logged.contains(messageLevel.getName() + ": " + text)) { 714 throw new RuntimeException("mismatch for " + desc 715 + "\n\texpected:" + "\n<<<<\n" 716 + "[date] LoggerFinderLoaderTest testLogger\n" 717 + messageLevel.getName() + " " + text 718 + "\n>>>>" 719 + "\n\t actual:" 720 + "\n<<<<\n" + logged + ">>>>\n"); 721 } else { 722 verbose("Got expected results for " 723 + desc + "\n<<<<\n" + logged + ">>>>\n"); 724 } 725 } 726 } 727 } 728 729 for (Level loggerLevel : EnumSet.of(Level.INFO)) { 730 for (Level messageLevel : Level.values()) { 731 String desc = "logger.log(messageLevel, bundle, \"blah\", thrown): loggerLevel=" 732 + loggerLevel+", messageLevel="+messageLevel; 733 sequencer.incrementAndGet(); 734 logger.log(messageLevel, bundle, msg, thrown); 735 if (loggerLevel == Level.OFF || messageLevel == Level.OFF || messageLevel.compareTo(loggerLevel) < 0) { 736 if (!ErrorStream.errorStream.peek().isEmpty()) { 737 throw new RuntimeException("unexpected event in queue for " 738 + desc +": " + "\n\t" + ErrorStream.errorStream.drain()); 739 } 740 } else { 741 String logged = ErrorStream.errorStream.drain(); 742 String textMsg = bundle.getString(msg); 743 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 744 thrown.printStackTrace(new PrintStream(baos)); 745 String text = baos.toString(); 746 if (!logged.contains("LoggerFinderLoaderTest testLogger") 747 || !logged.contains(messageLevel.getName() + ": " + textMsg) 748 || !logged.contains(text)) { 749 throw new RuntimeException("mismatch for " + desc 750 + "\n\texpected:" + "\n<<<<\n" 751 + "[date] LoggerFinderLoaderTest testLogger\n" 752 + messageLevel.getName() + " " + textMsg +"\n" 753 + text 754 + ">>>>" 755 + "\n\t actual:" 756 + "\n<<<<\n" + logged + ">>>>\n"); 757 } else { 758 verbose("Got expected results for " 759 + desc + "\n<<<<\n" + logged + ">>>>\n"); 760 } 761 } 762 } 763 } 764 765 } 766 767 final static class PermissionsBuilder { 768 final Permissions perms; 769 public PermissionsBuilder() { 770 this(new Permissions()); 771 } 772 public PermissionsBuilder(Permissions perms) { 773 this.perms = perms; 774 } 775 public PermissionsBuilder add(Permission p) { 776 perms.add(p); 777 return this; 778 } 779 public PermissionsBuilder addAll(PermissionCollection col) { 780 if (col != null) { 781 for (Enumeration<Permission> e = col.elements(); e.hasMoreElements(); ) { 782 perms.add(e.nextElement()); 783 } 784 } 785 return this; 786 } 787 public Permissions toPermissions() { 788 final PermissionsBuilder builder = new PermissionsBuilder(); 789 builder.addAll(perms); 790 return builder.perms; 791 } 792 } 793 794 public static class SimplePolicy extends Policy { 795 final static RuntimePermission CONTROL = LOGGERFINDER_PERMISSION; 796 final static RuntimePermission ACCESS = new RuntimePermission("accessClassInPackage.jdk.internal.logger"); 797 798 final Permissions permissions; 799 final ThreadLocal<AtomicBoolean> allowControl; 800 final ThreadLocal<AtomicBoolean> allowAccess; 801 public SimplePolicy(ThreadLocal<AtomicBoolean> allowControl, ThreadLocal<AtomicBoolean> allowAccess) { 802 this.allowControl = allowControl; 803 this.allowAccess = allowAccess; 804 permissions = new Permissions(); 805 permissions.add(new RuntimePermission("setIO")); 806 } 807 808 Permissions getPermissions() { 809 if (allowControl.get().get() || allowAccess.get().get()) { 810 PermissionsBuilder builder = new PermissionsBuilder() 811 .addAll(permissions); 812 if (allowControl.get().get()) { 813 builder.add(CONTROL); 814 } 815 if (allowAccess.get().get()) { 816 builder.add(ACCESS); 817 } 818 return builder.toPermissions(); 819 } 820 return permissions; 821 } 822 823 @Override 824 public boolean implies(ProtectionDomain domain, Permission permission) { 825 return getPermissions().implies(permission) || 826 DEFAULT_POLICY.implies(domain, permission); 827 } 828 829 @Override 830 public PermissionCollection getPermissions(CodeSource codesource) { 831 return new PermissionsBuilder().addAll(getPermissions()).toPermissions(); 832 } 833 834 @Override 835 public PermissionCollection getPermissions(ProtectionDomain domain) { 836 return new PermissionsBuilder().addAll(getPermissions()).toPermissions(); 837 } 838 } 839 }