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