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 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 }