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 
  24 import java.io.PrintStream;
  25 import java.lang.System.Logger;
  26 import java.lang.System.Logger.Level;
  27 import java.util.ArrayList;
  28 import java.util.concurrent.atomic.AtomicBoolean;
  29 import java.util.Enumeration;
  30 import java.util.List;
  31 import java.util.ResourceBundle;
  32 import java.util.Set;
  33 import java.lang.reflect.Module;
  34 import jdk.internal.logger.BootstrapLogger;
  35 import jdk.internal.logger.LazyLoggers;
  36 
  37 /*
  38  * @test
  39  * @bug     8144460 8144214
  40  * @summary Cover the logXX and LogEvent.valueOf APIs of BootstrapLogger
  41  *          and logXX APIs of SimpleConsoleLogger.
  42  * @modules java.base/jdk.internal.logger
  43  *          java.base/sun.util.logging
  44  * @build BootstrapLoggerUtils LogStream
  45  * @run main/othervm BootstrapLoggerAPIsTest
  46  */
  47 
  48 public class BootstrapLoggerAPIsTest {
  49 
  50     private static final LogStream ERR = new LogStream();
  51 
  52     public static void main(String[] args) throws Exception {
  53 
  54         final ContentManager MGR = new ContentManager();
  55 
  56         // private reflection hook that allows us to simulate a non booted VM
  57         final AtomicBoolean VM_BOOTED = new AtomicBoolean(false);
  58 
  59         BootstrapLoggerUtils.setBootedHook(() -> VM_BOOTED.get());
  60 
  61         // We replace System.err to check the messages that have been logged
  62         // by the JUL ConsoleHandler and default SimpleConsoleLogger
  63         // implementaion
  64         System.setErr(new PrintStream(ERR));
  65 
  66         VM_BOOTED.getAndSet(false);
  67         if (BootstrapLogger.isBooted()) {
  68             throw new RuntimeException("VM should not be booted!");
  69         }
  70 
  71         final Logger LOGGER =
  72                 LazyLoggers.getLogger("foo.bar", Thread.class.getModule());
  73         final sun.util.logging.PlatformLogger.Level PLATFORM_LEVEL =
  74                 sun.util.logging.PlatformLogger.Level.SEVERE;
  75         final MyResources BUNDLE = new MyResources();
  76 
  77         /*
  78          * Test logXX APIs for interface java.lang.System.Logger. Log content
  79          * before VM is booted should be retained. Log content after VM was
  80          * booted should be flushed instantly. VM is not booted in first round
  81          * of loop, VM is booted in second round of loop.
  82          */
  83         for (int i = 0; i < 2; i++) {
  84             boolean booted = BootstrapLogger.isBooted();
  85 
  86             // make sure there is no [remaining] content in the LogStream.
  87             MGR.failLog("xyz", "throwable #", "MyClass_#", "MyMethod_#");
  88 
  89             /*
  90              * test logXX APIs for interface java.lang.System.Logger.
  91              */
  92             // void log(java.lang.System$Logger$Level,java.util.ResourceBundle,
  93             //          java.lang.String,java.lang.Throwable)
  94             LOGGER.log(Level.ERROR, BUNDLE, "abc #0", new RuntimeException("throwable #0"));
  95             MGR.checkLog(booted, "xyz #0", "throwable #0");
  96 
  97             // void log(java.lang.System$Logger$Level,java.util.ResourceBundle,
  98             //          java.lang.String,java.lang.Object[])
  99             LOGGER.log(Level.ERROR, BUNDLE, "abc #1");
 100             MGR.checkLog(booted, "xyz #1");
 101 
 102             // void log(java.lang.System$Logger$Level,java.lang.String,java.lang.Object[])
 103             LOGGER.log(Level.ERROR, BUNDLE, "abc {0}", "#2");
 104             MGR.checkLog(booted, "xyz #2");
 105 
 106             // void log(java.lang.System$Logger$Level,java.lang.String,java.lang.Throwable)
 107             LOGGER.log(Level.ERROR, "xyz #3", new RuntimeException("throwable #3"));
 108             MGR.checkLog(booted, "xyz #3", "throwable #3");
 109 
 110             // void log(java.lang.System$Logger$Level,java.util.function.Supplier)
 111             LOGGER.log(Level.ERROR, () -> "xyz #4");
 112             MGR.checkLog(booted, "xyz #4");
 113 
 114             // void log(java.lang.System$Logger$Level,java.lang.Object)
 115             LOGGER.log(Level.ERROR, new MyObject("xyz #5"));
 116             MGR.checkLog(booted, "xyz #5");
 117 
 118             // void log(java.lang.System$Logger$Level,java.util.function.Supplier,
 119             //          java.lang.Throwable)
 120             LOGGER.log(Level.ERROR, () -> "xyz #6", new RuntimeException("throwable #6"));
 121             MGR.checkLog(booted, "xyz #6", "throwable #6");
 122 
 123 
 124             /*
 125              * test logXX APIs for interface
 126              * sun.util.logging.PlatformLogger.Bridge.
 127              */
 128             sun.util.logging.PlatformLogger.Bridge bridge =
 129                     (sun.util.logging.PlatformLogger.Bridge) LOGGER;
 130 
 131             // void log(sun.util.logging.PlatformLogger$Level,java.lang.String)
 132             bridge.log(PLATFORM_LEVEL, "xyz #7");
 133             MGR.checkLog(booted, "xyz #7");
 134 
 135             // void log(sun.util.logging.PlatformLogger$Level,java.lang.String,java.lang.Throwable)
 136             bridge.log(PLATFORM_LEVEL, "xyz #8", new RuntimeException("throwable #8"));
 137             MGR.checkLog(booted, "xyz #8", "throwable #8");
 138 
 139             // void log(sun.util.logging.PlatformLogger$Level,java.lang.String,java.lang.Object[])
 140             bridge.log(PLATFORM_LEVEL, "xyz {0}", "#9");
 141             MGR.checkLog(booted, "xyz #9");
 142 
 143             // void log(sun.util.logging.PlatformLogger$Level,java.util.function.Supplier)
 144             bridge.log(PLATFORM_LEVEL, () -> "xyz #10");
 145             MGR.checkLog(booted, "xyz #10");
 146 
 147             // void log(sun.util.logging.PlatformLogger$Level,
 148             //        java.lang.Throwable,java.util.function.Supplier)
 149             bridge.log(PLATFORM_LEVEL, new RuntimeException("throwable #11"), () -> "xyz #11");
 150             MGR.checkLog(booted, "xyz #11", "throwable #11");
 151 
 152             // void logp(sun.util.logging.PlatformLogger$Level,java.lang.String,
 153             //          java.lang.String,java.lang.String)
 154             bridge.logp(PLATFORM_LEVEL, "MyClass_#12", "MyMethod_#12", "xyz #12");
 155             MGR.checkLog(booted, "xyz #12", "MyClass_#12", "MyMethod_#12");
 156 
 157             // void logp(sun.util.logging.PlatformLogger$Level,java.lang.String,
 158             //          java.lang.String,java.util.function.Supplier)
 159             bridge.logp(PLATFORM_LEVEL, "MyClass_#13", "MyMethod_#13", () -> "xyz #13");
 160             MGR.checkLog(booted, "xyz #13", "MyClass_#13", "MyMethod_#13");
 161 
 162             // void logp(sun.util.logging.PlatformLogger$Level,java.lang.String,
 163             //          java.lang.String,java.lang.String,java.lang.Object[])
 164             bridge.logp(PLATFORM_LEVEL, "MyClass_#14", "MyMethod_#14", "xyz {0}", "#14");
 165             MGR.checkLog(booted, "xyz #14", "MyClass_#14", "MyMethod_#14");
 166 
 167             // void logp(sun.util.logging.PlatformLogger$Level,java.lang.String,
 168             //          java.lang.String,java.lang.String,java.lang.Throwable)
 169             bridge.logp(PLATFORM_LEVEL, "MyClass_#15", "MyMethod_#15",
 170                     "xyz #15", new RuntimeException("throwable #15"));
 171             MGR.checkLog(booted, "xyz #15", "throwable #15", "MyClass_#15", "MyMethod_#15");
 172 
 173             // void logp(sun.util.logging.PlatformLogger$Level,java.lang.String,
 174             //          java.lang.String,java.lang.Throwable,java.util.function.Supplier)
 175             bridge.logp(PLATFORM_LEVEL, "MyClass_#16", "MyMethod_#16",
 176                     new RuntimeException("throwable #16"), () -> "xyz #16");
 177             MGR.checkLog(booted, "xyz #16", "throwable #16", "MyClass_#16", "MyMethod_#16");
 178 
 179             // void logrb(sun.util.logging.PlatformLogger$Level,java.lang.String,java.lang.String,
 180             //          java.util.ResourceBundle,java.lang.String,java.lang.Object[])
 181             bridge.logrb(PLATFORM_LEVEL, "MyClass_#17", "MyMethod_#17",
 182                     BUNDLE, "abc {0}", "#17");
 183             MGR.checkLog(booted, "xyz #17", "MyClass_#17", "MyMethod_#17");
 184 
 185             // void logrb(sun.util.logging.PlatformLogger$Level,java.lang.String,java.lang.String,
 186             //          java.util.ResourceBundle,java.lang.String,java.lang.Throwable)
 187             bridge.logrb(PLATFORM_LEVEL, "MyClass_#18", "MyMethod_#18",
 188                     BUNDLE, "abc #18", new RuntimeException("throwable #18"));
 189             MGR.checkLog(booted, "xyz #18", "throwable #18", "MyClass_#18", "MyMethod_#18");
 190 
 191             // void logrb(sun.util.logging.PlatformLogger$Level,java.util.ResourceBundle,
 192             //          java.lang.String,java.lang.Object[])
 193             bridge.logrb(PLATFORM_LEVEL, BUNDLE, "abc {0}", "#19");
 194             MGR.checkLog(booted, "xyz #19");
 195 
 196             // void logrb(sun.util.logging.PlatformLogger$Level,java.util.ResourceBundle,
 197             //          java.lang.String,java.lang.Throwable)
 198             bridge.logrb(PLATFORM_LEVEL, BUNDLE, "abc #20",
 199                         new RuntimeException("throwable #20"));
 200             MGR.checkLog(booted, "xyz #20", "throwable #20");
 201 
 202             /*
 203              * retained log content should be flushed after VM is booted.
 204              */
 205             if (!booted) {
 206                 VM_BOOTED.getAndSet(true);
 207                 // trigger the flush, make sure to call LOGGER.log(...)
 208                 // after VM_BOOTED.getAndSet(true) and before MGR.assertCachedLog()
 209                 LOGGER.log(Level.ERROR, "VM was just booted! This log should flush the cached logs.");
 210                 MGR.assertCachedLog();
 211             }
 212         }
 213     }
 214 
 215     private static class ContentManager {
 216         final List<String[]> cached = new ArrayList<String[]>();
 217         String[] last;
 218 
 219         public void cache() {
 220             cached.add(last);
 221         }
 222 
 223         public ContentManager failLog(String... nonexistent) {
 224             last = nonexistent;
 225             for (String c : nonexistent) {
 226                 if (ERR.drain().contains(c)) {
 227                     throw new RuntimeException("Content \"" + nonexistent
 228                             + "\" should not exist in the log!");
 229                 }
 230             }
 231             return this;
 232         }
 233 
 234         public void assertLog(String... logs) {
 235             String log = ERR.drain();
 236             for (String str : logs) {
 237                 if (!log.contains(str)) {
 238                     throw new RuntimeException("Content \"" + str + "\" does not exist in the log!");
 239                 }
 240             }
 241         }
 242 
 243         public void checkLog(boolean booted, String... logs) {
 244             if (!booted) {
 245                 failLog(logs).cache();
 246             } else {
 247                 assertLog(logs);
 248             }
 249         }
 250 
 251         public void assertCachedLog() {
 252             String log = ERR.drain();
 253             for (String[] arr : cached) {
 254                 for (String c : arr) {
 255                     if (!log.contains(c)) {
 256                         throw new RuntimeException("Content \"" + c + "\" does not exist in the log!");
 257                     }
 258                 }
 259             }
 260         }
 261     }
 262 
 263     private static class MyObject {
 264         String str;
 265 
 266         public MyObject(String str) {
 267             this.str = str;
 268         }
 269 
 270         public String toString() {
 271             return str;
 272         }
 273     }
 274 
 275     private static class MyResources extends ResourceBundle {
 276         public Object handleGetObject(String key) {
 277             if (key.contains("abc #") || key.contains("abc {")) {
 278                 return key.replaceAll("abc ", "xyz ");
 279             }
 280             return null;
 281         }
 282 
 283         public Enumeration<String> getKeys() {
 284             return null;
 285         }
 286     }
 287 }