1 /*
   2  * Copyright (c) 2013, 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 
  24 /*
  25  * @test
  26  * @bug 8029781 8030801
  27  * @summary Test which verifies that various JDK logging Handlers are
  28  *          configured correctly from defaults and/or LogManager properties
  29  *          as specified in javadoc and that no special
  30  *          logging permission is required for instantiating them.
  31  * @run main/othervm HandlersConfigTest default
  32  * @run main/othervm HandlersConfigTest configured
  33  */
  34 
  35 import java.io.IOException;
  36 import java.io.OutputStream;
  37 import java.lang.reflect.Field;
  38 import java.net.ServerSocket;
  39 import java.net.URL;
  40 import java.util.Objects;
  41 import java.util.logging.ConsoleHandler;
  42 import java.util.logging.Filter;
  43 import java.util.logging.Formatter;
  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.MemoryHandler;
  49 import java.util.logging.SimpleFormatter;
  50 import java.util.logging.SocketHandler;
  51 import java.util.logging.StreamHandler;
  52 import java.util.logging.XMLFormatter;
  53 
  54 public abstract class HandlersConfigTest implements Runnable {
  55 
  56     public static void main(String[] args) {
  57         switch (args.length == 1 ? args[0] : "usage") {
  58             case "default":
  59                 new Default().run();
  60                 break;
  61             case "configured":
  62                 new Configured().run();
  63                 break;
  64             default:
  65                 System.err.println("Usage: HandlersConfigTest [default|configured]");
  66                 break;
  67         }
  68     }
  69 
  70     static final String CONFIG_FILE_PROPERTY = "java.util.logging.config.file";
  71     final Field memoryHandlerTarget, memoryHandlerSize, streamHandlerOutput;
  72     final ServerSocket serverSocket;
  73 
  74     HandlersConfigTest() {
  75         // establish access to private fields
  76         try {
  77             memoryHandlerTarget = MemoryHandler.class.getDeclaredField("target");
  78             memoryHandlerTarget.setAccessible(true);
  79             memoryHandlerSize = MemoryHandler.class.getDeclaredField("size");
  80             memoryHandlerSize.setAccessible(true);
  81             streamHandlerOutput = StreamHandler.class.getDeclaredField("output");
  82             streamHandlerOutput.setAccessible(true);
  83         } catch (NoSuchFieldException e) {
  84             throw new AssertionError(e);
  85         }
  86 
  87         // load logging.propertes for the test
  88         String rname = getClass().getName().replace('.', '/') + ".props";
  89         URL url = getClass().getClassLoader().getResource(rname);
  90         if (url == null || !"file".equals(url.getProtocol())) {
  91             throw new IllegalStateException("Resource: " + rname + " not found or not on file: " + url);
  92         }
  93         System.setProperty(CONFIG_FILE_PROPERTY, url.getFile());
  94 
  95         // create ServerSocket as a target for SocketHandler
  96         try {
  97             serverSocket = new ServerSocket(0); // auto allocated port
  98         } catch (IOException e) {
  99             throw new AssertionError(e);
 100         }
 101 
 102         // activate security
 103         System.setSecurityManager(new SecurityManager() {
 104             @Override
 105             public void checkConnect(String host, int port) {
 106                 // allow socket connections
 107             }
 108         });
 109 
 110         // initialize logging system
 111         LogManager.getLogManager();
 112     }
 113 
 114     // check that defaults are used as specified by javadoc
 115 
 116     public static class Default extends HandlersConfigTest {
 117         public static void main(String[] args) {
 118             new Default().run();
 119         }
 120 
 121         @Override
 122         public void run() {
 123             // MemoryHandler
 124 
 125             check(new MemoryHandler(),
 126                 Level.ALL, null, null, SimpleFormatter.class,
 127                 ConfiguredHandler.class, 1000, Level.SEVERE);
 128 
 129             check(new MemoryHandler(new SpecifiedHandler(), 100, Level.WARNING),
 130                 Level.ALL, null, null, SimpleFormatter.class,
 131                 SpecifiedHandler.class, 100, Level.WARNING);
 132 
 133             // StreamHandler
 134 
 135             check(new StreamHandler(),
 136                 Level.INFO, null, null, SimpleFormatter.class,
 137                 null);
 138 
 139             check(new StreamHandler(System.out, new SpecifiedFormatter()),
 140                 Level.INFO, null, null, SpecifiedFormatter.class,
 141                 System.out);
 142 
 143             // ConsoleHandler
 144 
 145             check(new ConsoleHandler(),
 146                 Level.INFO, null, null, SimpleFormatter.class,
 147                 System.err);
 148 
 149             // SocketHandler (use the ServerSocket's port)
 150 
 151             try {
 152                 check(new SocketHandler("localhost", serverSocket.getLocalPort()),
 153                     Level.ALL, null, null, XMLFormatter.class);
 154             } catch (IOException e) {
 155                 throw new RuntimeException("Can't connect to localhost:" + serverSocket.getLocalPort(), e);
 156             }
 157         }
 158     }
 159 
 160     // check that LogManager properties configuration is respected
 161 
 162     public static class Configured extends HandlersConfigTest {
 163         public static void main(String[] args) {
 164             new Configured().run();
 165         }
 166 
 167         @Override
 168         public void run() {
 169             // MemoryHandler
 170 
 171             check(new MemoryHandler(),
 172                 Level.FINE, null, ConfiguredFilter.class, ConfiguredFormatter.class,
 173                 ConfiguredHandler.class, 123, Level.FINE);
 174 
 175             check(new MemoryHandler(new SpecifiedHandler(), 100, Level.WARNING),
 176                 Level.FINE, null, ConfiguredFilter.class, ConfiguredFormatter.class,
 177                 SpecifiedHandler.class, 100, Level.WARNING);
 178 
 179             // StreamHandler
 180 
 181             check(new StreamHandler(),
 182                 Level.FINE, "ASCII", ConfiguredFilter.class, ConfiguredFormatter.class,
 183                 null);
 184 
 185             check(new StreamHandler(System.out, new SpecifiedFormatter()),
 186                 Level.FINE, "ASCII", ConfiguredFilter.class, SpecifiedFormatter.class,
 187                 System.out);
 188 
 189             // ConsoleHandler
 190 
 191             check(new ConsoleHandler(),
 192                 Level.FINE, "ASCII", ConfiguredFilter.class, ConfiguredFormatter.class,
 193                 System.err);
 194 
 195             // SocketHandler (use the ServerSocket's port)
 196 
 197             try {
 198                 check(new SocketHandler("localhost", serverSocket.getLocalPort()),
 199                     Level.FINE, "ASCII", ConfiguredFilter.class, ConfiguredFormatter.class);
 200             } catch (Exception e) {
 201                 throw new RuntimeException("Can't connect to localhost:" + serverSocket.getLocalPort(), e);
 202             }
 203         }
 204     }
 205 
 206     // test infrastructure
 207 
 208     void check(Handler handler,
 209                Level expectedLevel,
 210                String expectedEncoding,
 211                Class<? extends Filter> expectedFilterType,
 212                Class<? extends Formatter> expectedFormatterType) {
 213         checkEquals(handler, "level", handler.getLevel(), expectedLevel);
 214         checkEquals(handler, "encoding", handler.getEncoding(), expectedEncoding);
 215         checkType(handler, "filter", handler.getFilter(), expectedFilterType);
 216         checkType(handler, "formatter", handler.getFormatter(), expectedFormatterType);
 217     }
 218 
 219     void check(MemoryHandler handler,
 220                Level expectedLevel,
 221                String expectedEncoding,
 222                Class<? extends Filter> expectedFilterType,
 223                Class<? extends Formatter> expectedFormatterType,
 224                Class<? extends Handler> expextedTargetType,
 225                int expextedSize,
 226                Level expectedPushLevel) {
 227         checkType(handler, "target", getTarget(handler), expextedTargetType);
 228         checkEquals(handler, "size", getSize(handler), expextedSize);
 229         checkEquals(handler, "pushLevel", handler.getPushLevel(), expectedPushLevel);
 230         check(handler, expectedLevel, expectedEncoding, expectedFilterType, expectedFormatterType);
 231     }
 232 
 233     void check(StreamHandler handler,
 234                Level expectedLevel,
 235                String expectedEncoding,
 236                Class<? extends Filter> expectedFilterType,
 237                Class<? extends Formatter> expectedFormatterType,
 238                OutputStream expectedOutputStream) {
 239         checkEquals(handler, "outputStream", getOutput(handler), expectedOutputStream);
 240         check(handler, expectedLevel, expectedEncoding, expectedFilterType, expectedFormatterType);
 241     }
 242 
 243     <T> void checkEquals(Handler handler, String property, T value, T expectedValue) {
 244         if (!Objects.equals(value, expectedValue)) {
 245             fail(handler, property + ": " + value + ", expected " + property + ": " + expectedValue);
 246         }
 247     }
 248 
 249     <T> void checkType(Handler handler, String property, T value, Class<? extends T> expectedType) {
 250         if (!(expectedType == null && value == null || expectedType != null && expectedType.isInstance(value))) {
 251             Class<?> type = value == null ? null : value.getClass();
 252             fail(handler, property + " type: " + type + ", expected " + property + " type: " + expectedType);
 253         }
 254     }
 255 
 256     void fail(Handler handler, String message) {
 257         throw new AssertionError("Handler: " + handler.getClass().getName() +
 258                                  ", configured with: " + getClass().getName() +
 259                                  ", " + message);
 260     }
 261 
 262     Handler getTarget(MemoryHandler memoryHandler) {
 263         try {
 264             return (Handler) memoryHandlerTarget.get(memoryHandler);
 265         } catch (IllegalAccessException e) {
 266             throw new IllegalAccessError(e.getMessage());
 267         }
 268     }
 269 
 270     int getSize(MemoryHandler memoryHandler) {
 271         try {
 272             return (int) memoryHandlerSize.get(memoryHandler);
 273         } catch (IllegalAccessException e) {
 274             throw new IllegalAccessError(e.getMessage());
 275         }
 276     }
 277 
 278     OutputStream getOutput(StreamHandler streamHandler) {
 279         try {
 280             return (OutputStream) streamHandlerOutput.get(streamHandler);
 281         } catch (IllegalAccessException e) {
 282             throw new IllegalAccessError(e.getMessage());
 283         }
 284     }
 285 
 286     // various independent types of Formatters, Filters, Handlers...
 287 
 288     public static class SpecifiedFormatter extends Formatter {
 289         @Override
 290         public String format(LogRecord record) {
 291             return String.valueOf(record);
 292         }
 293     }
 294 
 295     public static class SpecifiedHandler extends Handler {
 296         @Override
 297         public void publish(LogRecord record) { }
 298 
 299         @Override
 300         public void flush() { }
 301 
 302         @Override
 303         public void close() throws SecurityException { }
 304     }
 305 
 306     public static class ConfiguredFormatter extends Formatter {
 307         @Override
 308         public String format(LogRecord record) {
 309             return String.valueOf(record);
 310         }
 311     }
 312 
 313     public static class ConfiguredFilter implements Filter {
 314         @Override
 315         public boolean isLoggable(LogRecord record) {
 316             return true;
 317         }
 318     }
 319 
 320     public static class ConfiguredHandler extends Handler {
 321         @Override
 322         public void publish(LogRecord record) { }
 323 
 324         @Override
 325         public void flush() { }
 326 
 327         @Override
 328         public void close() throws SecurityException { }
 329     }
 330 }