1/*
2 * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 */
23
24import java.security.CodeSource;
25import java.security.Permission;
26import java.security.PermissionCollection;
27import java.security.Permissions;
28import java.security.Policy;
29import java.security.ProtectionDomain;
30import java.util.EnumSet;
31import java.util.HashMap;
32import java.util.Map;
33import java.util.logging.LogManager;
34import java.util.logging.Logger;
35import java.util.logging.LoggingPermission;
36import jdk.internal.misc.JavaAWTAccess;
37import jdk.internal.misc.SharedSecrets;
38
39/*
40 * @test
41 * @bug 8017174 8010727 8019945
42 * @summary  NPE when using Logger.getAnonymousLogger or
43 *           LogManager.getLogManager().getLogger
44 *
45 * @modules java.base/jdk.internal.misc
46 *          java.logging
47 * @run main/othervm -Dtest.security=off TestAppletLoggerContext LoadingApplet
48 * @run main/othervm -Dtest.security=on TestAppletLoggerContext  LoadingApplet
49 * @run main/othervm -Dtest.security=off TestAppletLoggerContext LoadingMain
50 * @run main/othervm -Dtest.security=on TestAppletLoggerContext  LoadingMain
51 * @run main/othervm -Dtest.security=off TestAppletLoggerContext One
52 * @run main/othervm -Dtest.security=on TestAppletLoggerContext  One
53 * @run main/othervm -Dtest.security=off TestAppletLoggerContext Two
54 * @run main/othervm -Dtest.security=on TestAppletLoggerContext  Two
55 * @run main/othervm -Dtest.security=off TestAppletLoggerContext Three
56 * @run main/othervm -Dtest.security=on TestAppletLoggerContext  Three
57 * @run main/othervm -Dtest.security=off TestAppletLoggerContext Four
58 * @run main/othervm -Dtest.security=on TestAppletLoggerContext  Four
59 * @run main/othervm -Dtest.security=off TestAppletLoggerContext Five
60 * @run main/othervm -Dtest.security=on TestAppletLoggerContext  Five
61 * @run main/othervm -Dtest.security=off TestAppletLoggerContext Six
62 * @run main/othervm -Dtest.security=on TestAppletLoggerContext  Six
63 * @run main/othervm -Dtest.security=off TestAppletLoggerContext Seven
64 * @run main/othervm -Dtest.security=on TestAppletLoggerContext  Seven
65 * @run main/othervm -Dtest.security=off TestAppletLoggerContext
66 * @run main/othervm -Dtest.security=on TestAppletLoggerContext
67 */
68
69// NOTE: We run in other VM in order to 1. switch security manager and 2. cause
70// LogManager class to be loaded anew.
71public class TestAppletLoggerContext {
72
73    // Avoids the hassle of dealing with files and system props...
74    static class SimplePolicy extends Policy {
75        private final Permissions perms;
76        public SimplePolicy(Permission... permissions) {
77            perms = new Permissions();
78            for (Permission permission : permissions) {
79                perms.add(permission);
80            }
81        }
82        @Override
83        public PermissionCollection getPermissions(CodeSource cs) {
84            return perms;
85        }
86        @Override
87        public PermissionCollection getPermissions(ProtectionDomain pd) {
88            return perms;
89        }
90        @Override
91        public boolean implies(ProtectionDomain pd, Permission p) {
92           return perms.implies(p);
93        }
94    }
95
96    // The bridge class initializes the logging system.
97    // It stubs the applet context in order to simulate context changes.
98    //
99    public static class Bridge {
100
101        private static class JavaAWTAccessStub implements JavaAWTAccess {
102            boolean active = true;
103
104            private static class TestExc {
105                private final Map<Object, Object> map = new HashMap<>();
106                void put(Object key, Object v) { map.put(key, v); }
107                Object get(Object key) { return map.get(key); }
108                void remove(Object o) { map.remove(o); }
109                public static TestExc exc(Object o) {
110                    return TestExc.class.cast(o);
111                }
112            }
113
114            TestExc exc;
115
116            @Override
117            public Object getAppletContext() { return active ? exc : null; }
118        }
119
120        static final JavaAWTAccessStub javaAwtAccess = new JavaAWTAccessStub();
121        public static void init() {
122            SharedSecrets.setJavaAWTAccess(javaAwtAccess);
123            if (System.getProperty("test.security", "on").equals("on")) {
124                Policy p = new SimplePolicy(new LoggingPermission("control", null),
125                    new RuntimePermission("setContextClassLoader"),
126                    new RuntimePermission("shutdownHooks"));
127                Policy.setPolicy(p);
128                System.setSecurityManager(new SecurityManager());
129            }
130        }
131
132        public static void changeContext() {
133            System.out.println("... Switching to a new applet context ...");
134            javaAwtAccess.active = true;
135            javaAwtAccess.exc = new JavaAWTAccessStub.TestExc();
136        }
137
138        public static void desactivate() {
139            System.out.println("... Running with no applet context ...");
140            javaAwtAccess.exc = null;
141            javaAwtAccess.active = false;
142        }
143
144        public static class CustomAnonymousLogger extends Logger {
145            public CustomAnonymousLogger() {
146                this("");
147            }
148            public CustomAnonymousLogger(String name) {
149                super(null, null);
150                System.out.println( " LogManager: " +LogManager.getLogManager());
151                System.out.println( " getLogger: " +LogManager.getLogManager().getLogger(name));
152                setParent(LogManager.getLogManager().getLogger(name));
153            }
154        }
155
156        public static class CustomLogger extends Logger {
157            CustomLogger(String name) {
158                super(name, null);
159            }
160        }
161    }
162
163    public static enum TestCase {
164        LoadingApplet, LoadingMain, One, Two, Three, Four, Five, Six, Seven;
165        public void test() {
166            switch(this) {
167                // When run - each of these two tests must be
168                // run before any other tests and before each other.
169                case LoadingApplet: testLoadingApplet(); break;
170                case LoadingMain:   testLoadingMain(); break;
171                case One:   testOne(); break;
172                case Two:   testTwo(); break;
173                case Three: testThree(); break;
174                case Four:  testFour(); break;
175                case Five:  testFive(); break;
176                case Six:   testSix(); break;
177                case Seven: testSeven(); break;
178            }
179        }
180        public String describe() {
181            switch(this) {
182                case LoadingApplet:
183                    return "Test that when the LogManager class is"
184                        + " loaded in  an applet thread first,"
185                        + "\n all LoggerContexts are correctly initialized";
186                case LoadingMain:
187                    return "Test that when the LogManager class is"
188                        + " loaded in  the main thread first,"
189                        + "\n all LoggerContexts are correctly initialized";
190                case One:
191                    return "Test that Logger.getAnonymousLogger()"
192                        + " and new CustomAnonymousLogger() don't throw NPE";
193                case Two:
194                    return "Test that Logger.getLogger(\"\")"
195                            + " does not return null nor throws NPE";
196                case Three:
197                    return "Test that LogManager.getLogManager().getLogger(\"\")"
198                            + " does not return null nor throws NPE";
199                case Four:
200                    return "Test that Logger.getLogger(Logger.GLOBAL_LOGGER_NAME)"
201                            + " does not return null,\n and that"
202                            + " new CustomAnonymousLogger(Logger.GLOBAL_LOGGER_NAME)"
203                            + " does not throw NPE";
204                case Five:
205                    return "Test that LogManager.getLogManager().getLogger(Logger.GLOBAL_LOGGER_NAME)"
206                            + "\n does not return null nor throws NPE";
207                case Six:
208                    return "Test that manager.getLogger(Logger.GLOBAL_LOGGER_NAME)"
209                            + " returns null\n when manager is not the default"
210                            + " LogManager instance.\n"
211                            + "Test adding a new logger named \"global\" in that"
212                            + " non default instance.";
213                case Seven: return "Test that manager.getLogger(\"\")"
214                            + " returns null\n when manager is not the default"
215                            + " LogManager instance.\n"
216                            + "Test adding a new logger named \"\" in that"
217                            + " non default instance.";
218                default: return "Undefined";
219            }
220        }
221    };
222
223    /**
224     * @param args the command line arguments
225     */
226    public static void main(String[] args) {
227        Bridge.init();
228        EnumSet<TestCase> tests = EnumSet.noneOf(TestCase.class);
229        for (String arg : args) {
230            tests.add(TestCase.valueOf(arg));
231        }
232        if (args.length == 0) {
233            tests = EnumSet.complementOf(EnumSet.of(TestCase.LoadingMain));
234        }
235        final EnumSet<TestCase> loadingTests =
236            EnumSet.of(TestCase.LoadingApplet, TestCase.LoadingMain);
237        int testrun = 0;
238        for (TestCase test : tests) {
239            if (loadingTests.contains(test)) {
240                if (testrun > 0) {
241                    throw new UnsupportedOperationException("Test case "
242                          + test + " must be executed first!");
243                }
244            }
245            System.out.println("Testing "+ test+": ");
246            System.out.println(test.describe());
247            try {
248                test.test();
249            } catch (Exception x) {
250               throw new Error(String.valueOf(test)
251                   + (System.getSecurityManager() == null ? " without " : " with ")
252                   + "security failed: "+x+"\n "+"FAILED: "+test.describe()+"\n", x);
253            } finally {
254                testrun++;
255            }
256            Bridge.changeContext();
257            System.out.println("PASSED: "+ test);
258        }
259    }
260
261    public static void testLoadingApplet() {
262        Bridge.changeContext();
263
264        Logger bar = new Bridge.CustomLogger("com.foo.Bar");
265        LogManager.getLogManager().addLogger(bar);
266        assertNotNull(bar.getParent());
267        testParent(bar);
268        testParent(LogManager.getLogManager().getLogger("global"));
269        testParent(LogManager.getLogManager().getLogger(bar.getName()));
270
271        Bridge.desactivate();
272
273        Logger foo = new Bridge.CustomLogger("com.foo.Foo");
274        boolean b = LogManager.getLogManager().addLogger(foo);
275        assertEquals(Boolean.TRUE, Boolean.valueOf(b));
276        assertNotNull(foo.getParent());
277        testParent(foo);
278        testParent(LogManager.getLogManager().getLogger("global"));
279        testParent(LogManager.getLogManager().getLogger(foo.getName()));
280    }
281
282    public static void testLoadingMain() {
283        Bridge.desactivate();
284
285        Logger bar = new Bridge.CustomLogger("com.foo.Bar");
286        LogManager.getLogManager().addLogger(bar);
287        assertNotNull(bar.getParent());
288        testParent(bar);
289        testParent(LogManager.getLogManager().getLogger("global"));
290        testParent(LogManager.getLogManager().getLogger(bar.getName()));
291
292        Bridge.changeContext();
293
294        Logger foo = new Bridge.CustomLogger("com.foo.Foo");
295        boolean b = LogManager.getLogManager().addLogger(foo);
296        assertEquals(Boolean.TRUE, Boolean.valueOf(b));
297        assertNotNull(foo.getParent());
298        testParent(foo);
299        testParent(LogManager.getLogManager().getLogger("global"));
300        testParent(LogManager.getLogManager().getLogger(foo.getName()));
301
302    }
303
304    public static void testOne() {
305        for (int i=0; i<3 ; i++) {
306            Logger logger1 = Logger.getAnonymousLogger();
307            Logger logger1b = Logger.getAnonymousLogger();
308            Bridge.changeContext();
309            Logger logger2 = Logger.getAnonymousLogger();
310            Logger logger2b = Logger.getAnonymousLogger();
311            Bridge.changeContext();
312            Logger logger3 = new Bridge.CustomAnonymousLogger();
313            Logger logger3b = new Bridge.CustomAnonymousLogger();
314            Bridge.changeContext();
315            Logger logger4 = new Bridge.CustomAnonymousLogger();
316            Logger logger4b = new Bridge.CustomAnonymousLogger();
317        }
318    }
319
320
321    public static void testTwo() {
322        for (int i=0; i<3 ; i++) {
323            Logger logger1 = Logger.getLogger("");
324            Logger logger1b = Logger.getLogger("");
325            assertNotNull(logger1);
326            assertNotNull(logger1b);
327            assertEquals(logger1, logger1b);
328            Bridge.changeContext();
329            Logger logger2 = Logger.getLogger("");
330            Logger logger2b = Logger.getLogger("");
331            assertNotNull(logger2);
332            assertNotNull(logger2b);
333            assertEquals(logger2, logger2b);
334            assertEquals(logger1, logger2);
335        }
336    }
337
338    public static void testThree() {
339        for (int i=0; i<3 ; i++) {
340            Logger logger1 = LogManager.getLogManager().getLogger("");
341            Logger logger1b = LogManager.getLogManager().getLogger("");
342            assertNotNull(logger1);
343            assertNotNull(logger1b);
344            assertEquals(logger1, logger1b);
345            Bridge.changeContext();
346            Logger logger2 = LogManager.getLogManager().getLogger("");
347            Logger logger2b = LogManager.getLogManager().getLogger("");
348            assertNotNull(logger2);
349            assertNotNull(logger2b);
350            assertEquals(logger2, logger2b);
351            assertEquals(logger1, logger2);
352        }
353    }
354
355    public static void testFour() {
356        for (int i=0; i<3 ; i++) {
357            Logger logger1 = Logger.getLogger(Logger.GLOBAL_LOGGER_NAME);
358            Logger logger1b = Logger.getLogger(Logger.GLOBAL_LOGGER_NAME);
359            assertNotNull(logger1);
360            assertNotNull(logger1b);
361            assertEquals(logger1, logger1b);
362            Bridge.changeContext();
363
364            Logger logger2 = Logger.getLogger(Logger.GLOBAL_LOGGER_NAME);
365            Logger logger2b = Logger.getLogger(Logger.GLOBAL_LOGGER_NAME);
366            assertNotNull(logger2);
367            assertNotNull(logger2b);
368            assertEquals(logger2, logger2b);
369
370            assertEquals(logger1, logger2);
371
372            Bridge.changeContext();
373            Logger logger3 = new Bridge.CustomAnonymousLogger(Logger.GLOBAL_LOGGER_NAME);
374            Logger logger3b = new Bridge.CustomAnonymousLogger(Logger.GLOBAL_LOGGER_NAME);
375            Bridge.changeContext();
376            Logger logger4 = new Bridge.CustomAnonymousLogger(Logger.GLOBAL_LOGGER_NAME);
377            Logger logger4b = new Bridge.CustomAnonymousLogger(Logger.GLOBAL_LOGGER_NAME);
378        }
379    }
380
381    public static void testFive() {
382        for (int i=0; i<3 ; i++) {
383            Logger logger1 = LogManager.getLogManager().getLogger(Logger.GLOBAL_LOGGER_NAME);
384            Logger logger1b = LogManager.getLogManager().getLogger(Logger.GLOBAL_LOGGER_NAME);
385            assertNotNull(logger1);
386            assertNotNull(logger1b);
387            assertEquals(logger1, logger1b);
388
389            Bridge.changeContext();
390
391            Logger logger2 = LogManager.getLogManager().getLogger(Logger.GLOBAL_LOGGER_NAME);
392            Logger logger2b = LogManager.getLogManager().getLogger(Logger.GLOBAL_LOGGER_NAME);
393            assertNotNull(logger2);
394            assertNotNull(logger2b);
395            assertEquals(logger2, logger2b);
396
397            assertEquals(logger1, logger2);
398        }
399    }
400
401    /**
402     * This test is designed to test the behavior of additional LogManager instances.
403     * It must be noted that if the security manager is off, then calling
404     * Bridge.changeContext() has actually no effect - which explains why we have
405     * some differences between the cases security manager on & security manager
406     * off.
407     **/
408    public static void testSix() {
409        for (int i=0; i<3 ; i++) {
410            Bridge.desactivate();
411            LogManager manager = new LogManager() {};
412            Logger logger1 = manager.getLogger(Logger.GLOBAL_LOGGER_NAME);
413            Logger logger1b = manager.getLogger(Logger.GLOBAL_LOGGER_NAME);
414            assertNull(logger1);
415            assertNull(logger1b);
416            Logger global = new Bridge.CustomLogger(Logger.GLOBAL_LOGGER_NAME);
417            manager.addLogger(global);
418            Logger logger2 = manager.getLogger(Logger.GLOBAL_LOGGER_NAME);
419            Logger logger2b = manager.getLogger(Logger.GLOBAL_LOGGER_NAME);
420            assertNotNull(logger2);
421            assertNotNull(logger2b);
422            assertEquals(logger2, global);
423            assertEquals(logger2b, global);
424            assertNull(manager.getLogger(""));
425            assertNull(manager.getLogger(""));
426
427            for (int j = 0; j<3; j++) {
428                Bridge.changeContext();
429
430                // this is not a supported configuration:
431                // We are in an applet context with several log managers.
432                // We however need to check our assumptions...
433
434                // Applet context => root logger and global logger should also be null.
435
436                Logger expected = (System.getSecurityManager() == null ? global : null);
437                Logger logger3 = manager.getLogger(Logger.GLOBAL_LOGGER_NAME);
438                Logger logger3b = manager.getLogger(Logger.GLOBAL_LOGGER_NAME);
439                assertEquals(expected, logger3);
440                assertEquals(expected, logger3b);
441                Logger global2 = new Bridge.CustomLogger(Logger.GLOBAL_LOGGER_NAME);
442                manager.addLogger(global2);
443                Logger logger4 = manager.getLogger(Logger.GLOBAL_LOGGER_NAME);
444                Logger logger4b = manager.getLogger(Logger.GLOBAL_LOGGER_NAME);
445                assertNotNull(logger4);
446                assertNotNull(logger4b);
447                expected = (System.getSecurityManager() == null ? global : global2);;
448                assertEquals(logger4,  expected);
449                assertEquals(logger4b, expected);
450
451                Logger logger5 = manager.getLogger("");
452                Logger logger5b = manager.getLogger("");
453                Logger expectedRoot = null;
454                assertEquals(logger5, expectedRoot);
455                assertEquals(logger5b, expectedRoot);
456            }
457
458        }
459    }
460
461    /**
462     * This test is designed to test the behavior of additional LogManager instances.
463     * It must be noted that if the security manager is off, then calling
464     * Bridge.changeContext() has actually no effect - which explains why we have
465     * some differences between the cases security manager on & security manager
466     * off.
467     **/
468    public static void testSeven() {
469        for (int i=0; i<3 ; i++) {
470            Bridge.desactivate();
471            LogManager manager = new LogManager() {};
472            Logger logger1 = manager.getLogger("");
473            Logger logger1b = manager.getLogger("");
474            assertNull(logger1);
475            assertNull(logger1b);
476            Logger global = new Bridge.CustomLogger(Logger.GLOBAL_LOGGER_NAME);
477            manager.addLogger(global);
478            Logger logger2 = manager.getLogger(Logger.GLOBAL_LOGGER_NAME);
479            Logger logger2b = manager.getLogger(Logger.GLOBAL_LOGGER_NAME);
480            assertNotNull(logger2);
481            assertNotNull(logger2b);
482            assertEquals(logger2, global);
483            assertEquals(logger2b, global);
484            Logger logger3 = manager.getLogger("");
485            Logger logger3b = manager.getLogger("");
486            assertNull(logger3);
487            assertNull(logger3b);
488            Logger root = new Bridge.CustomLogger("");
489            manager.addLogger(root);
490            Logger logger4 = manager.getLogger("");
491            Logger logger4b = manager.getLogger("");
492            assertNotNull(logger4);
493            assertNotNull(logger4b);
494            assertEquals(logger4, root);
495            assertEquals(logger4b, root);
496
497            for (int j = 0 ; j < 3 ; j++) {
498                Bridge.changeContext();
499
500                // this is not a supported configuration:
501                // We are in an applet context with several log managers.
502                // We however need to check our assumptions...
503
504                // Applet context => root logger and global logger should also be null.
505
506                Logger logger5 = manager.getLogger("");
507                Logger logger5b = manager.getLogger("");
508                Logger expectedRoot = (System.getSecurityManager() == null ? root : null);
509                assertEquals(logger5, expectedRoot);
510                assertEquals(logger5b, expectedRoot);
511
512                if (System.getSecurityManager() != null) {
513                    assertNull(manager.getLogger(Logger.GLOBAL_LOGGER_NAME));
514                } else {
515                    assertEquals(global, manager.getLogger(Logger.GLOBAL_LOGGER_NAME));
516                }
517
518                Logger global2 = new Bridge.CustomLogger(Logger.GLOBAL_LOGGER_NAME);
519                manager.addLogger(global2);
520                Logger logger6 = manager.getLogger(Logger.GLOBAL_LOGGER_NAME);
521                Logger logger6b = manager.getLogger(Logger.GLOBAL_LOGGER_NAME);
522                Logger expectedGlobal = (System.getSecurityManager() == null ? global : global2);
523
524                assertNotNull(logger6);
525                assertNotNull(logger6b);
526                assertEquals(logger6, expectedGlobal);
527                assertEquals(logger6b, expectedGlobal);
528                if (System.getSecurityManager() != null) {
529                    assertNull(manager.getLogger(""));
530                } else {
531                    assertEquals(root, manager.getLogger(""));
532                }
533
534                Logger root2 = new Bridge.CustomLogger("");
535                manager.addLogger(root2);
536                expectedRoot = (System.getSecurityManager() == null ? root : root2);
537                Logger logger7 = manager.getLogger("");
538                Logger logger7b = manager.getLogger("");
539                assertNotNull(logger7);
540                assertNotNull(logger7b);
541                assertEquals(logger7, expectedRoot);
542                assertEquals(logger7b, expectedRoot);
543            }
544        }
545    }
546
547    public static void testParent(Logger logger) {
548        Logger l = logger;
549        while (l.getParent() != null) {
550            l = l.getParent();
551        }
552        assertEquals("", l.getName());
553    }
554
555    public static class TestError extends RuntimeException {
556        public TestError(String msg) {
557            super(msg);
558        }
559    }
560
561    public static void assertNotNull(Object obj) {
562        if (obj == null) throw new NullPointerException();
563    }
564
565    public static void assertNull(Object obj) {
566        if (obj != null) throw new TestError("Null expected, got "+obj);
567    }
568
569    public static void assertEquals(Object o1, Object o2) {
570        if (o1 != o2) {
571            throw new TestError(o1 + " != " + o2);
572        }
573    }
574
575    public static void assertNotEquals(Object o1, Object o2) {
576        if (o1 == o2) {
577            throw new TestError(o1 + " == " + o2);
578        }
579    }
580}
581