TestSetResourceBundle.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 */
23import java.security.AccessControlException;
24import java.security.Permission;
25import java.security.Permissions;
26import java.security.Policy;
27import java.security.ProtectionDomain;
28import java.util.Locale;
29import java.util.Objects;
30import java.util.PropertyPermission;
31import java.util.ResourceBundle;
32import java.util.logging.Handler;
33import java.util.logging.Level;
34import java.util.logging.LogManager;
35import java.util.logging.LogRecord;
36import java.util.logging.Logger;
37import java.util.logging.LoggingPermission;
38import resources.ListBundle;
39
40/**
41 * @test
42 * @bug 8013839
43 * @summary tests Logger.setResourceBundle;
44 * @build TestSetResourceBundle resources.ListBundle resources.ListBundle_fr
45 * @run main/othervm TestSetResourceBundle UNSECURE
46 * @run main/othervm TestSetResourceBundle PERMISSION
47 * @run main/othervm TestSetResourceBundle SECURE
48 * @author danielfuchs
49 */
50public class TestSetResourceBundle {
51
52    static final String LIST_BUNDLE_NAME = "resources.ListBundle";
53    static final String PROPERTY_BUNDLE_NAME = "resources.PropertyBundle";
54
55    /**
56     * A dummy handler class that we can use to check the bundle/bundle name
57     * that was present in the last LogRecord instance published.
58     */
59    static final class TestHandler extends Handler {
60        volatile ResourceBundle lastBundle = null;
61        volatile String lastBundleName = null;
62        @Override
63        public void publish(LogRecord record) {
64            lastBundle = record.getResourceBundle();
65            lastBundleName = record.getResourceBundleName();
66        }
67
68        @Override
69        public void flush() {
70        }
71
72        @Override
73        public void close() throws SecurityException {
74        }
75    }
76
77    /**
78     * We will test setResourceBundle() in 3 configurations.
79     * UNSECURE: No security manager.
80     * SECURE: With the security manager present - and the required
81     *         LoggingPermission("control") granted.
82     * PERMISSION: With the security manager present - and the required
83     *         LoggingPermission("control") *not* granted. Here we will
84     *         test that the expected security permission is thrown.
85     */
86    public static enum TestCase {
87        UNSECURE, SECURE, PERMISSION;
88        public void run(String name) throws Exception {
89            System.out.println("Running test case: " + name());
90            switch (this) {
91                case UNSECURE:
92                    testUnsecure(name);
93                    break;
94                case SECURE:
95                    testSecure(name);
96                    break;
97                case PERMISSION:
98                    testPermission(name);
99                    break;
100                default:
101                    throw new Error("Unknown test case: "+this);
102            }
103        }
104        public String loggerName(String name) {
105            return name().toLowerCase(Locale.ROOT) + "." + name;
106        }
107    }
108
109    public static void main(String... args) throws Exception {
110
111        Locale defaultLocale = Locale.getDefault();
112
113        if (args == null || args.length == 0) {
114            args = new String[] {
115                TestCase.UNSECURE.name(),
116                TestCase.SECURE.name()
117            };
118        }
119
120        for (String testName : args) {
121            TestCase test = TestCase.valueOf(testName);
122            try {
123                test.run(test.loggerName("foo.bar"));
124            } finally {
125                Locale.setDefault(defaultLocale);
126            }
127        }
128    }
129
130    /**
131     * Test without security manager.
132     * @param loggerName The logger to use.
133     * @throws Exception if the test fails.
134     */
135    public static void testUnsecure(String loggerName) throws Exception {
136        if (System.getSecurityManager() != null) {
137            throw new Error("Security manager is set");
138        }
139        test(loggerName);
140    }
141
142    /**
143     * Test with security manager.
144     * @param loggerName The logger to use.
145     * @throws Exception if the test fails.
146     */
147    public static void testSecure(String loggerName) throws Exception {
148        if (System.getSecurityManager() != null) {
149            throw new Error("Security manager is already set");
150        }
151        Policy.setPolicy(new SimplePolicy(TestCase.SECURE));
152        System.setSecurityManager(new SecurityManager());
153        test(loggerName);
154    }
155
156    /**
157     * Test the LoggingPermission("control") is required.
158     * @param loggerName The logger to use.
159     */
160    public static void testPermission(String loggerName) {
161        if (System.getSecurityManager() != null) {
162            throw new Error("Security manager is already set");
163        }
164        Policy.setPolicy(new SimplePolicy(TestCase.PERMISSION));
165        System.setSecurityManager(new SecurityManager());
166        final ResourceBundle bundle = ResourceBundle.getBundle(LIST_BUNDLE_NAME);
167        Logger foobar = Logger.getLogger(loggerName);
168        try {
169            foobar.setResourceBundle(bundle);
170            throw new RuntimeException("Permission not checked!");
171        } catch (AccessControlException x) {
172            if (x.getPermission() instanceof LoggingPermission) {
173                if ("control".equals(x.getPermission().getName())) {
174                    System.out.println("Got expected exception: " + x);
175                    return;
176                }
177            }
178            throw new RuntimeException("Unexpected exception: "+x, x);
179        }
180
181    }
182
183    static String getBaseName(ResourceBundle bundle) {
184        return bundle == null ? null : bundle.getBaseBundleName();
185    }
186
187    public static void test(String loggerName) throws Exception {
188
189        System.out.println("Starting test for " + loggerName);
190
191        final ResourceBundle bundle = ResourceBundle.getBundle(LIST_BUNDLE_NAME);
192        Logger foobar = Logger.getLogger(loggerName);
193
194        // Checks that IAE is thrown if the bundle has a null base name.
195        try {
196            foobar.setResourceBundle(new ListBundle());
197            throw new RuntimeException("Expected exception not raised!");
198        } catch (IllegalArgumentException x) {
199            System.out.println("Got expected exception: " + x);
200        }
201
202        // Verify that resource bundle was not set.
203        if (foobar.getResourceBundle() != null) {
204            throw new RuntimeException("Unexpected bundle: "
205                    + foobar.getResourceBundle());
206        }
207        if (foobar.getResourceBundleName() != null) {
208            throw new RuntimeException("Unexpected bundle: "
209                    + foobar.getResourceBundleName());
210        }
211
212        // Set acceptable resource bundle on logger.
213        foobar.setResourceBundle(bundle);
214
215        // check that the bundle has been set correctly
216        if (bundle != foobar.getResourceBundle()) {
217            throw new RuntimeException("Unexpected bundle: "
218                    + foobar.getResourceBundle());
219        }
220        if (!Objects.equals(getBaseName(bundle), foobar.getResourceBundleName())) {
221            throw new RuntimeException("Unexpected bundle name: "
222                    + foobar.getResourceBundleName());
223        }
224
225        // Check that we can replace the bundle with a bundle of the same name.
226        final ResourceBundle bundle_fr =
227                ResourceBundle.getBundle(LIST_BUNDLE_NAME, Locale.FRENCH);
228        foobar.setResourceBundle(bundle_fr);
229
230        if (bundle_fr != foobar.getResourceBundle()) {
231            throw new RuntimeException("Unexpected bundle: "
232                    + foobar.getResourceBundle());
233        }
234        if (!Objects.equals(getBaseName(bundle_fr), foobar.getResourceBundleName())) {
235            throw new RuntimeException("Unexpected bundle name: "
236                    + foobar.getResourceBundleName());
237        }
238
239        // Create a child logger
240        final Logger foobaz = Logger.getLogger(loggerName + ".baz");
241
242        if (foobar != foobaz.getParent()) {
243            throw new RuntimeException("Unexpected parent: " +
244                    foobaz.getParent() + " != " + foobar);
245        }
246
247        // Check that the child logger does not have a bundle set locally
248        if (foobaz.getResourceBundle() != null) {
249            throw new RuntimeException("Unexpected bundle: "
250                    + foobaz.getResourceBundle());
251        }
252        if (foobaz.getResourceBundleName() != null) {
253            throw new RuntimeException("Unexpected bundle: "
254                    + foobaz.getResourceBundleName());
255        }
256
257
258        // Add a handler on the child logger.
259        final TestHandler handler = new TestHandler();
260        foobaz.addHandler(handler);
261
262        // log a message on the child logger
263        foobaz.severe("dummy");
264
265        // checks that the message has been logged with the bundle
266        // inherited from the parent logger
267        if (!LIST_BUNDLE_NAME.equals(handler.lastBundleName)) {
268            debugLogger(foobaz, foobar, handler);
269            throw new RuntimeException("Unexpected bundle name: "
270                    + handler.lastBundleName);
271        }
272        if (!bundle_fr.equals(handler.lastBundle)) {
273            debugLogger(foobaz, foobar, handler);
274            throw new RuntimeException("Unexpected bundle: "
275                    + handler.lastBundle);
276        }
277
278        // Check that we can get set a bundle on the child logger
279        // using Logger.getLogger.
280        final Logger foobaz2 = Logger.getLogger(loggerName + ".baz", PROPERTY_BUNDLE_NAME);
281        if (foobaz2 != foobaz) {
282            throw new RuntimeException("Unexpected logger: " + foobaz2 + " != " + foobaz);
283        }
284        if (foobar != foobaz.getParent()) {
285            throw new RuntimeException("Unexpected parent: " +
286                    foobaz.getParent() + " != " + foobar);
287        }
288
289        // check that the child logger has the correct bundle.
290        // it should no longer inherit it from its parent.
291        if (!PROPERTY_BUNDLE_NAME.equals(foobaz2.getResourceBundleName())) {
292            throw new RuntimeException("Unexpected bundle name: "
293                    + foobaz2.getResourceBundleName());
294        }
295
296        if (!PROPERTY_BUNDLE_NAME.equals(foobaz2.getResourceBundle().getBaseBundleName())) {
297            throw new RuntimeException("Unexpected bundle name: "
298                    + foobaz2.getResourceBundle().getBaseBundleName());
299        }
300
301        boolean found = false;
302        for (Handler h : foobaz2.getHandlers()) {
303            if (h == handler) {
304                found = true;
305                break;
306            }
307        }
308
309        if (!found) {
310            throw new RuntimeException("Expected handler not found in: " +
311                    foobaz2.getName() + "(" + foobaz2.getClass().getName()+")" );
312        }
313
314        // log a message on the child logger
315        foobaz2.severe("dummy");
316
317
318        // check that the last published log record has the appropriate
319        // bundle.
320        if (!PROPERTY_BUNDLE_NAME.equals(handler.lastBundleName)) {
321            debugLogger(foobaz2, foobar, handler);
322            throw new RuntimeException("Unexpected bundle name: "
323                    + handler.lastBundleName);
324        }
325        if (foobaz2.getResourceBundle() != handler.lastBundle) {
326            debugLogger(foobaz2, foobar, handler);
327            throw new RuntimeException("Unexpected bundle: "
328                    + handler.lastBundle);
329        }
330
331        // try to set a bundle that has a different name, and checks that
332        // it fails in IAE.
333        try {
334            foobaz2.setResourceBundle(bundle_fr);
335            throw new RuntimeException("Expected exception not raised!");
336        } catch (IllegalArgumentException x) {
337            System.out.println("Got expected exception: " + x);
338        }
339
340        // Test with a subclass of logger which overrides
341        // getResourceBundle() and getResourceBundleName()
342        Logger customLogger = new Logger(foobar.getName()+".bie", null) {
343            @Override
344            public ResourceBundle getResourceBundle() {
345                return bundle_fr;
346            }
347
348            @Override
349            public String getResourceBundleName() {
350                return PROPERTY_BUNDLE_NAME;
351            }
352        };
353
354        final TestHandler handler2 = new TestHandler();
355        customLogger.addHandler(handler2);
356        customLogger.setLevel(Level.FINE);
357        LogManager.getLogManager().addLogger(customLogger);
358
359        Logger l = Logger.getLogger(customLogger.getName());
360        if (l != customLogger) {
361            throw new RuntimeException("Wrong logger: " + l);
362        }
363
364        // log on the custom logger.
365        customLogger.fine("dummy");
366
367        // check that the log record had the correct bundle.
368        if (! PROPERTY_BUNDLE_NAME.equals(handler2.lastBundleName)) {
369            debugLogger(customLogger, foobar, handler2);
370            throw new RuntimeException("Unexpected bundle name: "
371                    + handler2.lastBundleName);
372        }
373        if (! PROPERTY_BUNDLE_NAME.equals(customLogger.getResourceBundleName())) {
374            debugLogger(customLogger, foobar, handler2);
375            throw new RuntimeException("Unexpected bundle name: "
376                    + customLogger.getResourceBundleName());
377        }
378        if (bundle_fr != handler2.lastBundle) {
379            throw new RuntimeException("Unexpected bundle: "
380                    + handler2.lastBundle);
381        }
382        if (bundle_fr != customLogger.getResourceBundle()) {
383            throw new RuntimeException("Unexpected bundle: "
384                    + customLogger.getResourceBundle());
385        }
386
387        // Do the same thing again with a child of the custom logger.
388        Logger biebar = Logger.getLogger(customLogger.getName() + ".bar");
389        biebar.fine("dummy");
390
391        // because getResourceBundleName() is called on parent logger
392        //         we will have handler2.lastBundleName = PROPERTY_BUNDLE_NAME
393        if (!PROPERTY_BUNDLE_NAME.equals(handler2.lastBundleName)) {
394            debugLogger(biebar, customLogger, handler2);
395            throw new RuntimeException("Unexpected bundle name: "
396                    + handler2.lastBundleName);
397        }
398        // because getResourceBundle() is not called on parent logger
399        //         we will have getBaseName(handler2.lastBundle) = PROPERTY_BUNDLE_NAME
400        //         and not handler2.lastBundle = bundle_fr
401        if (handler2.lastBundle == null) {
402            debugLogger(biebar, customLogger, handler2);
403            throw new RuntimeException("Unexpected bundle: "
404                    + handler2.lastBundle);
405        }
406        if (!PROPERTY_BUNDLE_NAME.equals(getBaseName(handler2.lastBundle))) {
407            debugLogger(biebar, customLogger, handler2);
408            throw new RuntimeException("Unexpected bundle name: "
409                    + getBaseName(handler2.lastBundle));
410        }
411
412        // Just make sure that these loggers won't be eagerly GCed...
413        if (foobar == null || !loggerName.equals(foobar.getName())) {
414            throw new RuntimeException("foobar is null "
415                    + "- or doesn't have the expected  name: " + foobar);
416        }
417        if (foobaz == null || !foobaz.getName().startsWith(loggerName)) {
418            throw new RuntimeException("foobaz is null "
419                    + "- or doesn't have the expected  name: " + foobaz);
420        }
421        if (foobaz2 == null || !foobaz2.getName().startsWith(loggerName)) {
422            throw new RuntimeException("foobaz2 is null "
423                    + "- or doesn't have the expected  name: " + foobaz2);
424        }
425        if (!customLogger.getName().startsWith(loggerName)) {
426            throw new RuntimeException("customLogger "
427                    + "doesn't have the expected name: " + customLogger);
428        }
429        if (!biebar.getName().startsWith(loggerName)) {
430            throw new RuntimeException("biebar "
431                    + "doesn't have the expected  name: " + biebar.getName());
432        }
433        System.out.println("Test passed for " + loggerName);
434    }
435
436    static void debugLogger(Logger logger, Logger expectedParent, TestHandler handler) {
437        final String logName = logger.getName();
438        final String prefix = "    " + logName;
439        System.err.println("Logger " + logName
440                + " logged with bundle name " + handler.lastBundleName
441                + " (" + handler.lastBundle + ")");
442        System.err.println(prefix + ".getResourceBundleName() is "
443                + logger.getResourceBundleName());
444        System.err.println(prefix + ".getResourceBundle() is "
445                + logger.getResourceBundle());
446        final Logger parent = logger.getParent();
447        final String pname = parent == null ? null : parent.getName();
448        final String pclass = parent == null ? ""
449                : ("(" + parent.getClass().getName() + ")");
450        final String presn = parent == null ? null
451                : parent.getResourceBundleName();
452        final ResourceBundle pres = parent == null ? null
453                : parent.getResourceBundle();
454        System.err.println(prefix + ".getParent() is "
455                + pname + (pname == null ? ""
456                        : (" " + pclass + ": " + parent)));
457        System.err.println("    expected parent is :" + expectedParent);
458        System.err.println(prefix + ".parent.getResourceBundleName() is "
459                + presn);
460        System.err.println(prefix + ".parent.getResourceBundle() is "
461                + pres);
462        System.err.println("    expected parent getResourceBundleName() is "
463                + expectedParent.getResourceBundleName());
464        System.err.println("    expected parent.getResourceBundle() is "
465                + expectedParent.getResourceBundle());
466    }
467
468    public static class SimplePolicy extends Policy {
469
470        final Permissions permissions;
471        public SimplePolicy(TestCase test) {
472            permissions = new Permissions();
473            if (test != TestCase.PERMISSION) {
474                permissions.add(new LoggingPermission("control", null));
475            }
476            // required for calling Locale.setDefault in the test.
477            permissions.add(new PropertyPermission("user.language", "write"));
478        }
479
480        @Override
481        public boolean implies(ProtectionDomain domain, Permission permission) {
482            return permissions.implies(permission);
483        }
484    }
485
486}
487