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 import java.security.AccessControlException;
  24 import java.security.Permission;
  25 import java.security.Permissions;
  26 import java.security.Policy;
  27 import java.security.ProtectionDomain;
  28 import java.util.Locale;
  29 import java.util.Objects;
  30 import java.util.PropertyPermission;
  31 import java.util.ResourceBundle;
  32 import java.util.logging.Handler;
  33 import java.util.logging.Level;
  34 import java.util.logging.LogManager;
  35 import java.util.logging.LogRecord;
  36 import java.util.logging.Logger;
  37 import java.util.logging.LoggingPermission;
  38 import 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  */
  50 public class TestSetResourceBundle {
  51 
  52     final static String LIST_BUNDLE_NAME = "resources.ListBundle";
  53     final static 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         ResourceBundle lastBundle = null;
  61         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         final ResourceBundle bundle = ResourceBundle.getBundle(LIST_BUNDLE_NAME);
 190         Logger foobar = Logger.getLogger(loggerName);
 191 
 192         // Checks that IAE is thrown if the bundle has a null base name.
 193         try {
 194             foobar.setResourceBundle(new ListBundle());
 195             throw new RuntimeException("Expected exception not raised!");
 196         } catch (IllegalArgumentException x) {
 197             System.out.println("Got expected exception: " + x);
 198         }
 199 
 200         // Verify that resource bundle was not set.
 201         if (foobar.getResourceBundle() != null) {
 202             throw new RuntimeException("Unexpected bundle: "
 203                     + foobar.getResourceBundle());
 204         }
 205         if (foobar.getResourceBundleName() != null) {
 206             throw new RuntimeException("Unexpected bundle: "
 207                     + foobar.getResourceBundleName());
 208         }
 209 
 210         // Set acceptable resource bundle on logger.
 211         foobar.setResourceBundle(bundle);
 212 
 213         // check that the bundle has been set correctly
 214         if (bundle != foobar.getResourceBundle()) {
 215             throw new RuntimeException("Unexpected bundle: "
 216                     + foobar.getResourceBundle());
 217         }
 218         if (!Objects.equals(getBaseName(bundle), foobar.getResourceBundleName())) {
 219             throw new RuntimeException("Unexpected bundle name: "
 220                     + foobar.getResourceBundleName());
 221         }
 222 
 223         // Check that we can replace the bundle with a bundle of the same name.
 224         final ResourceBundle bundle_fr =
 225                 ResourceBundle.getBundle(LIST_BUNDLE_NAME, Locale.FRENCH);
 226         foobar.setResourceBundle(bundle_fr);
 227 
 228         if (bundle_fr != foobar.getResourceBundle()) {
 229             throw new RuntimeException("Unexpected bundle: "
 230                     + foobar.getResourceBundle());
 231         }
 232         if (!Objects.equals(getBaseName(bundle_fr), foobar.getResourceBundleName())) {
 233             throw new RuntimeException("Unexpected bundle name: "
 234                     + foobar.getResourceBundleName());
 235         }
 236 
 237         // Create a child logger
 238         Logger foobaz = Logger.getLogger(loggerName + ".baz");
 239 
 240         // Check that the child logger does not have a bundle set locally
 241         if (foobaz.getResourceBundle() != null) {
 242             throw new RuntimeException("Unexpected bundle: "
 243                     + foobar.getResourceBundle());
 244         }
 245         if (foobaz.getResourceBundleName() != null) {
 246             throw new RuntimeException("Unexpected bundle: "
 247                     + foobar.getResourceBundleName());
 248         }
 249 
 250 
 251         // Add a handler on the child logger.
 252         final TestHandler handler = new TestHandler();
 253         foobaz.addHandler(handler);
 254 
 255         // log a message on the child logger
 256         foobaz.severe("dummy");
 257 
 258         // checks that the message has been logged with the bundle
 259         // inherited from the parent logger
 260         if (!LIST_BUNDLE_NAME.equals(handler.lastBundleName)) {
 261             throw new RuntimeException("Unexpected bundle name: "
 262                     + handler.lastBundleName);
 263         }
 264         if (!bundle_fr.equals(handler.lastBundle)) {
 265             throw new RuntimeException("Unexpected bundle: "
 266                     + handler.lastBundle);
 267         }
 268 
 269         // Check that we can get set a bundle on the child logger
 270         // using Logger.getLogger.
 271         foobaz = Logger.getLogger(loggerName + ".baz", PROPERTY_BUNDLE_NAME);
 272 
 273         // check that the child logger has the correct bundle.
 274         // it should no longer inherit it from its parent.
 275         if (!PROPERTY_BUNDLE_NAME.equals(foobaz.getResourceBundleName())) {
 276             throw new RuntimeException("Unexpected bundle name: "
 277                     + foobaz.getResourceBundleName());
 278         }
 279         if (!PROPERTY_BUNDLE_NAME.equals(foobaz.getResourceBundle().getBaseBundleName())) {
 280             throw new RuntimeException("Unexpected bundle name: "
 281                     + foobaz.getResourceBundle().getBaseBundleName());
 282         }
 283 
 284         // log a message on the child logger
 285         foobaz.severe("dummy");
 286 
 287         // check that the last published log record has the appropriate
 288         // bundle.
 289         if (!PROPERTY_BUNDLE_NAME.equals(handler.lastBundleName)) {
 290             throw new RuntimeException("Unexpected bundle name: "
 291                     + handler.lastBundleName);
 292         }
 293         if (foobaz.getResourceBundle() != handler.lastBundle) {
 294             throw new RuntimeException("Unexpected bundle: "
 295                     + handler.lastBundle);
 296         }
 297 
 298         // try to set a bundle that has a different name, and checks that
 299         // it fails in IAE.
 300         try {
 301             foobaz.setResourceBundle(bundle_fr);
 302             throw new RuntimeException("Expected exception not raised!");
 303         } catch (IllegalArgumentException x) {
 304             System.out.println("Got expected exception: " + x);
 305         }
 306 
 307         // Test with a subclass of logger which overrides
 308         // getResourceBundle() and getResourceBundleName()
 309         Logger customLogger = new Logger(foobar.getName()+".bie", null) {
 310             @Override
 311             public ResourceBundle getResourceBundle() {
 312                 return bundle_fr;
 313             }
 314 
 315             @Override
 316             public String getResourceBundleName() {
 317                 return PROPERTY_BUNDLE_NAME;
 318             }
 319         };
 320 
 321         final TestHandler handler2 = new TestHandler();
 322         customLogger.addHandler(handler2);
 323         customLogger.setLevel(Level.FINE);
 324         LogManager.getLogManager().addLogger(customLogger);
 325 
 326         Logger l = Logger.getLogger(customLogger.getName());
 327         if (l != customLogger) {
 328             throw new RuntimeException("Wrong logger: " + l);
 329         }
 330 
 331         // log on the custom logger.
 332         customLogger.fine("dummy");
 333 
 334         // check that the log record had the correct bundle.
 335         if (! PROPERTY_BUNDLE_NAME.equals(handler2.lastBundleName)) {
 336             throw new RuntimeException("Unexpected bundle name: "
 337                     + handler2.lastBundleName);
 338         }
 339         if (! PROPERTY_BUNDLE_NAME.equals(customLogger.getResourceBundleName())) {
 340             throw new RuntimeException("Unexpected bundle name: "
 341                     + customLogger.getResourceBundleName());
 342         }
 343         if (bundle_fr != handler2.lastBundle) {
 344             throw new RuntimeException("Unexpected bundle: "
 345                     + handler2.lastBundle);
 346         }
 347         if (bundle_fr != customLogger.getResourceBundle()) {
 348             throw new RuntimeException("Unexpected bundle: "
 349                     + customLogger.getResourceBundle());
 350         }
 351 
 352         // Do the same thing again with a child of the custom logger.
 353         Logger biebar = Logger.getLogger(customLogger.getName() + ".bar");
 354         biebar.fine("dummy");
 355 
 356         // because getResourceBundleName() is called on parent logger
 357         //         we will have handler2.lastBundleName = PROPERTY_BUNDLE_NAME
 358         if (!PROPERTY_BUNDLE_NAME.equals(handler2.lastBundleName)) {
 359             throw new RuntimeException("Unexpected bundle name: "
 360                     + handler2.lastBundleName);
 361         }
 362         // because getResourceBundle() is not called on parent logger
 363         //         we will have getBaseName(handler2.lastBundle) = PROPERTY_BUNDLE_NAME
 364         //         and not handler2.lastBundle = bundle_fr
 365         if (handler2.lastBundle == null) {
 366             throw new RuntimeException("Unexpected bundle: "
 367                     + handler2.lastBundle);
 368         }
 369         if (!PROPERTY_BUNDLE_NAME.equals(getBaseName(handler2.lastBundle))) {
 370             throw new RuntimeException("Unexpected bundle name: "
 371                     + getBaseName(handler2.lastBundle));
 372         }
 373     }
 374 
 375     public static class SimplePolicy extends Policy {
 376 
 377         final Permissions permissions;
 378         public SimplePolicy(TestCase test) {
 379             permissions = new Permissions();
 380             if (test != TestCase.PERMISSION) {
 381                 permissions.add(new LoggingPermission("control", null));
 382             }
 383             // required for calling Locale.setDefault in the test.
 384             permissions.add(new PropertyPermission("user.language", "write"));
 385         }
 386 
 387         @Override
 388         public boolean implies(ProtectionDomain domain, Permission permission) {
 389             return permissions.implies(permission);
 390         }
 391     }
 392 
 393 }