Path: blob/master/test/jdk/java/lang/System/Logger/default/DefaultLoggerTest.java
41154 views
/*1* Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*/22import java.security.AccessControlException;23import java.security.CodeSource;24import java.security.Permission;25import java.security.PermissionCollection;26import java.security.Permissions;27import java.security.Policy;28import java.security.ProtectionDomain;29import java.util.Arrays;30import java.util.Collections;31import java.util.Enumeration;32import java.util.HashMap;33import java.util.Map;34import java.util.Objects;35import java.util.Queue;36import java.util.ResourceBundle;37import java.util.concurrent.ArrayBlockingQueue;38import java.util.concurrent.ConcurrentHashMap;39import java.util.concurrent.atomic.AtomicBoolean;40import java.util.concurrent.atomic.AtomicLong;41import java.util.function.Supplier;42import java.lang.System.LoggerFinder;43import java.lang.System.Logger;44import java.lang.System.Logger.Level;45import java.lang.reflect.InvocationTargetException;46import java.lang.reflect.Method;47import java.util.function.Function;48import java.util.logging.Handler;49import java.util.logging.LogRecord;50import java.util.stream.Stream;5152/**53* @test54* @bug 8140364 814568655* @summary Tests default loggers returned by System.getLogger, and in56* particular the implementation of the the System.Logger method57* performed by the default binding.58* @modules java.logging59* @build DefaultLoggerTest AccessSystemLogger60* @run driver AccessSystemLogger61* @run main/othervm -Xbootclasspath/a:boot DefaultLoggerTest NOSECURITY62* @run main/othervm -Xbootclasspath/a:boot -Djava.security.manager=allow DefaultLoggerTest NOPERMISSIONS63* @run main/othervm -Xbootclasspath/a:boot -Djava.security.manager=allow DefaultLoggerTest WITHPERMISSIONS64* @run main/othervm -Xbootclasspath/a:boot -Djava.security.manager=allow DefaultLoggerTest WITHCUSTOMWRAPPERS65* @run main/othervm -Xbootclasspath/a:boot -Djava.security.manager=allow DefaultLoggerTest WITHREFLECTION66* @author danielfuchs67*/68public class DefaultLoggerTest {6970final static AtomicLong sequencer = new AtomicLong();71final static boolean VERBOSE = false;72static final ThreadLocal<AtomicBoolean> allowControl = new ThreadLocal<AtomicBoolean>() {73@Override74protected AtomicBoolean initialValue() {75return new AtomicBoolean(false);76}77};78static final ThreadLocal<AtomicBoolean> allowAll = new ThreadLocal<AtomicBoolean>() {79@Override80protected AtomicBoolean initialValue() {81return new AtomicBoolean(false);82}83};8485public static final Queue<LogEvent> eventQueue = new ArrayBlockingQueue<>(128);8687public static final class LogEvent {8889public LogEvent() {90this(sequencer.getAndIncrement());91}9293LogEvent(long sequenceNumber) {94this.sequenceNumber = sequenceNumber;95}9697long sequenceNumber;98boolean isLoggable;99String loggerName;100java.util.logging.Level level;101ResourceBundle bundle;102Throwable thrown;103Object[] args;104String msg;105String className;106String methodName;107108Object[] toArray() {109return new Object[] {110sequenceNumber,111isLoggable,112loggerName,113level,114bundle,115thrown,116args,117msg,118className,119methodName,120};121}122123@Override124public String toString() {125return Arrays.deepToString(toArray());126}127128@Override129public boolean equals(Object obj) {130return obj instanceof LogEvent131&& Objects.deepEquals(this.toArray(), ((LogEvent)obj).toArray());132}133134@Override135public int hashCode() {136return Objects.hash(toArray());137}138public static LogEvent of(long sequenceNumber,139boolean isLoggable, String name,140java.util.logging.Level level, ResourceBundle bundle,141String key, Throwable thrown, Object... params) {142return LogEvent.of(sequenceNumber, isLoggable, name,143DefaultLoggerTest.class.getName(),144"testLogger", level, bundle, key,145thrown, params);146}147public static LogEvent of(long sequenceNumber,148boolean isLoggable, String name,149String className, String methodName,150java.util.logging.Level level, ResourceBundle bundle,151String key, Throwable thrown, Object... params) {152LogEvent evt = new LogEvent(sequenceNumber);153evt.loggerName = name;154evt.level = level;155evt.args = params;156evt.bundle = bundle;157evt.thrown = thrown;158evt.msg = key;159evt.isLoggable = isLoggable;160evt.className = className;161evt.methodName = methodName;162return evt;163}164165}166167static java.util.logging.Level mapToJul(Level level) {168switch (level) {169case ALL: return java.util.logging.Level.ALL;170case TRACE: return java.util.logging.Level.FINER;171case DEBUG: return java.util.logging.Level.FINE;172case INFO: return java.util.logging.Level.INFO;173case WARNING: return java.util.logging.Level.WARNING;174case ERROR: return java.util.logging.Level.SEVERE;175case OFF: return java.util.logging.Level.OFF;176}177throw new InternalError("No such level: " + level);178}179180static void setLevel(java.util.logging.Logger sink, java.util.logging.Level loggerLevel) {181boolean before = allowAll.get().get();182try {183allowAll.get().set(true);184sink.setLevel(loggerLevel);185} finally {186allowAll.get().set(before);187}188}189190public static class MyHandler extends Handler {191192@Override193public java.util.logging.Level getLevel() {194return java.util.logging.Level.ALL;195}196197@Override198public void publish(LogRecord record) {199eventQueue.add(LogEvent.of(sequencer.getAndIncrement(),200true, record.getLoggerName(),201record.getSourceClassName(),202record.getSourceMethodName(),203record.getLevel(),204record.getResourceBundle(), record.getMessage(),205record.getThrown(), record.getParameters()));206}207@Override208public void flush() {209}210@Override211public void close() throws SecurityException {212}213214}215public static class MyBundle extends ResourceBundle {216217final ConcurrentHashMap<String,String> map = new ConcurrentHashMap<>();218219@Override220protected Object handleGetObject(String key) {221if (key.contains(" (translated)")) {222throw new RuntimeException("Unexpected key: " + key);223}224return map.computeIfAbsent(key, k -> k + " (translated)");225}226227@Override228public Enumeration<String> getKeys() {229return Collections.enumeration(map.keySet());230}231232}233public static class MyLoggerBundle extends MyBundle {234235}236237static final AccessSystemLogger accessSystemLogger = new AccessSystemLogger();238239static enum TestCases {NOSECURITY, NOPERMISSIONS, WITHPERMISSIONS,240WITHCUSTOMWRAPPERS, WITHREFLECTION};241242static void setSecurityManager() {243if (System.getSecurityManager() == null) {244Policy.setPolicy(new SimplePolicy(allowControl, allowAll));245System.setSecurityManager(new SecurityManager());246}247}248249/**250* The CustomLoggerWrapper makes it possible to verify that classes251* which implements System.Logger will be skipped when looking for252* the calling method.253*/254static class CustomLoggerWrapper implements Logger {255256Logger impl;257public CustomLoggerWrapper(Logger logger) {258this.impl = Objects.requireNonNull(logger);259}260261262@Override263public String getName() {264return impl.getName();265}266267@Override268public boolean isLoggable(Level level) {269return impl.isLoggable(level);270}271272@Override273public void log(Level level, ResourceBundle rb, String string, Throwable thrwbl) {274impl.log(level, rb, string, thrwbl);275}276277@Override278public void log(Level level, ResourceBundle rb, String string, Object... os) {279impl.log(level, rb, string, os);280}281282@Override283public void log(Level level, Object o) {284impl.log(level, o);285}286287@Override288public void log(Level level, String string) {289impl.log(level, string);290}291292@Override293public void log(Level level, Supplier<String> splr) {294impl.log(level, splr);295}296297@Override298public void log(Level level, String string, Object... os) {299impl.log(level, string, os);300}301302@Override303public void log(Level level, String string, Throwable thrwbl) {304impl.log(level, string, thrwbl);305}306307@Override308public void log(Level level, Supplier<String> splr, Throwable thrwbl) {309Logger.super.log(level, splr, thrwbl);310}311312@Override313public String toString() {314return super.toString() + "(impl=" + impl + ")";315}316317}318319/**320* The ReflectionLoggerWrapper additionally makes it possible to verify321* that code which use reflection to call System.Logger will be skipped322* when looking for the calling method.323*/324static class ReflectionLoggerWrapper implements Logger {325326Logger impl;327public ReflectionLoggerWrapper(Logger logger) {328this.impl = Objects.requireNonNull(logger);329}330331private Object invoke(Method m, Object... params) {332try {333return m.invoke(impl, params);334} catch (IllegalAccessException | IllegalArgumentException335| InvocationTargetException ex) {336throw new RuntimeException(ex);337}338}339340@Override341public String getName() {342return impl.getName();343}344345@Override346public boolean isLoggable(Level level) {347return impl.isLoggable(level);348}349350@Override351public void log(Level level, ResourceBundle rb, String string, Throwable thrwbl) {352try {353invoke(System.Logger.class.getMethod(354"log", Level.class, ResourceBundle.class, String.class, Throwable.class),355level, rb, string, thrwbl);356} catch (NoSuchMethodException ex) {357throw new RuntimeException(ex);358}359}360361@Override362public void log(Level level, ResourceBundle rb, String string, Object... os) {363try {364invoke(System.Logger.class.getMethod(365"log", Level.class, ResourceBundle.class, String.class, Object[].class),366level, rb, string, os);367} catch (NoSuchMethodException ex) {368throw new RuntimeException(ex);369}370}371372@Override373public void log(Level level, String string) {374try {375invoke(System.Logger.class.getMethod(376"log", Level.class, String.class),377level, string);378} catch (NoSuchMethodException ex) {379throw new RuntimeException(ex);380}381}382383@Override384public void log(Level level, String string, Object... os) {385try {386invoke(System.Logger.class.getMethod(387"log", Level.class, String.class, Object[].class),388level, string, os);389} catch (NoSuchMethodException ex) {390throw new RuntimeException(ex);391}392}393394@Override395public void log(Level level, String string, Throwable thrwbl) {396try {397invoke(System.Logger.class.getMethod(398"log", Level.class, String.class, Throwable.class),399level, string, thrwbl);400} catch (NoSuchMethodException ex) {401throw new RuntimeException(ex);402}403}404405406@Override407public String toString() {408return super.toString() + "(impl=" + impl + ")";409}410411}412413public static void main(String[] args) {414if (args.length == 0)415args = new String[] {416"NOSECURITY",417"NOPERMISSIONS",418"WITHPERMISSIONS",419"WITHCUSTOMWRAPPERS",420"WITHREFLECTION"421};422423// 1. Obtain destination loggers directly from the LoggerFinder424// - LoggerFinder.getLogger("foo", type)425426427Stream.of(args).map(TestCases::valueOf).forEach((testCase) -> {428switch (testCase) {429case NOSECURITY:430System.out.println("\n*** Without Security Manager\n");431test(true);432System.out.println("Tetscase count: " + sequencer.get());433break;434case NOPERMISSIONS:435System.out.println("\n*** With Security Manager, without permissions\n");436setSecurityManager();437test(false);438System.out.println("Tetscase count: " + sequencer.get());439break;440case WITHPERMISSIONS:441System.out.println("\n*** With Security Manager, with control permission\n");442setSecurityManager();443final boolean control = allowControl.get().get();444try {445allowControl.get().set(true);446test(true);447} finally {448allowControl.get().set(control);449}450break;451case WITHCUSTOMWRAPPERS:452System.out.println("\n*** With Security Manager, with control permission, using custom Wrappers\n");453setSecurityManager();454final boolean previous = allowControl.get().get();455try {456allowControl.get().set(true);457test(CustomLoggerWrapper::new, true);458} finally {459allowControl.get().set(previous);460}461break;462case WITHREFLECTION:463System.out.println("\n*** With Security Manager,"464+ " with control permission,"465+ " using reflection while logging\n");466setSecurityManager();467final boolean before = allowControl.get().get();468try {469allowControl.get().set(true);470test(ReflectionLoggerWrapper::new, true);471} finally {472allowControl.get().set(before);473}474break;475476default:477throw new RuntimeException("Unknown test case: " + testCase);478}479});480System.out.println("\nPASSED: Tested " + sequencer.get() + " cases.");481}482483public static void test(boolean hasRequiredPermissions) {484test(Function.identity(), hasRequiredPermissions);485}486487public static void test(Function<Logger, Logger> wrapper, boolean hasRequiredPermissions) {488489ResourceBundle loggerBundle = ResourceBundle.getBundle(MyLoggerBundle.class.getName());490final Map<Logger, String> loggerDescMap = new HashMap<>();491492493// 1. Test loggers returned by:494// - System.getLogger("foo")495// - and AccessSystemLogger.getLogger("foo")496Logger sysLogger1 = null;497try {498sysLogger1 = wrapper.apply(accessSystemLogger.getLogger("foo"));499loggerDescMap.put(sysLogger1, "AccessSystemLogger.getLogger(\"foo\")");500} catch (AccessControlException acx) {501if (hasRequiredPermissions) {502throw new RuntimeException("Unexpected security exception: ", acx);503}504if (!acx.getPermission().equals(SimplePolicy.LOGGERFINDER_PERMISSION)) {505throw new RuntimeException("Unexpected permission in exception: " + acx, acx);506}507throw new RuntimeException("unexpected exception: " + acx, acx);508}509510Logger appLogger1 = wrapper.apply(System.getLogger("foo"));511loggerDescMap.put(appLogger1, "System.getLogger(\"foo\");");512513if (appLogger1 == sysLogger1) {514throw new RuntimeException("identical loggers");515}516517// 2. Test loggers returned by:518// - System.getLogger(\"foo\", loggerBundle)519// - and AccessSystemLogger.getLogger(\"foo\", loggerBundle)520Logger appLogger2 = wrapper.apply(521System.getLogger("foo", loggerBundle));522loggerDescMap.put(appLogger2, "System.getLogger(\"foo\", loggerBundle)");523524Logger sysLogger2 = null;525try {526sysLogger2 = wrapper.apply(accessSystemLogger.getLogger("foo", loggerBundle));527loggerDescMap.put(sysLogger2, "AccessSystemLogger.getLogger(\"foo\", loggerBundle)");528} catch (AccessControlException acx) {529if (hasRequiredPermissions) {530throw new RuntimeException("Unexpected security exception: ", acx);531}532if (!acx.getPermission().equals(SimplePolicy.LOGGERFINDER_PERMISSION)) {533throw new RuntimeException("Unexpected permission in exception: " + acx, acx);534}535throw new RuntimeException("unexpected exception: " + acx, acx);536}537if (appLogger2 == sysLogger2) {538throw new RuntimeException("identical loggers");539}540541final java.util.logging.Logger sink;542final java.util.logging.Logger appSink;543final java.util.logging.Logger sysSink;544final java.util.logging.Handler appHandler;545final java.util.logging.Handler sysHandler;546final LoggerFinder provider;547allowAll.get().set(true);548try {549appSink = java.util.logging.Logger.getLogger("foo");550sysSink = accessSystemLogger.demandSystemLogger("foo");551sink = java.util.logging.Logger.getLogger("foo");552sink.addHandler(appHandler = sysHandler = new MyHandler());553sink.setUseParentHandlers(false);554provider = LoggerFinder.getLoggerFinder();555} finally {556allowAll.get().set(false);557}558try {559testLogger(provider, loggerDescMap, "foo", null, sysLogger1, sysSink);560testLogger(provider, loggerDescMap, "foo", null, appLogger1, appSink);561testLogger(provider, loggerDescMap, "foo", loggerBundle, sysLogger2, sysSink);562testLogger(provider, loggerDescMap, "foo", loggerBundle, appLogger2, appSink);563} finally {564allowAll.get().set(true);565try {566appSink.removeHandler(appHandler);567sysSink.removeHandler(sysHandler);568sysSink.setLevel(null);569appSink.setLevel(null);570} finally {571allowAll.get().set(false);572}573}574}575576public static class Foo {577578}579580static void verbose(String msg) {581if (VERBOSE) {582System.out.println(msg);583}584}585586// Calls the 8 methods defined on Logger and verify the587// parameters received by the underlying BaseLoggerFinder.LoggerImpl588// logger.589private static void testLogger(LoggerFinder provider,590Map<Logger, String> loggerDescMap,591String name,592ResourceBundle loggerBundle,593Logger logger,594java.util.logging.Logger sink) {595596System.out.println("Testing " + loggerDescMap.get(logger));597598Foo foo = new Foo();599String fooMsg = foo.toString();600for (Level loggerLevel : Level.values()) {601setLevel(sink, mapToJul(loggerLevel));602for (Level messageLevel : Level.values()) {603String desc = "logger.log(messageLevel, foo): loggerLevel="604+ loggerLevel+", messageLevel="+messageLevel;605606LogEvent expected =607LogEvent.of(608sequencer.get(),609messageLevel.compareTo(loggerLevel) >= 0,610name, mapToJul(messageLevel), (ResourceBundle)null,611fooMsg, (Throwable)null, (Object[])null);612logger.log(messageLevel, foo);613if (loggerLevel == Level.OFF || messageLevel.compareTo(loggerLevel) < 0) {614if (eventQueue.poll() != null) {615throw new RuntimeException("unexpected event in queue for " + desc);616}617} else {618LogEvent actual = eventQueue.poll();619if (!expected.equals(actual)) {620throw new RuntimeException("mismatch for " + desc621+ "\n\texpected=" + expected622+ "\n\t actual=" + actual);623} else {624verbose("Got expected results for "625+ desc + "\n\t" + expected);626}627}628}629}630631String msg = "blah";632for (Level loggerLevel : Level.values()) {633setLevel(sink, mapToJul(loggerLevel));634for (Level messageLevel : Level.values()) {635String desc = "logger.log(messageLevel, \"blah\"): loggerLevel="636+ loggerLevel+", messageLevel="+messageLevel;637LogEvent expected =638LogEvent.of(639sequencer.get(),640messageLevel.compareTo(loggerLevel) >= 0 && loggerLevel != Level.OFF,641name, mapToJul(messageLevel), loggerBundle,642msg, (Throwable)null, (Object[])null);643logger.log(messageLevel, msg);644if (loggerLevel == Level.OFF || messageLevel.compareTo(loggerLevel) < 0) {645if (eventQueue.poll() != null) {646throw new RuntimeException("unexpected event in queue for " + desc);647}648} else {649LogEvent actual = eventQueue.poll();650if (!expected.equals(actual)) {651throw new RuntimeException("mismatch for " + desc652+ "\n\texpected=" + expected653+ "\n\t actual=" + actual);654} else {655verbose("Got expected results for "656+ desc + "\n\t" + expected);657}658}659}660}661662Supplier<String> fooSupplier = new Supplier<String>() {663@Override664public String get() {665return this.toString();666}667};668669for (Level loggerLevel : Level.values()) {670setLevel(sink, mapToJul(loggerLevel));671for (Level messageLevel : Level.values()) {672String desc = "logger.log(messageLevel, fooSupplier): loggerLevel="673+ loggerLevel+", messageLevel="+messageLevel;674LogEvent expected =675LogEvent.of(676sequencer.get(),677messageLevel.compareTo(loggerLevel) >= 0,678name, mapToJul(messageLevel), (ResourceBundle)null,679fooSupplier.get(),680(Throwable)null, (Object[])null);681logger.log(messageLevel, fooSupplier);682if (loggerLevel == Level.OFF || messageLevel.compareTo(loggerLevel) < 0) {683if (eventQueue.poll() != null) {684throw new RuntimeException("unexpected event in queue for " + desc);685}686} else {687LogEvent actual = eventQueue.poll();688if (!expected.equals(actual)) {689throw new RuntimeException("mismatch for " + desc690+ "\n\texpected=" + expected691+ "\n\t actual=" + actual);692} else {693verbose("Got expected results for "694+ desc + "\n\t" + expected);695}696}697}698}699700String format = "two params [{1} {2}]";701Object arg1 = foo;702Object arg2 = msg;703for (Level loggerLevel : Level.values()) {704setLevel(sink, mapToJul(loggerLevel));705for (Level messageLevel : Level.values()) {706String desc = "logger.log(messageLevel, format, params...): loggerLevel="707+ loggerLevel+", messageLevel="+messageLevel;708LogEvent expected =709LogEvent.of(710sequencer.get(),711messageLevel.compareTo(loggerLevel) >= 0 && loggerLevel != Level.OFF,712name, mapToJul(messageLevel), loggerBundle,713format, (Throwable)null, new Object[] {arg1, arg2});714logger.log(messageLevel, format, arg1, arg2);715if (loggerLevel == Level.OFF || messageLevel.compareTo(loggerLevel) < 0) {716if (eventQueue.poll() != null) {717throw new RuntimeException("unexpected event in queue for " + desc);718}719} else {720LogEvent actual = eventQueue.poll();721if (!expected.equals(actual)) {722throw new RuntimeException("mismatch for " + desc723+ "\n\texpected=" + expected724+ "\n\t actual=" + actual);725} else {726verbose("Got expected results for "727+ desc + "\n\t" + expected);728}729}730}731}732733Throwable thrown = new Exception("OK: log me!");734for (Level loggerLevel : Level.values()) {735setLevel(sink, mapToJul(loggerLevel));736for (Level messageLevel : Level.values()) {737String desc = "logger.log(messageLevel, \"blah\", thrown): loggerLevel="738+ loggerLevel+", messageLevel="+messageLevel;739LogEvent expected =740LogEvent.of(741sequencer.get(),742messageLevel.compareTo(loggerLevel) >= 0 && loggerLevel != Level.OFF,743name, mapToJul(messageLevel), loggerBundle,744msg, thrown, (Object[]) null);745logger.log(messageLevel, msg, thrown);746if (loggerLevel == Level.OFF || messageLevel.compareTo(loggerLevel) < 0) {747if (eventQueue.poll() != null) {748throw new RuntimeException("unexpected event in queue for " + desc);749}750} else {751LogEvent actual = eventQueue.poll();752if (!expected.equals(actual)) {753throw new RuntimeException("mismatch for " + desc754+ "\n\texpected=" + expected755+ "\n\t actual=" + actual);756} else {757verbose("Got expected results for "758+ desc + "\n\t" + expected);759}760}761}762}763764765for (Level loggerLevel : Level.values()) {766setLevel(sink, mapToJul(loggerLevel));767for (Level messageLevel : Level.values()) {768String desc = "logger.log(messageLevel, thrown, fooSupplier): loggerLevel="769+ loggerLevel+", messageLevel="+messageLevel;770LogEvent expected =771LogEvent.of(772sequencer.get(),773messageLevel.compareTo(loggerLevel) >= 0,774name, mapToJul(messageLevel), (ResourceBundle)null,775fooSupplier.get(),776(Throwable)thrown, (Object[])null);777logger.log(messageLevel, fooSupplier, thrown);778if (loggerLevel == Level.OFF || messageLevel.compareTo(loggerLevel) < 0) {779if (eventQueue.poll() != null) {780throw new RuntimeException("unexpected event in queue for " + desc);781}782} else {783LogEvent actual = eventQueue.poll();784if (!expected.equals(actual)) {785throw new RuntimeException("mismatch for " + desc786+ "\n\texpected=" + expected787+ "\n\t actual=" + actual);788} else {789verbose("Got expected results for "790+ desc + "\n\t" + expected);791}792}793}794}795796ResourceBundle bundle = ResourceBundle.getBundle(MyBundle.class.getName());797for (Level loggerLevel : Level.values()) {798setLevel(sink, mapToJul(loggerLevel));799for (Level messageLevel : Level.values()) {800String desc = "logger.log(messageLevel, bundle, format, params...): loggerLevel="801+ loggerLevel+", messageLevel="+messageLevel;802LogEvent expected =803LogEvent.of(804sequencer.get(),805messageLevel.compareTo(loggerLevel) >= 0 && loggerLevel != Level.OFF,806name, mapToJul(messageLevel), bundle,807format, (Throwable)null, new Object[] {foo, msg});808logger.log(messageLevel, bundle, format, foo, msg);809if (loggerLevel == Level.OFF || messageLevel.compareTo(loggerLevel) < 0) {810if (eventQueue.poll() != null) {811throw new RuntimeException("unexpected event in queue for " + desc);812}813} else {814LogEvent actual = eventQueue.poll();815if (!expected.equals(actual)) {816throw new RuntimeException("mismatch for " + desc817+ "\n\texpected=" + expected818+ "\n\t actual=" + actual);819} else {820verbose("Got expected results for "821+ desc + "\n\t" + expected);822}823}824}825}826827for (Level loggerLevel : Level.values()) {828setLevel(sink, mapToJul(loggerLevel));829for (Level messageLevel : Level.values()) {830String desc = "logger.log(messageLevel, bundle, \"blah\", thrown): loggerLevel="831+ loggerLevel+", messageLevel="+messageLevel;832LogEvent expected =833LogEvent.of(834sequencer.get(),835messageLevel.compareTo(loggerLevel) >= 0 && loggerLevel != Level.OFF,836name, mapToJul(messageLevel), bundle,837msg, thrown, (Object[]) null);838logger.log(messageLevel, bundle, msg, thrown);839if (loggerLevel == Level.OFF || messageLevel.compareTo(loggerLevel) < 0) {840if (eventQueue.poll() != null) {841throw new RuntimeException("unexpected event in queue for " + desc);842}843} else {844LogEvent actual = eventQueue.poll();845if (!expected.equals(actual)) {846throw new RuntimeException("mismatch for " + desc847+ "\n\texpected=" + expected848+ "\n\t actual=" + actual);849} else {850verbose("Got expected results for "851+ desc + "\n\t" + expected);852}853}854}855}856}857858final static class PermissionsBuilder {859final Permissions perms;860public PermissionsBuilder() {861this(new Permissions());862}863public PermissionsBuilder(Permissions perms) {864this.perms = perms;865}866public PermissionsBuilder add(Permission p) {867perms.add(p);868return this;869}870public PermissionsBuilder addAll(PermissionCollection col) {871if (col != null) {872for (Enumeration<Permission> e = col.elements(); e.hasMoreElements(); ) {873perms.add(e.nextElement());874}875}876return this;877}878public Permissions toPermissions() {879final PermissionsBuilder builder = new PermissionsBuilder();880builder.addAll(perms);881return builder.perms;882}883}884885public static class SimplePolicy extends Policy {886887static final Policy DEFAULT_POLICY = Policy.getPolicy();888889static final RuntimePermission LOGGERFINDER_PERMISSION =890new RuntimePermission("loggerFinder");891final Permissions permissions;892final Permissions allPermissions;893final Permissions controlPermissions;894final ThreadLocal<AtomicBoolean> allowControl;895final ThreadLocal<AtomicBoolean> allowAll;896public SimplePolicy(ThreadLocal<AtomicBoolean> allowControl, ThreadLocal<AtomicBoolean> allowAll) {897this.allowControl = allowControl;898this.allowAll = allowAll;899permissions = new Permissions();900901// these are used for configuring the test itself...902controlPermissions = new Permissions();903controlPermissions.add(LOGGERFINDER_PERMISSION);904allPermissions = new Permissions();905allPermissions.add(new java.security.AllPermission());906907}908909@Override910public boolean implies(ProtectionDomain domain, Permission permission) {911if (allowAll.get().get()) return allPermissions.implies(permission);912if (allowControl.get().get()) return controlPermissions.implies(permission);913return permissions.implies(permission) || DEFAULT_POLICY.implies(domain, permission);914}915916@Override917public PermissionCollection getPermissions(CodeSource codesource) {918return new PermissionsBuilder().addAll(allowAll.get().get()919? allPermissions : allowControl.get().get()920? controlPermissions : permissions).toPermissions();921}922923@Override924public PermissionCollection getPermissions(ProtectionDomain domain) {925return new PermissionsBuilder().addAll(allowAll.get().get()926? allPermissions : allowControl.get().get()927? controlPermissions : permissions).toPermissions();928}929}930}931932933