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