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