1 /*
   2  * Copyright (c) 2015, 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.io.ByteArrayInputStream;
  24 import java.io.ByteArrayOutputStream;
  25 import java.io.FileOutputStream;
  26 import java.io.IOException;
  27 import java.nio.file.Path;
  28 import java.nio.file.Paths;
  29 import java.security.CodeSource;
  30 import java.security.Permission;
  31 import java.security.PermissionCollection;
  32 import java.security.Permissions;
  33 import java.security.Policy;
  34 import java.security.ProtectionDomain;
  35 import java.util.Arrays;
  36 import java.util.Enumeration;
  37 import java.util.Objects;
  38 import java.util.Properties;
  39 import java.util.concurrent.Callable;
  40 import java.util.concurrent.atomic.AtomicBoolean;
  41 import java.util.concurrent.atomic.AtomicLong;
  42 import java.util.function.BiFunction;
  43 import java.util.function.Function;
  44 import java.util.logging.Handler;
  45 import java.util.logging.Level;
  46 import java.util.logging.LogManager;
  47 import java.util.logging.LogRecord;
  48 import java.util.logging.Logger;
  49 import java.util.logging.LoggingPermission;
  50 
  51 /**
  52  * @test
  53  * @bug 8033661 8189291
  54  * @summary tests LogManager.updateConfiguration(InputStream, Function) method
  55  * @run main/othervm SimpleUpdateConfigWithInputStreamTest UNSECURE
  56  * @run main/othervm SimpleUpdateConfigWithInputStreamTest SECURE
  57  * @author danielfuchs
  58  */
  59 public class SimpleUpdateConfigWithInputStreamTest {
  60     static final Policy DEFAULT_POLICY = Policy.getPolicy();
  61 
  62     /**
  63      * We will test updateConfiguration in
  64      * two configurations:
  65      * UNSECURE: No security manager.
  66      * SECURE: With the security manager present - and the required
  67      *         permissions granted.
  68      */
  69     public static enum TestCase {
  70         UNSECURE, SECURE;
  71         public void execute(Runnable run) {
  72             System.out.println("Running test case: " + name());
  73             try {
  74                Configure.setUp(this);
  75                Configure.doPrivileged(run, SimplePolicy.allowControl);
  76             } finally {
  77                Configure.doPrivileged(() -> {
  78                    try {
  79                        setSystemProperty("java.util.logging.config.file", null);
  80                        LogManager.getLogManager().readConfiguration();
  81                        System.gc();
  82                    } catch (Exception x) {
  83                        throw new RuntimeException(x);
  84                    }
  85                }, SimplePolicy.allowAll);
  86             }
  87         }
  88     }
  89 
  90     public static class MyHandler extends Handler {
  91         static final AtomicLong seq = new AtomicLong();
  92         long count = seq.incrementAndGet();
  93 
  94         @Override
  95         public void publish(LogRecord record) {
  96         }
  97 
  98         @Override
  99         public void flush() {
 100         }
 101 
 102         @Override
 103         public void close() throws SecurityException {
 104         }
 105 
 106         @Override
 107         public String toString() {
 108             return super.toString() + "("+count+")";
 109         }
 110 
 111     }
 112 
 113     static String storePropertyToFile(String name, Properties props)
 114         throws Exception {
 115         return Configure.callPrivileged(() -> {
 116             String scratch = System.getProperty("user.dir", ".");
 117             Path p = Paths.get(scratch, name);
 118             try (FileOutputStream fos = new FileOutputStream(p.toFile())) {
 119                 props.store(fos, name);
 120             }
 121             return p.toString();
 122         }, SimplePolicy.allowAll);
 123     }
 124 
 125     static void setSystemProperty(String name, String value)
 126         throws Exception {
 127         Configure.doPrivileged(() -> {
 128             if (value == null)
 129                 System.clearProperty(name);
 130             else
 131                 System.setProperty(name, value);
 132         }, SimplePolicy.allowAll);
 133     }
 134 
 135     static String trim(String value) {
 136         return value == null ? null : value.trim();
 137     }
 138 
 139 
 140     /**
 141      * Tests one of the configuration defined above.
 142      * <p>
 143      * This is the main test method (the rest is infrastructure).
 144      */
 145     static void testUpdateConfiguration() {
 146         try {
 147             // manager initialized with default configuration.
 148             LogManager manager = LogManager.getLogManager();
 149 
 150             // Test default configuration. It should not have
 151             // any value for "com.foo.level" and "com.foo.handlers"
 152             assertEquals(null, manager.getProperty("com.foo.level"),
 153                 "com.foo.level in default configuration");
 154             assertEquals(null, manager.getProperty("com.foo.handlers"),
 155                 "com.foo.handlers in default configuration");
 156 
 157             // Create a logging configuration file that contains
 158             // com.foo.level=FINEST
 159             // and set "java.util.logging.config.file" to this file.
 160             Properties props = new Properties();
 161             props.setProperty("com.foo.level", "FINEST");
 162 
 163             // Update configuration with props
 164             // then test that the new configuration has
 165             // com.foo.level=FINEST
 166             // and nothing for com.foo.handlers
 167             Configure.updateConfigurationWith(props, null);
 168             assertEquals("FINEST", manager.getProperty("com.foo.level"),
 169                 "com.foo.level in " + props);
 170             assertEquals(null, manager.getProperty("com.foo.handlers"),
 171                 "com.foo.handlers in " + props);
 172 
 173             // call updateConfiguration with an empty stream.
 174             // check that the new configuration no longer has
 175             // any value for com.foo.level, and still no value
 176             // for com.foo.handlers
 177             Configure.updateConfigurationWith(new Properties(), null);
 178             assertEquals(null, manager.getProperty("com.foo.level"),
 179                     "com.foo.level in default configuration");
 180             assertEquals(null, manager.getProperty("com.foo.handlers"),
 181                 "com.foo.handlers in default configuration");
 182 
 183             // creates the com.foo logger, check it has
 184             // the default config: no level, and no handlers
 185             final Logger logger = Logger.getLogger("com.foo");
 186             assertEquals(null, logger.getLevel(),
 187                 "Logger.getLogger(\"com.foo\").getLevel()");
 188             assertDeepEquals(new Handler[0], logger.getHandlers(),
 189                     "Logger.getLogger(\"com.foo\").getHandlers()");
 190 
 191             // call updateConfiguration with 'props'
 192             // check that the configuration has
 193             // com.foo.level=FINEST
 194             // and nothing for com.foo.handlers
 195             // check that the logger has now a FINEST level and still
 196             // no handlers
 197             Configure.updateConfigurationWith(props, null);
 198             assertEquals("FINEST", manager.getProperty("com.foo.level"),
 199                 "com.foo.level in " + props);
 200             assertEquals(Level.FINEST, logger.getLevel(),
 201                 "Logger.getLogger(\"com.foo\").getLevel()");
 202             assertDeepEquals(new Handler[0], logger.getHandlers(),
 203                     "Logger.getLogger(\"com.foo\").getHandlers()");
 204             assertEquals(null, manager.getProperty("com.foo.handlers"),
 205                 "com.foo.handlers in " + props);
 206 
 207             // Calls updateConfiguration with a lambda whose effect should
 208             // be to set the FINER level on the "com.foo" logger.
 209             // Check that the new configuration has
 210             // com.foo.level=FINER
 211             // and nothing for com.foo.handlers
 212             // check that the logger has now a FINER level and still
 213             // no handlers
 214             Configure.updateConfigurationWith(props,
 215                     (k) -> ("com.foo.level".equals(k) ? (o, n) -> "FINER" : (o, n) -> n));
 216             assertEquals("FINER", manager.getProperty("com.foo.level"),
 217                 "com.foo.level set to FINER by updateConfiguration");
 218             assertEquals(Level.FINER, logger.getLevel(),
 219                 "Logger.getLogger(\"com.foo\").getLevel()");
 220             assertDeepEquals(new Handler[0], logger.getHandlers(),
 221                     "Logger.getLogger(\"com.foo\").getHandlers()");
 222             assertEquals(null, manager.getProperty("com.foo.handlers"),
 223                 "com.foo.handlers in " + props);
 224 
 225             // Calls updateConfiguration with a lambda whose effect is a noop.
 226             // This should not change the configuration, so
 227             // check that the new configuration still has
 228             // com.foo.level=FINER
 229             // and nothing for com.foo.handlers
 230             // check that the logger still has FINER level and still
 231             // no handlers
 232             Configure.updateConfigurationWith(props,
 233                     (k) -> ((o, n) -> o));
 234             assertEquals("FINER", manager.getProperty("com.foo.level"),
 235                 "com.foo.level preserved by updateConfiguration");
 236             assertEquals(Level.FINER, logger.getLevel(),
 237                 "Logger.getLogger(\"com.foo\").getLevel()");
 238             assertDeepEquals(new Handler[0], logger.getHandlers(),
 239                     "Logger.getLogger(\"com.foo\").getHandlers()");
 240             assertEquals(null, manager.getProperty("com.foo.handlers"),
 241                 "com.foo.handlers in " + props);
 242 
 243             // Calls updateConfiguration with a lambda whose effect is to
 244             // take all values from the new configuration.
 245             // This should update the configuration to what is in props, so
 246             // check that the new configuration has
 247             // com.foo.level=FINEST
 248             // and nothing for com.foo.handlers
 249             // check that the logger now has FINEST level and still
 250             // no handlers
 251             Configure.updateConfigurationWith(props,
 252                     (k) -> ((o, n) -> n));
 253             assertEquals("FINEST", manager.getProperty("com.foo.level"),
 254                 "com.foo.level updated by updateConfiguration");
 255             assertEquals(Level.FINEST, logger.getLevel(),
 256                 "Logger.getLogger(\"com.foo\").getLevel()");
 257             assertDeepEquals(new Handler[0], logger.getHandlers(),
 258                     "Logger.getLogger(\"com.foo\").getHandlers()");
 259             assertEquals(null, manager.getProperty("com.foo.handlers"),
 260                 "com.foo.handlers in " + props);
 261 
 262             // now set a handler on the com.foo logger.
 263             MyHandler h = new MyHandler();
 264             logger.addHandler(h);
 265             assertDeepEquals(new Handler[] {h}, logger.getHandlers(),
 266                     "Logger.getLogger(\"com.foo\").getHandlers()");
 267 
 268             // Calls updateConfiguration with a lambda whose effect should
 269             // be to set the FINER level on the "com.foo" logger, and
 270             // take the value from props for everything else.
 271             // Check that the new configuration has
 272             // com.foo.level=FINER
 273             // and nothing for com.foo.handlers
 274             // check that the logger has now a FINER level, but that its
 275             // handlers are still present and have not been reset
 276             // since neither the old nor new configuration defined them.
 277             Configure.updateConfigurationWith(props,
 278                     (k) -> ("com.foo.level".equals(k) ? (o, n) -> "FINER" : (o, n) -> n));
 279             assertEquals("FINER", manager.getProperty("com.foo.level"),
 280                 "com.foo.level set to FINER by updateConfiguration");
 281             assertEquals(Level.FINER, logger.getLevel(),
 282                 "Logger.getLogger(\"com.foo\").getLevel()");
 283             assertDeepEquals(new Handler[] {h}, logger.getHandlers(),
 284                     "Logger.getLogger(\"com.foo\").getHandlers()");
 285             assertEquals(null, manager.getProperty("com.foo.handlers"),
 286                 "com.foo.handlers in " + props);
 287 
 288             // now add some configuration for com.foo.handlers
 289             props.setProperty("com.foo.handlers", MyHandler.class.getName());
 290 
 291             // we didn't call updateConfiguration, so just changing the
 292             // content of props should have had no effect.
 293             assertEquals("FINER", manager.getProperty("com.foo.level"),
 294                 "com.foo.level set to FINER by updateConfiguration");
 295             assertEquals(Level.FINER, logger.getLevel(),
 296                 "Logger.getLogger(\"com.foo\").getLevel()");
 297             assertEquals(null,
 298                     manager.getProperty("com.foo.handlers"),
 299                     "manager.getProperty(\"com.foo.handlers\")");
 300             assertDeepEquals(new Handler[] {h}, logger.getHandlers(),
 301                     "Logger.getLogger(\"com.foo\").getHandlers()");
 302 
 303             // Calls updateConfiguration with a lambda whose effect is a noop.
 304             // This should not change the current configuration, so
 305             // check that the new configuration still has
 306             // com.foo.level=FINER
 307             // and nothing for com.foo.handlers
 308             // check that the logger still has FINER level and still
 309             // has its handlers and that they haven't been reset.
 310             Configure.updateConfigurationWith(props, (k) -> ((o, n) -> o));
 311             assertEquals("FINER", manager.getProperty("com.foo.level"),
 312                 "com.foo.level set to FINER by updateConfiguration");
 313             assertEquals(Level.FINER, logger.getLevel(),
 314                 "Logger.getLogger(\"com.foo\").getLevel()");
 315             assertEquals(null,
 316                     manager.getProperty("com.foo.handlers"),
 317                     "manager.getProperty(\"com.foo.handlers\")");
 318             assertDeepEquals(new Handler[] {h}, logger.getHandlers(),
 319                     "Logger.getLogger(\"com.foo\").getHandlers()");
 320 
 321             // Calls updateConfiguration with a lambda whose effect is to
 322             // take all values from the new configuration.
 323             // This should update the configuration to what is in props, so
 324             // check that the new configuration has
 325             // com.foo.level=FINEST
 326             // com.foo.handlers=SimpleUpdateConfigWithInputStreamTest$MyHandler
 327             // check that the logger now has FINEST level
 328             // and a new handler instance, since the old config
 329             // had no handlers for com.foo and the new config has one.
 330             Configure.updateConfigurationWith(props, (k) -> ((o, n) -> n));
 331             assertEquals("FINEST", manager.getProperty("com.foo.level"),
 332                 "com.foo.level updated by updateConfiguration");
 333             assertEquals(Level.FINEST, logger.getLevel(),
 334                 "Logger.getLogger(\"com.foo\").getLevel()");
 335             assertEquals(MyHandler.class.getName(),
 336                     manager.getProperty("com.foo.handlers"),
 337                     "manager.getProperty(\"com.foo.handlers\")");
 338             Handler[] loggerHandlers = logger.getHandlers().clone();
 339             assertEquals(1, loggerHandlers.length,
 340                     "Logger.getLogger(\"com.foo\").getHandlers().length");
 341             assertEquals(MyHandler.class, loggerHandlers[0].getClass(),
 342                     "Logger.getLogger(\"com.foo\").getHandlers()[0].getClass()");
 343             assertEquals(h.count + 1, ((MyHandler)logger.getHandlers()[0]).count,
 344                     "Logger.getLogger(\"com.foo\").getHandlers()[0].count");
 345 
 346             // Calls updateConfiguration with a lambda whose effect is a noop.
 347             // This should not change the current configuration, so
 348             // check that the new configuration still has
 349             // com.foo.level=FINEST
 350             // com.foo.handlers=SimpleUpdateConfigWithInputStreamTest$MyHandler
 351             // check that the logger still has FINEST level and still
 352             // has its handlers and that they haven't been reset.
 353             Configure.updateConfigurationWith(props, (k) -> ((o, n) -> o));
 354             assertDeepEquals(loggerHandlers, logger.getHandlers(),
 355                     "Logger.getLogger(\"com.foo\").getHandlers()");
 356             assertEquals("FINEST", manager.getProperty("com.foo.level"),
 357                 "com.foo.level updated by updateConfiguration");
 358             assertEquals(Level.FINEST, logger.getLevel(),
 359                 "Logger.getLogger(\"com.foo\").getLevel()");
 360             assertEquals(MyHandler.class.getName(),
 361                     manager.getProperty("com.foo.handlers"),
 362                     "manager.getProperty(\"com.foo.handlers\")");
 363 
 364             // Calls updateConfiguration with a lambda whose effect is to
 365             // take all values from the new configuration.
 366             // Because the content of the props hasn't changed, then
 367             // it should also be a noop.
 368             // check that the new configuration still has
 369             // com.foo.level=FINEST
 370             // com.foo.handlers=SimpleUpdateConfigWithInputStreamTest$MyHandler
 371             // check that the logger still has FINEST level and still
 372             // has its handlers and that they haven't been reset.
 373             Configure.updateConfigurationWith(props, (k) -> ((o, n) -> n));
 374             assertDeepEquals(loggerHandlers, logger.getHandlers(),
 375                     "Logger.getLogger(\"com.foo\").getHandlers()");
 376             assertEquals("FINEST", manager.getProperty("com.foo.level"),
 377                 "com.foo.level updated by updateConfiguration");
 378             assertEquals(Level.FINEST, logger.getLevel(),
 379                 "Logger.getLogger(\"com.foo\").getLevel()");
 380             assertEquals(MyHandler.class.getName(),
 381                     manager.getProperty("com.foo.handlers"),
 382                     "manager.getProperty(\"com.foo.handlers\")");
 383 
 384             // Calls updateConfiguration with a null lambda, whose effect is to
 385             // take all values from the new configuration.
 386             // Because the content of the props hasn't changed, then
 387             // it should also be a noop.
 388             // check that the new configuration still has
 389             // com.foo.level=FINEST
 390             // com.foo.handlers=SimpleUpdateConfigWithInputStreamTest$MyHandler
 391             // check that the logger still has FINEST level and still
 392             // has its handlers and that they haven't been reset.
 393             Configure.updateConfigurationWith(props, (k) -> ((o, n) -> n));
 394             assertDeepEquals(loggerHandlers, logger.getHandlers(),
 395                     "Logger.getLogger(\"com.foo\").getHandlers()");
 396             assertEquals("FINEST", manager.getProperty("com.foo.level"),
 397                 "com.foo.level updated by updateConfiguration");
 398             assertEquals(Level.FINEST, logger.getLevel(),
 399                 "Logger.getLogger(\"com.foo\").getLevel()");
 400             assertEquals(MyHandler.class.getName(),
 401                     manager.getProperty("com.foo.handlers"),
 402                     "manager.getProperty(\"com.foo.handlers\")");
 403 
 404             // now remove com.foo.handlers=SimpleUpdateConfigWithInputStreamTest$MyHandler
 405             // from the configuration file.
 406             props.remove("com.foo.handlers");
 407 
 408             // Calls updateConfiguration with a lambda whose effect is a noop.
 409             // This should not change the current configuration, so
 410             // check that the new configuration still has
 411             // com.foo.level=FINEST
 412             // com.foo.handlers=SimpleUpdateConfigWithInputStreamTest$MyHandler
 413             // check that the logger still has FINEST level and still
 414             // has its handlers and that they haven't been reset.
 415             Configure.updateConfigurationWith(props, (k) -> ((o, n) -> o));
 416             assertDeepEquals(loggerHandlers, logger.getHandlers(),
 417                     "Logger.getLogger(\"com.foo\").getHandlers()");
 418             assertEquals("FINEST", manager.getProperty("com.foo.level"),
 419                 "com.foo.level updated by updateConfiguration");
 420             assertEquals(Level.FINEST, logger.getLevel(),
 421                 "Logger.getLogger(\"com.foo\").getLevel()");
 422             assertEquals(MyHandler.class.getName(),
 423                     manager.getProperty("com.foo.handlers"),
 424                     "manager.getProperty(\"com.foo.handlers\")");
 425 
 426             // Calls updateConfiguration with a lambda whose effect is to
 427             // take all values from the new configuration.
 428             // This should update the configuration to what is in props, so
 429             // check that the new configuration has
 430             // com.foo.level=FINEST
 431             // and nothing for com.foo.handlers
 432             // check that the logger still has FINEST level
 433             // and no handlers, since the old config
 434             // had an handler for com.foo and the new config doesn't.
 435             Configure.updateConfigurationWith(props, (k) -> ((o, n) -> n));
 436             assertDeepEquals(new Handler[0], logger.getHandlers(),
 437                     "Logger.getLogger(\"com.foo\").getHandlers()");
 438             assertEquals("FINEST", manager.getProperty("com.foo.level"),
 439                 "com.foo.level updated by updateConfiguration");
 440             assertEquals(Level.FINEST, logger.getLevel(),
 441                 "Logger.getLogger(\"com.foo\").getLevel()");
 442             assertEquals(null,
 443                     manager.getProperty("com.foo.handlers"),
 444                     "manager.getProperty(\"com.foo.handlers\")");
 445 
 446 
 447         } catch (RuntimeException | Error r) {
 448             throw r;
 449         } catch (Exception x) {
 450             throw new RuntimeException(x);
 451         }
 452     }
 453 
 454     public static void main(String[] args) throws Exception {
 455         if (args == null || args.length == 0) {
 456             args = new String[] { "UNSECURE", "SECURE" };
 457         }
 458         for (String test : args) {
 459             TestCase.valueOf(test).execute(SimpleUpdateConfigWithInputStreamTest::testUpdateConfiguration);
 460         }
 461     }
 462 
 463     static class Configure {
 464         static Policy policy = null;
 465         static void setUp(TestCase test) {
 466             switch (test) {
 467                 case SECURE:
 468                     if (policy == null && System.getSecurityManager() != null) {
 469                         throw new IllegalStateException("SecurityManager already set");
 470                     } else if (policy == null) {
 471                         policy = new SimplePolicy(TestCase.SECURE);
 472                         Policy.setPolicy(policy);
 473                         System.setSecurityManager(new SecurityManager());
 474                     }
 475                     if (System.getSecurityManager() == null) {
 476                         throw new IllegalStateException("No SecurityManager.");
 477                     }
 478                     if (policy == null) {
 479                         throw new IllegalStateException("policy not configured");
 480                     }
 481                     break;
 482                 case UNSECURE:
 483                     if (System.getSecurityManager() != null) {
 484                         throw new IllegalStateException("SecurityManager already set");
 485                     }
 486                     break;
 487                 default:
 488                     throw new InternalError("No such testcase: " + test);
 489             }
 490         }
 491 
 492         static void updateConfigurationWith(Properties propertyFile,
 493                 Function<String,BiFunction<String,String,String>> remapper) {
 494             try {
 495                 ByteArrayOutputStream bytes = new ByteArrayOutputStream();
 496                 propertyFile.store(bytes, propertyFile.getProperty("test.name"));
 497                 ByteArrayInputStream bais = new ByteArrayInputStream(bytes.toByteArray());
 498                 LogManager.getLogManager().updateConfiguration(bais, remapper);
 499             } catch (IOException ex) {
 500                 throw new RuntimeException(ex);
 501             }
 502         }
 503 
 504         static void doPrivileged(Runnable run, ThreadLocal<AtomicBoolean> granter) {
 505             final boolean old = granter.get().getAndSet(true);
 506             try {
 507                 run.run();
 508             } finally {
 509                 granter.get().set(old);
 510             }
 511         }
 512         static <T> T callPrivileged(Callable<T> call,
 513                 ThreadLocal<AtomicBoolean> granter) throws Exception {
 514             final boolean old = granter.get().getAndSet(true);
 515             try {
 516                 return call.call();
 517             } finally {
 518                 granter.get().set(old);
 519             }
 520         }
 521     }
 522 
 523     static final class TestAssertException extends RuntimeException {
 524         TestAssertException(String msg) {
 525             super(msg);
 526         }
 527     }
 528 
 529     private static void assertEquals(long expected, long received, String msg) {
 530         if (expected != received) {
 531             throw new TestAssertException("Unexpected result for " + msg
 532                     + ".\n\texpected: " + expected
 533                     +  "\n\tactual:   " + received);
 534         } else {
 535             System.out.println("Got expected " + msg + ": " + received);
 536         }
 537     }
 538 
 539     private static void assertEquals(String expected, String received, String msg) {
 540         if (!Objects.equals(expected, received)) {
 541             throw new TestAssertException("Unexpected result for " + msg
 542                     + ".\n\texpected: " + expected
 543                     +  "\n\tactual:   " + received);
 544         } else {
 545             System.out.println("Got expected " + msg + ": " + received);
 546         }
 547     }
 548 
 549     private static void assertEquals(Object expected, Object received, String msg) {
 550         if (!Objects.equals(expected, received)) {
 551             throw new TestAssertException("Unexpected result for " + msg
 552                     + ".\n\texpected: " + expected
 553                     +  "\n\tactual:   " + received);
 554         } else {
 555             System.out.println("Got expected " + msg + ": " + received);
 556         }
 557     }
 558 
 559     public static String deepToString(Object o) {
 560         if (o == null) {
 561             return "null";
 562         } else if (o.getClass().isArray()) {
 563             String s;
 564             if (o instanceof Object[])
 565                 s = Arrays.deepToString((Object[]) o);
 566             else if (o instanceof byte[])
 567                 s = Arrays.toString((byte[]) o);
 568             else if (o instanceof short[])
 569                 s = Arrays.toString((short[]) o);
 570             else if (o instanceof int[])
 571                 s = Arrays.toString((int[]) o);
 572             else if (o instanceof long[])
 573                 s = Arrays.toString((long[]) o);
 574             else if (o instanceof char[])
 575                 s = Arrays.toString((char[]) o);
 576             else if (o instanceof float[])
 577                 s = Arrays.toString((float[]) o);
 578             else if (o instanceof double[])
 579                 s = Arrays.toString((double[]) o);
 580             else if (o instanceof boolean[])
 581                 s = Arrays.toString((boolean[]) o);
 582             else
 583                 s = o.toString();
 584             return s;
 585         } else {
 586             return o.toString();
 587         }
 588     }
 589 
 590     private static void assertDeepEquals(Object expected, Object received, String msg) {
 591         if (!Objects.deepEquals(expected, received)) {
 592             throw new TestAssertException("Unexpected result for " + msg
 593                     + ".\n\texpected: " + deepToString(expected)
 594                     +  "\n\tactual:   " + deepToString(received));
 595         } else {
 596             System.out.println("Got expected " + msg + ": " + deepToString(received));
 597         }
 598     }
 599 
 600     final static class PermissionsBuilder {
 601         final Permissions perms;
 602         public PermissionsBuilder() {
 603             this(new Permissions());
 604         }
 605         public PermissionsBuilder(Permissions perms) {
 606             this.perms = perms;
 607         }
 608         public PermissionsBuilder add(Permission p) {
 609             perms.add(p);
 610             return this;
 611         }
 612         public PermissionsBuilder addAll(PermissionCollection col) {
 613             if (col != null) {
 614                 for (Enumeration<Permission> e = col.elements(); e.hasMoreElements(); ) {
 615                     perms.add(e.nextElement());
 616                 }
 617             }
 618             return this;
 619         }
 620         public Permissions toPermissions() {
 621             final PermissionsBuilder builder = new PermissionsBuilder();
 622             builder.addAll(perms);
 623             return builder.perms;
 624         }
 625     }
 626 
 627     public static class SimplePolicy extends Policy {
 628 
 629         final Permissions basic;
 630         final Permissions control;
 631         final Permissions all;
 632         public final static ThreadLocal<AtomicBoolean> allowAll =
 633                 new ThreadLocal<AtomicBoolean>() {
 634             @Override
 635             protected AtomicBoolean initialValue() {
 636                 return new AtomicBoolean();
 637             }
 638         };
 639         public final static ThreadLocal<AtomicBoolean> allowControl =
 640                 new ThreadLocal<AtomicBoolean>() {
 641             @Override
 642             protected AtomicBoolean initialValue() {
 643                 return new AtomicBoolean();
 644             }
 645         };
 646         public SimplePolicy(TestCase test) {
 647             basic = new Permissions();
 648             control = new Permissions();
 649             control.add(new LoggingPermission("control", null));
 650 
 651             // these are used for configuring the test itself...
 652             all = new Permissions();
 653             all.add(new java.security.AllPermission());
 654 
 655         }
 656 
 657         @Override
 658         public boolean implies(ProtectionDomain domain, Permission permission) {
 659             return getPermissions(domain).implies(permission) ||
 660                    DEFAULT_POLICY.implies(domain, permission);
 661         }
 662 
 663         public PermissionCollection permissions() {
 664             PermissionsBuilder builder = new PermissionsBuilder();
 665             if (allowAll.get().get()) {
 666                 builder.addAll(all);
 667             } else {
 668                 builder.addAll(basic);
 669                 if (allowControl.get().get()) {
 670                     builder.addAll(control);
 671                 }
 672             }
 673             return builder.toPermissions();
 674         }
 675 
 676         @Override
 677         public PermissionCollection getPermissions(CodeSource codesource) {
 678             return permissions();
 679         }
 680 
 681         @Override
 682         public PermissionCollection getPermissions(ProtectionDomain domain) {
 683             return permissions();
 684         }
 685     }
 686 
 687 }