1 /*
2  * Copyright (c) 2015, 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.security.AccessControlException;
24 import java.security.CodeSource;
25 import java.security.Permission;
26 import java.security.PermissionCollection;
27 import java.security.Permissions;
28 import java.security.Policy;
29 import java.security.ProtectionDomain;
30 import java.util.Collections;
31 import java.util.Enumeration;
32 import java.util.HashMap;
33 import java.util.Map;
34 import java.util.ResourceBundle;
35 import java.util.stream.Stream;
36 import java.util.concurrent.ConcurrentHashMap;
37 import java.util.concurrent.atomic.AtomicBoolean;
38 import java.util.concurrent.atomic.AtomicLong;
39 import java.util.function.Supplier;
40 import java.lang.System.LoggerFinder;
41 import java.lang.System.Logger;
42 import java.lang.System.Logger.Level;
43 
44 /**
45  * @test
46  * @bug     8140364
47  * @summary Tests a naive implementation of LoggerFinder, and in particular
48  *   the default body of System.Logger methods.
49  * @build AccessSystemLogger BaseLoggerFinderTest CustomSystemClassLoader BaseLoggerFinder TestLoggerFinder
50  * @run  driver AccessSystemLogger
51  * @run  main/othervm -Xbootclasspath/a:boot -Djava.system.class.loader=CustomSystemClassLoader BaseLoggerFinderTest NOSECURITY
52  * @run  main/othervm -Xbootclasspath/a:boot -Djava.system.class.loader=CustomSystemClassLoader BaseLoggerFinderTest NOPERMISSIONS
53  * @run  main/othervm -Xbootclasspath/a:boot -Djava.system.class.loader=CustomSystemClassLoader BaseLoggerFinderTest WITHPERMISSIONS
54  * @author danielfuchs
55  */
56 public class BaseLoggerFinderTest {
57 
58     static final RuntimePermission LOGGERFINDER_PERMISSION =
59                 new RuntimePermission("loggerFinder");
60     final static boolean VERBOSE = false;
61     static final ThreadLocal<AtomicBoolean> allowControl = new ThreadLocal<AtomicBoolean>() {
62         @Override
63         protected AtomicBoolean initialValue() {
64             return  new AtomicBoolean(false);
65         }
66     };
67     static final ThreadLocal<AtomicBoolean> allowAccess = new ThreadLocal<AtomicBoolean>() {
68         @Override
69         protected AtomicBoolean initialValue() {
70             return  new AtomicBoolean(false);
71         }
72     };
73 
74     final static AccessSystemLogger accessSystemLogger = new AccessSystemLogger();
75     static final Class<?> providerClass;
76     static {
77         try {
78             providerClass = ClassLoader.getSystemClassLoader().loadClass("BaseLoggerFinder");
79         } catch (ClassNotFoundException ex) {
80             throw new ExceptionInInitializerError(ex);
81         }
82     }
83 
84     public static class MyBundle extends ResourceBundle {
85 
86         final ConcurrentHashMap<String,String> map = new ConcurrentHashMap<>();
87 
88         @Override
handleGetObject(String key)89         protected Object handleGetObject(String key) {
90             if (key.contains(" (translated)")) {
91                 throw new RuntimeException("Unexpected key: " + key);
92             }
93             return map.computeIfAbsent(key, k -> k + " (translated)");
94         }
95 
96         @Override
getKeys()97         public Enumeration<String> getKeys() {
98             return Collections.enumeration(map.keySet());
99         }
100 
101     }
102     public static class MyLoggerBundle extends MyBundle {
103 
104     }
105 
106     static enum TestCases {NOSECURITY, NOPERMISSIONS, WITHPERMISSIONS};
107 
setSecurityManager()108     static void setSecurityManager() {
109         if (System.getSecurityManager() == null) {
110             Policy.setPolicy(new SimplePolicy(allowControl, allowAccess));
111             System.setSecurityManager(new SecurityManager());
112         }
113     }
114 
main(String[] args)115     public static void main(String[] args) {
116         if (args.length == 0)
117             args = new String[] {
118                 //"NOSECURITY",
119                 "NOPERMISSIONS",
120                 "WITHPERMISSIONS"
121             };
122 
123         System.out.println("Using provider class: " + providerClass + "[" + providerClass.getClassLoader() + "]");
124 
125         Stream.of(args).map(TestCases::valueOf).forEach((testCase) -> {
126             TestLoggerFinder provider;
127             switch (testCase) {
128                 case NOSECURITY:
129                     System.out.println("\n*** Without Security Manager\n");
130                     provider = TestLoggerFinder.class.cast(LoggerFinder.getLoggerFinder());
131                     test(provider, true);
132                     System.out.println("Tetscase count: " + TestLoggerFinder.sequencer.get());
133                     break;
134                 case NOPERMISSIONS:
135                     System.out.println("\n*** With Security Manager, without permissions\n");
136                     setSecurityManager();
137                     try {
138                         provider = TestLoggerFinder.class.cast(LoggerFinder.getLoggerFinder());
139                         throw new RuntimeException("Expected exception not raised");
140                     } catch (AccessControlException x) {
141                         if (!LOGGERFINDER_PERMISSION.equals(x.getPermission())) {
142                             throw new RuntimeException("Unexpected permission check", x);
143                         }
144                         final boolean control = allowControl.get().get();
145                         try {
146                             allowControl.get().set(true);
147                             provider = TestLoggerFinder.class.cast(LoggerFinder.getLoggerFinder());
148                         } finally {
149                             allowControl.get().set(control);
150                         }
151                     }
152                     test(provider, false);
153                     System.out.println("Tetscase count: " + TestLoggerFinder.sequencer.get());
154                     break;
155                 case WITHPERMISSIONS:
156                     System.out.println("\n*** With Security Manager, with control permission\n");
157                     setSecurityManager();
158                     final boolean control = allowControl.get().get();
159                     try {
160                         allowControl.get().set(true);
161                         provider = TestLoggerFinder.class.cast(LoggerFinder.getLoggerFinder());
162                         test(provider, true);
163                     } finally {
164                         allowControl.get().set(control);
165                     }
166                     break;
167                 default:
168                     throw new RuntimeException("Unknown test case: " + testCase);
169             }
170         });
171         System.out.println("\nPASSED: Tested " + TestLoggerFinder.sequencer.get() + " cases.");
172     }
173 
test(TestLoggerFinder provider, boolean hasRequiredPermissions)174     public static void test(TestLoggerFinder provider, boolean hasRequiredPermissions) {
175 
176         ResourceBundle loggerBundle = ResourceBundle.getBundle(MyLoggerBundle.class.getName());
177         final Map<Logger, String> loggerDescMap = new HashMap<>();
178 
179 
180         // 1. Test loggers returned by LoggerFinder, both for system callers
181         //    and not system callers.
182         TestLoggerFinder.LoggerImpl appLogger1 = null;
183         try {
184             appLogger1 =
185                 TestLoggerFinder.LoggerImpl.class.cast(provider.getLogger("foo", BaseLoggerFinderTest.class.getModule()));
186             loggerDescMap.put(appLogger1, "provider.getLogger(\"foo\", BaseLoggerFinderTest.class.getModule())");
187             if (!hasRequiredPermissions) {
188                 throw new RuntimeException("Managed to obtain a logger without permission");
189             }
190         } catch (AccessControlException acx) {
191             if (hasRequiredPermissions) {
192                 throw new RuntimeException("Unexpected security exception: ", acx);
193             }
194             if (!acx.getPermission().equals(LOGGERFINDER_PERMISSION)) {
195                 throw new RuntimeException("Unexpected permission in exception: " + acx, acx);
196             }
197             System.out.println("Got expected exception for logger: " + acx);
198             final boolean old = allowControl.get().get();
199             allowControl.get().set(true);
200             try {
201                 appLogger1 =
202                     TestLoggerFinder.LoggerImpl.class.cast(provider.getLogger("foo", BaseLoggerFinderTest.class.getModule()));
203                     loggerDescMap.put(appLogger1, "provider.getLogger(\"foo\", BaseLoggerFinderTest.class.getModule())");
204             } finally {
205                 allowControl.get().set(old);
206             }
207         }
208 
209         TestLoggerFinder.LoggerImpl sysLogger1 = null;
210         try {
211             sysLogger1 = TestLoggerFinder.LoggerImpl.class.cast(provider.getLogger("foo", Thread.class.getModule()));
212             loggerDescMap.put(sysLogger1, "provider.getLogger(\"foo\", Thread.class.getModule())");
213             if (!hasRequiredPermissions) {
214                 throw new RuntimeException("Managed to obtain a system logger without permission");
215             }
216         } catch (AccessControlException acx) {
217             if (hasRequiredPermissions) {
218                 throw new RuntimeException("Unexpected security exception: ", acx);
219             }
220             if (!acx.getPermission().equals(LOGGERFINDER_PERMISSION)) {
221                 throw new RuntimeException("Unexpected permission in exception: " + acx, acx);
222             }
223             System.out.println("Got expected exception for system logger: " + acx);
224             final boolean old = allowControl.get().get();
225             allowControl.get().set(true);
226             try {
227                 sysLogger1 = TestLoggerFinder.LoggerImpl.class.cast(provider.getLogger("foo", Thread.class.getModule()));
228                 loggerDescMap.put(sysLogger1, "provider.getLogger(\"foo\", Thread.class.getModule())");
229             } finally {
230                 allowControl.get().set(old);
231             }
232         }
233         if (appLogger1 == sysLogger1) {
234             throw new RuntimeException("identical loggers");
235         }
236 
237         if (provider.system.contains(appLogger1)) {
238             throw new RuntimeException("app logger in system map");
239         }
240         if (!provider.user.contains(appLogger1)) {
241             throw new RuntimeException("app logger not in appplication map");
242         }
243         if (provider.user.contains(sysLogger1)) {
244             throw new RuntimeException("sys logger in appplication map");
245         }
246         if (!provider.system.contains(sysLogger1)) {
247             throw new RuntimeException("sys logger not in system map");
248         }
249 
250         testLogger(provider, loggerDescMap, "foo", null, appLogger1, appLogger1);
251         testLogger(provider, loggerDescMap, "foo", null, sysLogger1, sysLogger1);
252 
253         // 2. Test localized loggers returned LoggerFinder, both for system
254         //   callers and non system callers
255         Logger appLogger2 = null;
256         try {
257             appLogger2 = provider.getLocalizedLogger("foo", loggerBundle, BaseLoggerFinderTest.class.getModule());
258             loggerDescMap.put(appLogger2, "provider.getLocalizedLogger(\"foo\", loggerBundle, BaseLoggerFinderTest.class.getModule())");
259             if (!hasRequiredPermissions) {
260                 throw new RuntimeException("Managed to obtain a logger without permission");
261             }
262         } catch (AccessControlException acx) {
263             if (hasRequiredPermissions) {
264                 throw new RuntimeException("Unexpected security exception: ", acx);
265             }
266             if (!acx.getPermission().equals(LOGGERFINDER_PERMISSION)) {
267                 throw new RuntimeException("Unexpected permission in exception: " + acx, acx);
268             }
269             System.out.println("Got expected exception for logger: " + acx);
270             final boolean old = allowControl.get().get();
271             allowControl.get().set(true);
272             try {
273                 appLogger2 = provider.getLocalizedLogger("foo", loggerBundle, BaseLoggerFinderTest.class.getModule());
274                 loggerDescMap.put(appLogger2, "provider.getLocalizedLogger(\"foo\", loggerBundle, BaseLoggerFinderTest.class.getModule())");
275             } finally {
276                 allowControl.get().set(old);
277             }
278         }
279 
280         Logger sysLogger2 = null;
281         try {
282             sysLogger2 = provider.getLocalizedLogger("foo", loggerBundle, Thread.class.getModule());
283             loggerDescMap.put(sysLogger2, "provider.getLocalizedLogger(\"foo\", loggerBundle, Thread.class.getModule())");
284             if (!hasRequiredPermissions) {
285                 throw new RuntimeException("Managed to obtain a system logger without permission");
286             }
287         } catch (AccessControlException acx) {
288             if (hasRequiredPermissions) {
289                 throw new RuntimeException("Unexpected security exception: ", acx);
290             }
291             if (!acx.getPermission().equals(LOGGERFINDER_PERMISSION)) {
292                 throw new RuntimeException("Unexpected permission in exception: " + acx, acx);
293             }
294             System.out.println("Got expected exception for localized system logger: " + acx);
295             final boolean old = allowControl.get().get();
296             allowControl.get().set(true);
297             try {
298                 sysLogger2 = provider.getLocalizedLogger("foo", loggerBundle, Thread.class.getModule());
299                 loggerDescMap.put(sysLogger2, "provider.getLocalizedLogger(\"foo\", loggerBundle, Thread.class.getModule()))");
300             } finally {
301                 allowControl.get().set(old);
302             }
303         }
304         if (appLogger2 == sysLogger2) {
305             throw new RuntimeException("identical loggers");
306         }
307         if (appLogger2 == appLogger1) {
308             throw new RuntimeException("identical loggers");
309         }
310         if (sysLogger2 == sysLogger1) {
311             throw new RuntimeException("identical loggers");
312         }
313 
314         if (provider.system.contains(appLogger2)) {
315             throw new RuntimeException("localized app logger in system map");
316         }
317         if (provider.user.contains(appLogger2)) {
318             throw new RuntimeException("localized app logger  in appplication map");
319         }
320         if (provider.user.contains(sysLogger2)) {
321             throw new RuntimeException("localized sys logger in appplication map");
322         }
323         if (provider.system.contains(sysLogger2)) {
324             throw new RuntimeException("localized sys logger not in system map");
325         }
326 
327         testLogger(provider, loggerDescMap, "foo", loggerBundle, appLogger2, appLogger1);
328         testLogger(provider, loggerDescMap, "foo", loggerBundle, sysLogger2, sysLogger1);
329 
330         // 3 Test loggers returned by:
331         //   3.1: System.getLogger("foo")
332         Logger appLogger3 = System.getLogger("foo");
333         loggerDescMap.put(appLogger3, "System.getLogger(\"foo\")");
334         testLogger(provider, loggerDescMap, "foo", null, appLogger3, appLogger1);
335 
336         //   3.2: System.getLogger("foo")
337         //        Emulate what System.getLogger() does when the caller is a
338         //        platform classes
339         Logger sysLogger3 = accessSystemLogger.getLogger("foo");
340         loggerDescMap.put(sysLogger3, "AccessSystemLogger.getLogger(\"foo\")");
341 
342         if (appLogger3 == sysLogger3) {
343             throw new RuntimeException("identical loggers");
344         }
345 
346         testLogger(provider, loggerDescMap, "foo", null, sysLogger3, sysLogger1);
347 
348         // 4. Test loggers returned by:
349         //    4.1 System.getLogger("foo", loggerBundle)
350         Logger appLogger4 =
351                 System.getLogger("foo", loggerBundle);
352         loggerDescMap.put(appLogger4, "System.getLogger(\"foo\", loggerBundle)");
353         if (appLogger4 == appLogger1) {
354             throw new RuntimeException("identical loggers");
355         }
356 
357         testLogger(provider, loggerDescMap, "foo", loggerBundle, appLogger4, appLogger1);
358 
359         //   4.2: System.getLogger("foo", loggerBundle)
360         //        Emulate what System.getLogger() does when the caller is a
361         //        platform classes
362         Logger sysLogger4 = accessSystemLogger.getLogger("foo", loggerBundle);
363         loggerDescMap.put(sysLogger4, "AccessSystemLogger.getLogger(\"foo\", loggerBundle)");
364         if (appLogger4 == sysLogger4) {
365             throw new RuntimeException("identical loggers");
366         }
367 
368         testLogger(provider, loggerDescMap, "foo", loggerBundle, sysLogger4, sysLogger1);
369 
370     }
371 
372     public static class Foo {
373 
374     }
375 
verbose(String msg)376     static void verbose(String msg) {
377        if (VERBOSE) {
378            System.out.println(msg);
379        }
380     }
381 
382     // Calls the 8 methods defined on Logger and verify the
383     // parameters received by the underlying TestProvider.LoggerImpl
384     // logger.
testLogger(TestLoggerFinder provider, Map<Logger, String> loggerDescMap, String name, ResourceBundle loggerBundle, Logger logger, TestLoggerFinder.LoggerImpl sink)385     private static void testLogger(TestLoggerFinder provider,
386             Map<Logger, String> loggerDescMap,
387             String name,
388             ResourceBundle loggerBundle,
389             Logger logger,
390             TestLoggerFinder.LoggerImpl sink) {
391 
392         System.out.println("Testing " + loggerDescMap.get(logger) + " [" + logger +"]");
393         AtomicLong sequencer = TestLoggerFinder.sequencer;
394 
395         Foo foo = new Foo();
396         String fooMsg = foo.toString();
397         for (Level loggerLevel : Level.values()) {
398             sink.level = loggerLevel;
399             for (Level messageLevel : Level.values()) {
400                 String desc = "logger.log(messageLevel, foo): loggerLevel="
401                         + loggerLevel+", messageLevel="+messageLevel;
402                 TestLoggerFinder.LogEvent expected =
403                         TestLoggerFinder.LogEvent.of(
404                             sequencer.get(),
405                             messageLevel.compareTo(loggerLevel) >= 0,
406                             name, messageLevel, (ResourceBundle)null,
407                             fooMsg, null, (Throwable)null, (Object[])null);
408                 logger.log(messageLevel, foo);
409                 if (loggerLevel == Level.OFF || messageLevel.compareTo(loggerLevel) < 0) {
410                     if (provider.eventQueue.poll() != null) {
411                         throw new RuntimeException("unexpected event in queue for " + desc);
412                     }
413                 } else {
414                     TestLoggerFinder.LogEvent actual =  provider.eventQueue.poll();
415                     if (!expected.equals(actual)) {
416                         throw new RuntimeException("mismatch for " + desc
417                                 + "\n\texpected=" + expected
418                                 + "\n\t  actual=" + actual);
419                     } else {
420                         verbose("Got expected results for "
421                                 + desc + "\n\t" + expected);
422                     }
423                 }
424             }
425         }
426 
427         String msg = "blah";
428         for (Level loggerLevel : Level.values()) {
429             sink.level = loggerLevel;
430             for (Level messageLevel : Level.values()) {
431                 String desc = "logger.log(messageLevel, \"blah\"): loggerLevel="
432                         + loggerLevel+", messageLevel="+messageLevel;
433                 TestLoggerFinder.LogEvent expected =
434                         TestLoggerFinder.LogEvent.of(
435                             sequencer.get(),
436                             messageLevel.compareTo(loggerLevel) >= 0 && loggerLevel != Level.OFF,
437                             name, messageLevel, loggerBundle,
438                             msg, null, (Throwable)null, (Object[])null);
439                 logger.log(messageLevel, msg);
440                 TestLoggerFinder.LogEvent actual =  provider.eventQueue.poll();
441                 if (!expected.equals(actual)) {
442                     throw new RuntimeException("mismatch for " + desc
443                             + "\n\texpected=" + expected
444                             + "\n\t  actual=" + actual);
445                 } else {
446                     verbose("Got expected results for "
447                             + desc + "\n\t" + expected);
448                 }
449             }
450         }
451 
452         Supplier<String> fooSupplier = new Supplier<String>() {
453             @Override
454             public String get() {
455                 return this.toString();
456             }
457         };
458 
459         for (Level loggerLevel : Level.values()) {
460             sink.level = loggerLevel;
461             for (Level messageLevel : Level.values()) {
462                 String desc = "logger.log(messageLevel, fooSupplier): loggerLevel="
463                         + loggerLevel+", messageLevel="+messageLevel;
464                 TestLoggerFinder.LogEvent expected =
465                         TestLoggerFinder.LogEvent.of(
466                             sequencer.get(),
467                             messageLevel.compareTo(loggerLevel) >= 0,
468                             name, messageLevel, (ResourceBundle)null,
469                             fooSupplier.get(), null,
470                             (Throwable)null, (Object[])null);
471                 logger.log(messageLevel, fooSupplier);
472                 if (loggerLevel == Level.OFF || messageLevel.compareTo(loggerLevel) < 0) {
473                     if (provider.eventQueue.poll() != null) {
474                         throw new RuntimeException("unexpected event in queue for " + desc);
475                     }
476                 } else {
477                     TestLoggerFinder.LogEvent actual =  provider.eventQueue.poll();
478                     if (!expected.equals(actual)) {
479                         throw new RuntimeException("mismatch for " + desc
480                                 + "\n\texpected=" + expected
481                                 + "\n\t  actual=" + actual);
482                     } else {
483                         verbose("Got expected results for "
484                                 + desc + "\n\t" + expected);
485                     }
486                 }
487             }
488         }
489 
490         String format = "two params [{1} {2}]";
491         Object arg1 = foo;
492         Object arg2 = msg;
493         for (Level loggerLevel : Level.values()) {
494             sink.level = loggerLevel;
495             for (Level messageLevel : Level.values()) {
496                 String desc = "logger.log(messageLevel, format, params...): loggerLevel="
497                         + loggerLevel+", messageLevel="+messageLevel;
498                 TestLoggerFinder.LogEvent expected =
499                         TestLoggerFinder.LogEvent.of(
500                             sequencer.get(),
501                             messageLevel.compareTo(loggerLevel) >= 0 && loggerLevel != Level.OFF,
502                             name, messageLevel, loggerBundle,
503                             format, null, (Throwable)null, new Object[] {foo, msg});
504                 logger.log(messageLevel, format, foo, msg);
505                 TestLoggerFinder.LogEvent actual =  provider.eventQueue.poll();
506                 if (!expected.equals(actual)) {
507                     throw new RuntimeException("mismatch for " + desc
508                             + "\n\texpected=" + expected
509                             + "\n\t  actual=" + actual);
510                 } else {
511                     verbose("Got expected results for "
512                             + desc + "\n\t" + expected);
513                 }
514             }
515         }
516 
517         Throwable thrown = new Exception("OK: log me!");
518         for (Level loggerLevel : Level.values()) {
519             sink.level = loggerLevel;
520             for (Level messageLevel : Level.values()) {
521                 String desc = "logger.log(messageLevel, \"blah\", thrown): loggerLevel="
522                         + loggerLevel+", messageLevel="+messageLevel;
523                 TestLoggerFinder.LogEvent expected =
524                         TestLoggerFinder.LogEvent.of(
525                             sequencer.get(),
526                             messageLevel.compareTo(loggerLevel) >= 0 && loggerLevel != Level.OFF,
527                             name, messageLevel, loggerBundle,
528                             msg, null, thrown, (Object[]) null);
529                 logger.log(messageLevel, msg, thrown);
530                 TestLoggerFinder.LogEvent actual =  provider.eventQueue.poll();
531                 if (!expected.equals(actual)) {
532                     throw new RuntimeException("mismatch for " + desc
533                             + "\n\texpected=" + expected
534                             + "\n\t  actual=" + actual);
535                 } else {
536                     verbose("Got expected results for "
537                             + desc + "\n\t" + expected);
538                 }
539             }
540         }
541 
542 
543         for (Level loggerLevel : Level.values()) {
544             sink.level = loggerLevel;
545             for (Level messageLevel : Level.values()) {
546                 String desc = "logger.log(messageLevel, thrown, fooSupplier): loggerLevel="
547                         + loggerLevel+", messageLevel="+messageLevel;
548                 TestLoggerFinder.LogEvent expected =
549                         TestLoggerFinder.LogEvent.of(
550                             sequencer.get(),
551                             messageLevel.compareTo(loggerLevel) >= 0,
552                             name, messageLevel, (ResourceBundle)null,
553                             fooSupplier.get(), null,
554                             (Throwable)thrown, (Object[])null);
555                 logger.log(messageLevel, fooSupplier, thrown);
556                 if (loggerLevel == Level.OFF || messageLevel.compareTo(loggerLevel) < 0) {
557                     if (provider.eventQueue.poll() != null) {
558                         throw new RuntimeException("unexpected event in queue for " + desc);
559                     }
560                 } else {
561                     TestLoggerFinder.LogEvent actual =  provider.eventQueue.poll();
562                     if (!expected.equals(actual)) {
563                         throw new RuntimeException("mismatch for " + desc
564                                 + "\n\texpected=" + expected
565                                 + "\n\t  actual=" + actual);
566                     } else {
567                         verbose("Got expected results for "
568                                 + desc + "\n\t" + expected);
569                     }
570                 }
571             }
572         }
573 
574         ResourceBundle bundle = ResourceBundle.getBundle(MyBundle.class.getName());
575         for (Level loggerLevel : Level.values()) {
576             sink.level = loggerLevel;
577             for (Level messageLevel : Level.values()) {
578                 String desc = "logger.log(messageLevel, bundle, format, params...): loggerLevel="
579                         + loggerLevel+", messageLevel="+messageLevel;
580                 TestLoggerFinder.LogEvent expected =
581                         TestLoggerFinder.LogEvent.of(
582                             sequencer.get(),
583                             messageLevel.compareTo(loggerLevel) >= 0 && loggerLevel != Level.OFF,
584                             name, messageLevel, bundle,
585                             format, null, (Throwable)null, new Object[] {foo, msg});
586                 logger.log(messageLevel, bundle, format, foo, msg);
587                 TestLoggerFinder.LogEvent actual =  provider.eventQueue.poll();
588                 if (!expected.equals(actual)) {
589                     throw new RuntimeException("mismatch for " + desc
590                             + "\n\texpected=" + expected
591                             + "\n\t  actual=" + actual);
592                 } else {
593                     verbose("Got expected results for "
594                             + desc + "\n\t" + expected);
595                 }
596             }
597         }
598 
599         for (Level loggerLevel : Level.values()) {
600             sink.level = loggerLevel;
601             for (Level messageLevel : Level.values()) {
602                 String desc = "logger.log(messageLevel, bundle, \"blah\", thrown): loggerLevel="
603                         + loggerLevel+", messageLevel="+messageLevel;
604                 TestLoggerFinder.LogEvent expected =
605                         TestLoggerFinder.LogEvent.of(
606                             sequencer.get(),
607                             messageLevel.compareTo(loggerLevel) >= 0 && loggerLevel != Level.OFF,
608                             name, messageLevel, bundle,
609                             msg, null, thrown, (Object[]) null);
610                 logger.log(messageLevel, bundle, msg, thrown);
611                 TestLoggerFinder.LogEvent actual =  provider.eventQueue.poll();
612                 if (!expected.equals(actual)) {
613                     throw new RuntimeException("mismatch for " + desc
614                             + "\n\texpected=" + expected
615                             + "\n\t  actual=" + actual);
616                 } else {
617                     verbose("Got expected results for "
618                             + desc + "\n\t" + expected);
619                 }
620             }
621         }
622     }
623 
624     final static class PermissionsBuilder {
625         final Permissions perms;
PermissionsBuilder()626         public PermissionsBuilder() {
627             this(new Permissions());
628         }
PermissionsBuilder(Permissions perms)629         public PermissionsBuilder(Permissions perms) {
630             this.perms = perms;
631         }
add(Permission p)632         public PermissionsBuilder add(Permission p) {
633             perms.add(p);
634             return this;
635         }
addAll(PermissionCollection col)636         public PermissionsBuilder addAll(PermissionCollection col) {
637             if (col != null) {
638                 for (Enumeration<Permission> e = col.elements(); e.hasMoreElements(); ) {
639                     perms.add(e.nextElement());
640                 }
641             }
642             return this;
643         }
toPermissions()644         public Permissions toPermissions() {
645             final PermissionsBuilder builder = new PermissionsBuilder();
646             builder.addAll(perms);
647             return builder.perms;
648         }
649     }
650 
651     public static class SimplePolicy extends Policy {
652         final static RuntimePermission CONTROL = LOGGERFINDER_PERMISSION;
653         final static RuntimePermission ACCESS = new RuntimePermission("accessClassInPackage.jdk.internal.logger");
654 
655         final Permissions permissions;
656         final ThreadLocal<AtomicBoolean> allowControl;
657         final ThreadLocal<AtomicBoolean> allowAccess;
SimplePolicy(ThreadLocal<AtomicBoolean> allowControl, ThreadLocal<AtomicBoolean> allowAccess)658         public SimplePolicy(ThreadLocal<AtomicBoolean> allowControl, ThreadLocal<AtomicBoolean> allowAccess) {
659             this.allowControl = allowControl;
660             this.allowAccess = allowAccess;
661             permissions = new Permissions();
662         }
663 
getPermissions()664         Permissions getPermissions() {
665             if (allowControl.get().get() || allowAccess.get().get()) {
666                 PermissionsBuilder builder =  new PermissionsBuilder()
667                         .addAll(permissions);
668                 if (allowControl.get().get()) {
669                     builder.add(CONTROL);
670                 }
671                 if (allowAccess.get().get()) {
672                     builder.add(ACCESS);
673                 }
674                 return builder.toPermissions();
675             }
676             return permissions;
677         }
678 
679         @Override
implies(ProtectionDomain domain, Permission permission)680         public boolean implies(ProtectionDomain domain, Permission permission) {
681             return getPermissions().implies(permission);
682         }
683 
684         @Override
getPermissions(CodeSource codesource)685         public PermissionCollection getPermissions(CodeSource codesource) {
686             return new PermissionsBuilder().addAll(getPermissions()).toPermissions();
687         }
688 
689         @Override
getPermissions(ProtectionDomain domain)690         public PermissionCollection getPermissions(ProtectionDomain domain) {
691             return new PermissionsBuilder().addAll(getPermissions()).toPermissions();
692         }
693     }
694 }
695