Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/test/jdk/java/lang/System/LoggerFinder/internal/api/LoggerFinderAPITest.java
41161 views
1
/*
2
* Copyright (c) 2015, 2016, 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 8140364
27
* @author danielfuchs
28
* @summary JDK implementation specific unit test for JDK internal artifacts.
29
* Tests the consistency of the LoggerFinder and JDK extensions.
30
* @modules java.base/sun.util.logging
31
* java.base/jdk.internal.logger
32
* java.logging
33
* @run main LoggerFinderAPITest
34
*/
35
36
37
import java.lang.reflect.Method;
38
import java.lang.reflect.Modifier;
39
import java.util.ArrayList;
40
import java.util.Arrays;
41
import java.util.Collection;
42
import java.util.Collections;
43
import java.util.Enumeration;
44
import java.util.HashMap;
45
import java.util.LinkedHashMap;
46
import java.util.LinkedHashSet;
47
import java.util.List;
48
import java.util.Map;
49
import java.util.ResourceBundle;
50
import java.util.function.Supplier;
51
import java.util.logging.ConsoleHandler;
52
import java.util.logging.Handler;
53
import java.util.logging.LogRecord;
54
import java.util.logging.Logger;
55
import java.util.regex.Matcher;
56
import java.util.regex.Pattern;
57
import java.util.stream.Collectors;
58
import java.util.stream.Stream;
59
import sun.util.logging.PlatformLogger;
60
61
public class LoggerFinderAPITest {
62
63
static final Class<java.lang.System.Logger> spiLoggerClass
64
= java.lang.System.Logger.class;
65
static final Class<java.lang.System.Logger> jdkLoggerClass
66
= java.lang.System.Logger.class;
67
static final Class<sun.util.logging.PlatformLogger.Bridge> bridgeLoggerClass
68
= sun.util.logging.PlatformLogger.Bridge.class;
69
static final Class<java.util.logging.Logger> julLoggerClass
70
= java.util.logging.Logger.class;
71
static final Class<sun.util.logging.PlatformLogger.Bridge> julLogProducerClass
72
= PlatformLogger.Bridge.class;
73
static final Pattern julLogNames = Pattern.compile(
74
"^((log(p|rb)?)|severe|warning|info|config|fine|finer|finest|isLoggable)$");
75
static final Collection<Method> julLoggerIgnores;
76
static {
77
List<Method> ignores = new ArrayList<>();
78
try {
79
ignores.add(julLoggerClass.getDeclaredMethod("log", LogRecord.class));
80
} catch (NoSuchMethodException | SecurityException ex) {
81
throw new ExceptionInInitializerError(ex);
82
}
83
julLoggerIgnores = Collections.unmodifiableList(ignores);
84
}
85
86
87
88
// Don't require LoggerBridge to have a body for those methods
89
interface LoggerBridgeMethodsWithNoBody extends
90
PlatformLogger.Bridge, java.lang.System.Logger {
91
92
@Override
93
public default String getName() {
94
throw new UnsupportedOperationException("Not supported yet.");
95
}
96
97
@Override
98
public default boolean isLoggable(PlatformLogger.Level level) {
99
throw new UnsupportedOperationException("Not supported yet.");
100
}
101
102
@Override
103
public default void log(sun.util.logging.PlatformLogger.Level level,
104
String msg, Throwable thrown) {
105
}
106
@Override
107
public default void log(sun.util.logging.PlatformLogger.Level level,
108
Throwable thrown, Supplier<String> msgSupplier) {
109
}
110
@Override
111
public default void log(sun.util.logging.PlatformLogger.Level level,
112
Supplier<String> msgSupplier) {
113
}
114
@Override
115
public default void log(sun.util.logging.PlatformLogger.Level level, String msg) {
116
}
117
@Override
118
public default void log(sun.util.logging.PlatformLogger.Level level,
119
String format, Object... params) {
120
}
121
@Override
122
public default void logrb(sun.util.logging.PlatformLogger.Level level,
123
ResourceBundle bundle, String key, Throwable thrown) {
124
}
125
@Override
126
public default void logrb(sun.util.logging.PlatformLogger.Level level,
127
ResourceBundle bundle, String format, Object... params) {
128
}
129
130
@Override
131
public default void logrb(PlatformLogger.Level level,
132
String sourceClass, String sourceMethod,
133
ResourceBundle bundle, String msg, Throwable thrown) {
134
}
135
136
@Override
137
public default void logrb(PlatformLogger.Level level, String sourceClass,
138
String sourceMethod, ResourceBundle bundle, String msg,
139
Object... params) {
140
}
141
142
@Override
143
public default void logp(PlatformLogger.Level level, String sourceClass,
144
String sourceMethod, Supplier<String> msgSupplier) {
145
}
146
147
@Override
148
public default void logp(PlatformLogger.Level level, String sourceClass,
149
String sourceMethod, String msg, Object... params) {
150
}
151
152
@Override
153
public default void logp(PlatformLogger.Level level, String sourceClass,
154
String sourceMethod, String msg, Throwable thrown) {
155
}
156
157
@Override
158
public default void logp(PlatformLogger.Level level, String sourceClass,
159
String sourceMethod, String msg) {
160
}
161
162
@Override
163
public default void logp(PlatformLogger.Level level, String sourceClass,
164
String sourceMethod, Throwable thrown,
165
Supplier<String> msgSupplier) {
166
}
167
168
static boolean requiresDefaultBodyFor(Method m) {
169
try {
170
Method m2 = LoggerBridgeMethodsWithNoBody.class
171
.getDeclaredMethod(m.getName(),
172
m.getParameterTypes());
173
return !m2.isDefault();
174
} catch (NoSuchMethodException x) {
175
return true;
176
}
177
}
178
}
179
180
final boolean warnDuplicateMappings;
181
public LoggerFinderAPITest(boolean verbose) {
182
this.warnDuplicateMappings = verbose;
183
for (Handler h : Logger.getLogger("").getHandlers()) {
184
if (h instanceof ConsoleHandler) {
185
Logger.getLogger("").removeHandler(h);
186
}
187
}
188
Logger.getLogger("").addHandler( new Handler() {
189
@Override
190
public void publish(LogRecord record) {
191
StringBuilder builder = new StringBuilder();
192
builder.append("GOT LogRecord: ")
193
.append(record.getLevel().getLocalizedName())
194
.append(": [").append(record.getLoggerName())
195
.append("] ").append(record.getSourceClassName())
196
.append('.')
197
.append(record.getSourceMethodName()).append(" -> ")
198
.append(record.getMessage())
199
.append(' ')
200
.append(record.getParameters() == null ? ""
201
: Arrays.toString(record.getParameters()))
202
;
203
System.out.println(builder);
204
if (record.getThrown() != null) {
205
record.getThrown().printStackTrace(System.out);
206
}
207
}
208
@Override public void flush() {}
209
@Override public void close() {}
210
});
211
}
212
213
public Stream<Method> getJulLogMethodStream(Class<?> loggerClass) {
214
215
return Stream.of(loggerClass.getMethods()).filter((x) -> {
216
final Matcher m = julLogNames.matcher(x.getName());
217
return m.matches() ? x.getAnnotation(Deprecated.class) == null : false;
218
});
219
}
220
221
/**
222
* Tells whether a method invocation of 'origin' can be transformed in a
223
* method invocation of 'target'.
224
* This method only look at the parameter signatures, it doesn't look at
225
* the name, nor does it look at the return types.
226
* <p>
227
* Example:
228
* <ul>
229
* <li>java.util.logging.Logger.log(Level, String, Object) can be invoked as<br>
230
java.util.logging.spi.Logger.log(Level, String, Object...) because the
231
last parameter in 'target' is a varargs.</li>
232
* <li>java.util.logging.Logger.log(Level, String) can also be invoked as<br>
233
java.util.logging.spi.Logger.log(Level, String, Object...) for the
234
same reason.</li>
235
* </ul>
236
* <p>
237
* The algorithm is tailored for our needs: when the last parameter in the
238
* target is a vararg, and when origin & target have the same number of
239
* parameters, then we consider that the types of the last parameter *must*
240
* match.
241
* <p>
242
* Similarly - we do not consider that o(X x, Y y, Y y) matches t(X x, Y... y)
243
* although strictly speaking, it should...
244
*
245
* @param origin The method in the original class
246
* @param target The correspondent candidate in the target class
247
* @return true if a method invocation of 'origin' can be transformed in a
248
* method invocation of 'target'.
249
*/
250
public boolean canBeInvokedAs(Method origin, Method target,
251
Map<Class<?>,Class<?>> substitutes) {
252
final Class<?>[] xParams = target.getParameterTypes();
253
final Class<?>[] mParams = Stream.of(origin.getParameterTypes())
254
.map((x) -> substitutes.getOrDefault(x, x))
255
.collect(Collectors.toList()).toArray(new Class<?>[0]);
256
if (Arrays.deepEquals(xParams, mParams)) return true;
257
if (target.isVarArgs()) {
258
if (xParams.length == mParams.length) {
259
if (xParams[xParams.length-1].isArray()) {
260
return mParams[mParams.length -1].equals(
261
xParams[xParams.length -1].getComponentType());
262
}
263
} else if (xParams.length == mParams.length + 1) {
264
return Arrays.deepEquals(
265
Arrays.copyOfRange(xParams, 0, xParams.length-1), mParams);
266
}
267
}
268
return false;
269
}
270
271
/**
272
* Look whether {@code otherClass} has a public method similar to m
273
* @param m
274
* @param otherClass
275
* @return
276
*/
277
public Stream<Method> findInvokable(Method m, Class<?> otherClass) {
278
final Map<Class<?>,Class<?>> substitues =
279
Collections.singletonMap(java.util.logging.Level.class,
280
sun.util.logging.PlatformLogger.Level.class);
281
return Stream.of(otherClass.getMethods())
282
.filter((x) -> m.getName().equals(x.getName()))
283
.filter((x) -> canBeInvokedAs(m, x, substitues));
284
}
285
286
/**
287
* Test that the concrete Logger implementation passed as parameter
288
* overrides all the methods defined by its interface.
289
* @param julLogger A concrete implementation of System.Logger
290
* whose backend is a JUL Logger.
291
*/
292
StringBuilder testDefaultJULLogger(java.lang.System.Logger julLogger) {
293
final StringBuilder errors = new StringBuilder();
294
if (!bridgeLoggerClass.isInstance(julLogger)) {
295
final String errorMsg =
296
"Logger returned by LoggerFactory.getLogger(\"foo\") is not a "
297
+ bridgeLoggerClass + "\n\t" + julLogger;
298
System.err.println(errorMsg);
299
errors.append(errorMsg).append('\n');
300
}
301
final Class<? extends java.lang.System.Logger> xClass = julLogger.getClass();
302
List<Method> notOverridden =
303
Stream.of(bridgeLoggerClass.getDeclaredMethods()).filter((m) -> {
304
try {
305
Method x = xClass.getDeclaredMethod(m.getName(), m.getParameterTypes());
306
return x == null;
307
} catch (NoSuchMethodException ex) {
308
return !Modifier.isStatic(m.getModifiers());
309
}
310
}).collect(Collectors.toList());
311
notOverridden.stream().filter((x) -> {
312
boolean shouldOverride = true;
313
try {
314
final Method m = xClass.getMethod(x.getName(), x.getParameterTypes());
315
Method m2 = null;
316
try {
317
m2 = jdkLoggerClass.getDeclaredMethod(x.getName(), x.getParameterTypes());
318
} catch (Exception e) {
319
320
}
321
shouldOverride = m.isDefault() || m2 == null;
322
} catch (Exception e) {
323
// should override.
324
}
325
return shouldOverride;
326
}).forEach(x -> {
327
final String errorMsg = xClass.getName() + " should override\n\t" + x.toString();
328
System.err.println(errorMsg);
329
errors.append(errorMsg).append('\n');
330
});
331
if (notOverridden.isEmpty()) {
332
System.out.println(xClass + " overrides all methods from " + bridgeLoggerClass);
333
}
334
return errors;
335
}
336
337
public static class ResourceBundeParam extends ResourceBundle {
338
Map<String, String> map = Collections.synchronizedMap(new LinkedHashMap<>());
339
@Override
340
protected Object handleGetObject(String key) {
341
map.putIfAbsent(key, "${"+key+"}");
342
return map.get(key);
343
}
344
345
@Override
346
public Enumeration<String> getKeys() {
347
return Collections.enumeration(new LinkedHashSet<>(map.keySet()));
348
}
349
350
}
351
352
final ResourceBundle bundleParam =
353
ResourceBundle.getBundle(ResourceBundeParam.class.getName());
354
355
public static class ResourceBundeLocalized extends ResourceBundle {
356
Map<String, String> map = Collections.synchronizedMap(new LinkedHashMap<>());
357
@Override
358
protected Object handleGetObject(String key) {
359
map.putIfAbsent(key, "Localized:${"+key+"}");
360
return map.get(key);
361
}
362
363
@Override
364
public Enumeration<String> getKeys() {
365
return Collections.enumeration(new LinkedHashSet<>(map.keySet()));
366
}
367
368
}
369
370
final static ResourceBundle bundleLocalized =
371
ResourceBundle.getBundle(ResourceBundeLocalized.class.getName());
372
373
final Map<Class<?>, Object> params = new HashMap<>();
374
{
375
params.put(String.class, "TestString");
376
params.put(sun.util.logging.PlatformLogger.Level.class, sun.util.logging.PlatformLogger.Level.WARNING);
377
params.put(java.lang.System.Logger.Level.class, java.lang.System.Logger.Level.WARNING);
378
params.put(ResourceBundle.class, bundleParam);
379
params.put(Throwable.class, new Throwable("TestThrowable (Please ignore it!)"));
380
params.put(Object[].class, new Object[] {"One", "Two"});
381
params.put(Object.class, new Object() {
382
@Override public String toString() { return "I am an object!"; }
383
});
384
}
385
386
public Object[] getParamsFor(Method m) {
387
final Object[] res = new Object[m.getParameterCount()];
388
final Class<?>[] sig = m.getParameterTypes();
389
if (res.length == 0) {
390
return res;
391
}
392
for (int i=0; i<res.length; i++) {
393
Object p = params.get(sig[i]);
394
if (p == null && sig[i].equals(Supplier.class)) {
395
final String msg = "SuppliedMsg["+i+"]";
396
p = (Supplier<String>) () -> msg;
397
}
398
if (p instanceof String) {
399
res[i] = String.valueOf(p)+"["+i+"]";
400
} else {
401
res[i] = p;
402
}
403
}
404
return res;
405
}
406
407
public void invokeOn(java.lang.System.Logger logger, Method m) {
408
Object[] p = getParamsFor(m);
409
try {
410
m.invoke(logger, p);
411
} catch (Exception e) {
412
throw new RuntimeException("Failed to invoke "+m.toString(), e);
413
}
414
}
415
416
public void testAllJdkExtensionMethods(java.lang.System.Logger logger) {
417
Stream.of(jdkLoggerClass.getDeclaredMethods())
418
.filter(m -> !Modifier.isStatic(m.getModifiers()))
419
.forEach((m) -> invokeOn(logger, m));
420
}
421
422
public void testAllAPIMethods(java.lang.System.Logger logger) {
423
Stream.of(spiLoggerClass.getDeclaredMethods())
424
.filter(m -> !Modifier.isStatic(m.getModifiers()))
425
.forEach((m) -> invokeOn(logger, m));
426
}
427
428
public void testAllBridgeMethods(java.lang.System.Logger logger) {
429
Stream.of(bridgeLoggerClass.getDeclaredMethods())
430
.filter(m -> !Modifier.isStatic(m.getModifiers()))
431
.forEach((m) -> invokeOn(logger, m));
432
}
433
434
public void testAllLogProducerMethods(java.lang.System.Logger logger) {
435
Stream.of(julLogProducerClass.getDeclaredMethods())
436
.filter(m -> !Modifier.isStatic(m.getModifiers()))
437
.forEach((m) -> invokeOn(logger, m));
438
}
439
440
public StringBuilder testGetLoggerOverriddenOnSpi() {
441
final StringBuilder errors = new StringBuilder();
442
Stream.of(jdkLoggerClass.getDeclaredMethods())
443
.filter(m -> Modifier.isStatic(m.getModifiers()))
444
.filter(m -> Modifier.isPublic(m.getModifiers()))
445
.filter(m -> !m.getName().equals("getLoggerFinder"))
446
.filter(m -> {
447
try {
448
final Method x = bridgeLoggerClass.getDeclaredMethod(m.getName(), m.getParameterTypes());
449
return x == null;
450
} catch (NoSuchMethodException ex) {
451
return true;
452
}
453
}).forEach(m -> {
454
final String errorMsg = bridgeLoggerClass.getName() + " should override\n\t" + m.toString();
455
System.err.println(errorMsg);
456
errors.append(errorMsg).append('\n');
457
});
458
if (errors.length() == 0) {
459
System.out.println(bridgeLoggerClass + " overrides all static methods from " + jdkLoggerClass);
460
} else {
461
if (errors.length() > 0) throw new RuntimeException(errors.toString());
462
}
463
return errors;
464
}
465
466
public static void main(String argv[]) throws Exception {
467
final LoggerFinderAPITest test = new LoggerFinderAPITest(false);
468
final StringBuilder errors = new StringBuilder();
469
errors.append(test.testGetLoggerOverriddenOnSpi());
470
java.lang.System.Logger julLogger =
471
java.lang.System.LoggerFinder.getLoggerFinder()
472
.getLogger("foo", LoggerFinderAPITest.class.getModule());
473
errors.append(test.testDefaultJULLogger(julLogger));
474
if (errors.length() > 0) throw new RuntimeException(errors.toString());
475
java.lang.System.Logger julSystemLogger =
476
java.lang.System.LoggerFinder.getLoggerFinder()
477
.getLogger("bar", Thread.class.getModule());
478
errors.append(test.testDefaultJULLogger(julSystemLogger));
479
if (errors.length() > 0) throw new RuntimeException(errors.toString());
480
java.lang.System.Logger julLocalizedLogger =
481
(java.lang.System.Logger)
482
System.getLogger("baz", bundleLocalized);
483
java.lang.System.Logger julLocalizedSystemLogger =
484
java.lang.System.LoggerFinder.getLoggerFinder()
485
.getLocalizedLogger("oof", bundleLocalized, Thread.class.getModule());
486
final String error = errors.toString();
487
if (!error.isEmpty()) throw new RuntimeException(error);
488
for (java.lang.System.Logger logger : new java.lang.System.Logger[] {
489
julLogger, julSystemLogger, julLocalizedLogger, julLocalizedSystemLogger
490
}) {
491
test.testAllJdkExtensionMethods(logger);
492
test.testAllAPIMethods(logger);
493
test.testAllBridgeMethods(logger);
494
test.testAllLogProducerMethods(logger);
495
}
496
}
497
498
}
499
500