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