1 /*
   2  * Copyright (c) 2017, 2018, 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.IOException;
  24 import java.nio.file.Files;
  25 import java.nio.file.Path;
  26 import java.nio.file.Paths;
  27 import java.nio.file.StandardCopyOption;
  28 import java.util.Collections;
  29 import java.util.List;
  30 import java.util.logging.Handler;
  31 import java.util.logging.Level;
  32 import java.util.logging.LogManager;
  33 import java.util.logging.Logger;
  34 import java.util.stream.Collectors;
  35 import java.util.stream.Stream;
  36 
  37 /**
  38  * @test
  39  * @bug 8191033
  40  * @build custom.DotHandler custom.Handler
  41  * @run main/othervm RootLoggerHandlers
  42  * @run main/othervm/java.security.policy==test.policy RootLoggerHandlers
  43  * @author danielfuchs
  44  */
  45 public class RootLoggerHandlers {
  46 
  47     public static final Path SRC_DIR =
  48             Paths.get(System.getProperty("test.src", "src"));
  49     public static final Path USER_DIR =
  50             Paths.get(System.getProperty("user.dir", "."));
  51     public static final Path CONFIG_FILE = Paths.get("logging.properties");
  52 
  53     // Uncomment this to run the test on Java 8. Java 8 does not have
  54     // List.of(...)
  55     //    static final class List {
  56     //        static <T> java.util.List<T> of(T... items) {
  57     //            return Collections.unmodifiableList(Arrays.asList(items));
  58     //        }
  59     //    }
  60 
  61     public static void main(String[] args) throws IOException {
  62         Path initialProps = SRC_DIR.resolve(CONFIG_FILE);
  63         Path loggingProps = USER_DIR.resolve(CONFIG_FILE);
  64         System.setProperty("java.util.logging.config.file", loggingProps.toString());
  65         Files.copy(initialProps, loggingProps, StandardCopyOption.REPLACE_EXISTING);
  66         System.out.println("Root level is: " + Logger.getLogger("").getLevel());
  67         if (Logger.getLogger("").getLevel() != Level.INFO) {
  68             throw new RuntimeException("Expected root level INFO, got: "
  69                                         + Logger.getLogger("").getLevel());
  70         }
  71         // Verify that we have two handlers. One was configured with
  72         // handlers=custom.Handler, the other with
  73         // .handlers=custom.DotHandler
  74         // Verify that exactly one of the two handlers is a custom.Handler
  75         // Verify that exactly one of the two handlers is a custom.DotHandler
  76         // Verify that the two handlers has an id of '1'
  77         checkHandlers(Logger.getLogger(""),
  78                 Logger.getLogger("").getHandlers(),
  79                 1L,
  80                 custom.Handler.class,
  81                 custom.DotHandler.class);
  82         checkHandlers(Logger.getLogger("global"),
  83                 Logger.getGlobal().getHandlers(),
  84                 1L,
  85                 custom.GlobalHandler.class);
  86 
  87         // The log message "hi" should appear twice on the console.
  88         // We don't check that. This is just for log analysis in case
  89         // of test failure.
  90         Logger.getAnonymousLogger().info("hi");
  91 
  92         // Change the root logger level to FINE in the properties file
  93         // and reload the configuration.
  94         Files.write(loggingProps,
  95                 Files.lines(initialProps)
  96                         .map((s) -> s.replace("INFO", "FINE"))
  97                         .collect(Collectors.toList()));
  98         LogManager.getLogManager().readConfiguration();
  99 
 100         System.out.println("Root level is: " + Logger.getLogger("").getLevel());
 101         if (Logger.getLogger("").getLevel() != Level.FINE) {
 102             throw new RuntimeException("Expected root level FINE, got: "
 103                     + Logger.getLogger("").getLevel());
 104         }
 105 
 106         // Verify that we have now only one handler, configured with
 107         // handlers=custom.Handler, and that the other configured with
 108         // .handlers=custom.DotHandler was ignored.
 109         // Verify that the handler is a custom.Handler
 110         // Verify that the handler has an id of '2'
 111         checkHandlers(Logger.getLogger(""),
 112                 Logger.getLogger("").getHandlers(),
 113                 2L,
 114                 custom.Handler.class);
 115         checkHandlers(Logger.getGlobal(),
 116                 Logger.getGlobal().getHandlers(),
 117                 1L);
 118 
 119         // The log message "there" should appear only once on the console.
 120         // We don't check that. This is just for log analysis in case
 121         // of test failure.
 122         Logger.getAnonymousLogger().info("there!");
 123 
 124         // Change the root logger level to FINER in the properties file
 125         // and reload the configuration.
 126         Files.write(loggingProps,
 127                 Files.lines(initialProps)
 128                         .map((s) -> s.replace("INFO", "FINER"))
 129                         .collect(Collectors.toList()));
 130         LogManager.getLogManager().readConfiguration();
 131 
 132         System.out.println("Root level is: " + Logger.getLogger("").getLevel());
 133         if (Logger.getLogger("").getLevel() != Level.FINER) {
 134             throw new RuntimeException("Expected root level FINER, got: "
 135                     + Logger.getLogger("").getLevel());
 136         }
 137 
 138         // Verify that we have only one handler, configured with
 139         // handlers=custom.Handler, and that the other configured with
 140         // .handlers=custom.DotHandler was ignored.
 141         // Verify that the handler is a custom.Handler
 142         // Verify that the handler has an id of '3'
 143         checkHandlers(Logger.getLogger(""),
 144                 Logger.getLogger("").getHandlers(),
 145                 3L,
 146                 custom.Handler.class);
 147         checkHandlers(Logger.getGlobal(),
 148                 Logger.getGlobal().getHandlers(),
 149                 1L);
 150 
 151         LogManager.getLogManager().reset();
 152         LogManager.getLogManager().updateConfiguration((s) -> (o,n) -> n);
 153         // Verify that we have only one handler, configured with
 154         // handlers=custom.Handler, and that the other configured with
 155         // .handlers=custom.DotHandler was ignored.
 156         // Verify that the handler is a custom.Handler
 157         // Verify that the handler has an id of '4'
 158         checkHandlers(Logger.getLogger(""),
 159                 Logger.getLogger("").getHandlers(),
 160                 4L,
 161                 custom.Handler.class);
 162         checkHandlers(Logger.getGlobal(),
 163                 Logger.getGlobal().getHandlers(),
 164                 2L,
 165                 custom.GlobalHandler.class);
 166 
 167         LogManager.getLogManager().updateConfiguration((s) -> (o,n) -> n);
 168         // Verify that we have only one handler, configured with
 169         // handlers=custom.Handler, and that the other configured with
 170         // .handlers=custom.DotHandler was ignored.
 171         // Verify that the handler is a custom.Handler
 172         // Verify that the handler has an id of '4'
 173         checkHandlers(Logger.getLogger(""),
 174                 Logger.getLogger("").getHandlers(),
 175                 4L,
 176                 custom.Handler.class);
 177         checkHandlers(Logger.getGlobal(),
 178                 Logger.getGlobal().getHandlers(),
 179                 2L,
 180                 custom.GlobalHandler.class);
 181 
 182 
 183         // The log message "done" should appear only once on the console.
 184         // We don't check that. This is just for log analysis in case
 185         // of test failure.
 186         Logger.getAnonymousLogger().info("done!");
 187     }
 188 
 189     static void checkHandlers(Logger logger, Handler[] handlers, Long expectedID, Class<?>... clz) {
 190         // Verify that we have the expected number of handlers.
 191         if (Stream.of(handlers).count() != clz.length) {
 192             throw new RuntimeException("Expected " + clz.length + " handlers, got: "
 193                     + List.of(logger.getHandlers()));
 194         }
 195         for (Class<?> cl : clz) {
 196             // Verify that the handlers are of the expected class.
 197             // For each class, we should have exactly one handler
 198             // of that class.
 199             if (Stream.of(handlers)
 200                     .map(Object::getClass)
 201                     .filter(cl::equals)
 202                     .count() != 1) {
 203                 throw new RuntimeException("Expected one " + cl +", got: "
 204                         + List.of(logger.getHandlers()));
 205             }
 206         }
 207         // Verify that all handlers have the expected ID
 208         if (Stream.of(logger.getHandlers())
 209                 .map(RootLoggerHandlers::getId)
 210                 .filter(expectedID::equals)
 211                 .count() != clz.length) {
 212             throw new RuntimeException("Expected ids to be " + expectedID + ", got: "
 213                     + List.of(logger.getHandlers()));
 214         }
 215     }
 216 
 217     static long getId(Handler h) {
 218         if (h instanceof custom.Handler) {
 219             return ((custom.Handler)h).id;
 220         }
 221         if (h instanceof custom.DotHandler) {
 222             return ((custom.DotHandler)h).id;
 223         }
 224         if (h instanceof custom.GlobalHandler) {
 225             return ((custom.GlobalHandler)h).id;
 226         }
 227         return -1;
 228     }
 229 }