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