Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/java.base/share/classes/jdk/internal/logger/LazyLoggers.java
41159 views
1
/*
2
* Copyright (c) 2015, 2021, 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. Oracle designates this
8
* particular file as subject to the "Classpath" exception as provided
9
* by Oracle in the LICENSE file that accompanied this code.
10
*
11
* This code is distributed in the hope that it will be useful, but WITHOUT
12
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14
* version 2 for more details (a copy is included in the LICENSE file that
15
* accompanied this code).
16
*
17
* You should have received a copy of the GNU General Public License version
18
* 2 along with this work; if not, write to the Free Software Foundation,
19
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20
*
21
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22
* or visit www.oracle.com if you need additional information or have any
23
* questions.
24
*/
25
26
package jdk.internal.logger;
27
28
import java.security.AccessController;
29
import java.security.PrivilegedAction;
30
import java.util.function.BiFunction;
31
import java.lang.System.LoggerFinder;
32
import java.lang.System.Logger;
33
import java.lang.ref.WeakReference;
34
import java.util.Objects;
35
import jdk.internal.misc.VM;
36
import sun.util.logging.PlatformLogger;
37
38
/**
39
* This class is a factory for Lazy Loggers; only system loggers can be
40
* Lazy Loggers.
41
*/
42
public final class LazyLoggers {
43
44
static final RuntimePermission LOGGERFINDER_PERMISSION =
45
new RuntimePermission("loggerFinder");
46
47
private LazyLoggers() {
48
throw new InternalError();
49
}
50
51
/**
52
* This class is used to hold the factories that a Lazy Logger will use
53
* to create (or map) its wrapped logger.
54
* @param <L> {@link Logger} or a subclass of {@link Logger}.
55
*/
56
private static final class LazyLoggerFactories<L extends Logger> {
57
58
/**
59
* A factory method to create an SPI logger.
60
* Usually, this will be something like LazyLoggers::getSystemLogger.
61
*/
62
final BiFunction<String, Module, L> loggerSupplier;
63
64
65
public LazyLoggerFactories(BiFunction<String, Module, L> loggerSupplier) {
66
this(Objects.requireNonNull(loggerSupplier),
67
(Void)null);
68
}
69
70
private LazyLoggerFactories(BiFunction<String, Module, L> loggerSupplier,
71
Void unused) {
72
this.loggerSupplier = loggerSupplier;
73
}
74
75
}
76
77
static interface LoggerAccessor {
78
/**
79
* The logger name.
80
* @return The name of the logger that is / will be lazily created.
81
*/
82
public String getLoggerName();
83
84
/**
85
* Returns the wrapped logger object.
86
* @return the wrapped logger object.
87
*/
88
public Logger wrapped();
89
90
/**
91
* A PlatformLogger.Bridge view of the wrapped logger object.
92
* @return A PlatformLogger.Bridge view of the wrapped logger object.
93
*/
94
public PlatformLogger.Bridge platform();
95
}
96
97
/**
98
* The LazyLoggerAccessor class holds all the logic that delays the creation
99
* of the SPI logger until such a time that the VM is booted and the logger
100
* is actually used for logging.
101
*
102
* This class uses the services of the BootstrapLogger class to instantiate
103
* temporary loggers if appropriate.
104
*/
105
static final class LazyLoggerAccessor implements LoggerAccessor {
106
107
// The factories that will be used to create the logger lazyly
108
final LazyLoggerFactories<? extends Logger> factories;
109
110
// We need to pass the actual caller module when creating the logger.
111
private final WeakReference<Module> moduleRef;
112
113
// The name of the logger that will be created lazyly
114
final String name;
115
// The plain logger SPI object - null until it is accessed for the
116
// first time.
117
private volatile Logger w;
118
// A PlatformLogger.Bridge view of w.
119
private volatile PlatformLogger.Bridge p;
120
121
122
private LazyLoggerAccessor(String name,
123
LazyLoggerFactories<? extends Logger> factories,
124
Module module) {
125
this(Objects.requireNonNull(name), Objects.requireNonNull(factories),
126
Objects.requireNonNull(module), null);
127
}
128
129
private LazyLoggerAccessor(String name,
130
LazyLoggerFactories<? extends Logger> factories,
131
Module module, Void unused) {
132
this.name = name;
133
this.factories = factories;
134
this.moduleRef = new WeakReference<>(module);
135
}
136
137
/**
138
* The logger name.
139
* @return The name of the logger that is / will be lazily created.
140
*/
141
@Override
142
public String getLoggerName() {
143
return name;
144
}
145
146
// must be called in synchronized block
147
// set wrapped logger if not set
148
private void setWrappedIfNotSet(Logger wrapped) {
149
if (w == null) {
150
w = wrapped;
151
}
152
}
153
154
/**
155
* Returns the logger SPI object, creating it if 'w' is still null.
156
* @return the logger SPI object.
157
*/
158
public Logger wrapped() {
159
Logger wrapped = w;
160
if (wrapped != null) return wrapped;
161
// Wrapped logger not created yet: create it.
162
// BootstrapLogger has the logic to decide whether to invoke the
163
// SPI or use a temporary (BootstrapLogger or SimpleConsoleLogger)
164
// logger.
165
wrapped = BootstrapLogger.getLogger(this);
166
synchronized(this) {
167
// if w has already been in between, simply drop 'wrapped'.
168
setWrappedIfNotSet(wrapped);
169
return w;
170
}
171
}
172
173
/**
174
* A PlatformLogger.Bridge view of the wrapped logger.
175
* @return A PlatformLogger.Bridge view of the wrapped logger.
176
*/
177
public PlatformLogger.Bridge platform() {
178
// We can afford to return the platform view of the previous
179
// logger - if that view is not null.
180
// Because that view will either be the BootstrapLogger, which
181
// will redirect to the new wrapper properly, or the temporary
182
// logger - which in effect is equivalent to logging something
183
// just before the application initialized LogManager.
184
PlatformLogger.Bridge platform = p;
185
if (platform != null) return platform;
186
synchronized (this) {
187
if (w != null) {
188
if (p == null) p = PlatformLogger.Bridge.convert(w);
189
return p;
190
}
191
}
192
// If we reach here it means that the wrapped logger may not
193
// have been created yet: attempt to create it.
194
// BootstrapLogger has the logic to decide whether to invoke the
195
// SPI or use a temporary (BootstrapLogger or SimpleConsoleLogger)
196
// logger.
197
final Logger wrapped = BootstrapLogger.getLogger(this);
198
synchronized(this) {
199
// if w has already been set, simply drop 'wrapped'.
200
setWrappedIfNotSet(wrapped);
201
if (p == null) p = PlatformLogger.Bridge.convert(w);
202
return p;
203
}
204
}
205
206
/**
207
* Makes this accessor release a temporary logger.
208
* This method is called
209
* by BootstrapLogger when JUL is the default backend and LogManager
210
* is initialized, in order to replace temporary SimpleConsoleLoggers by
211
* real JUL loggers. See BootstrapLogger for more details.
212
* If {@code replace} is {@code true}, then this method will force
213
* the accessor to eagerly recreate its wrapped logger.
214
* Note: passing {@code replace=false} is no guarantee that the
215
* method will not actually replace the released logger.
216
* @param temporary The temporary logger too be released.
217
* @param replace Whether the released logger should be eagerly
218
* replaced.
219
*/
220
void release(SimpleConsoleLogger temporary, boolean replace) {
221
PlatformLogger.ConfigurableBridge.LoggerConfiguration conf =
222
PlatformLogger.ConfigurableBridge.getLoggerConfiguration(temporary);
223
PlatformLogger.Level level = conf != null
224
? conf.getPlatformLevel()
225
: null;
226
synchronized (this) {
227
if (this.w == temporary) {
228
this.w = null; this.p = null;
229
}
230
}
231
PlatformLogger.Bridge platform = replace || level != null
232
? this.platform() : null;
233
234
if (level != null) {
235
conf = (platform != null && platform != temporary)
236
? PlatformLogger.ConfigurableBridge.getLoggerConfiguration(platform)
237
: null;
238
if (conf != null) conf.setPlatformLevel(level);
239
}
240
}
241
242
/**
243
* Replace 'w' by the real SPI logger and flush the log messages pending
244
* in the temporary 'bootstrap' Logger. Called by BootstrapLogger when
245
* this accessor's bootstrap logger is accessed and BootstrapLogger
246
* notices that the VM is no longer booting.
247
* @param bootstrap This accessor's bootstrap logger (usually this is 'w').
248
*/
249
Logger getConcreteLogger(BootstrapLogger bootstrap) {
250
assert VM.isBooted();
251
synchronized(this) {
252
// another thread may have already invoked flush()
253
if (this.w == bootstrap) {
254
this.w = null; this.p = null;
255
}
256
}
257
return this.wrapped();
258
}
259
260
PlatformLogger.Bridge getConcretePlatformLogger(BootstrapLogger bootstrap) {
261
assert VM.isBooted();
262
synchronized(this) {
263
// another thread may have already invoked flush()
264
if (this.w == bootstrap) {
265
this.w = null; this.p = null;
266
}
267
}
268
return this.platform();
269
}
270
271
// Creates the wrapped logger by invoking the SPI.
272
Logger createLogger() {
273
final Module module = moduleRef.get();
274
if (module == null) {
275
throw new IllegalStateException("The module for which this logger"
276
+ " was created has been garbage collected");
277
}
278
return this.factories.loggerSupplier.apply(name, module);
279
}
280
281
/**
282
* Creates a new lazy logger accessor for the named logger. The given
283
* factories will be use when it becomes necessary to actually create
284
* the logger.
285
* @param <T> An interface that extends {@link Logger}.
286
* @param name The logger name.
287
* @param factories The factories that should be used to create the
288
* wrapped logger.
289
* @return A new LazyLoggerAccessor.
290
*/
291
public static LazyLoggerAccessor makeAccessor(String name,
292
LazyLoggerFactories<? extends Logger> factories, Module module) {
293
return new LazyLoggerAccessor(name, factories, module);
294
}
295
296
}
297
298
/**
299
* An implementation of {@link Logger} that redirects all calls to a wrapped
300
* instance of {@code Logger}.
301
*/
302
private static class LazyLoggerWrapper
303
extends AbstractLoggerWrapper<Logger> {
304
305
final LoggerAccessor loggerAccessor;
306
307
public LazyLoggerWrapper(LazyLoggerAccessor loggerSinkSupplier) {
308
this(Objects.requireNonNull(loggerSinkSupplier), (Void)null);
309
}
310
311
private LazyLoggerWrapper(LazyLoggerAccessor loggerSinkSupplier,
312
Void unused) {
313
this.loggerAccessor = loggerSinkSupplier;
314
}
315
316
@Override
317
final Logger wrapped() {
318
return loggerAccessor.wrapped();
319
}
320
321
@Override
322
PlatformLogger.Bridge platformProxy() {
323
return loggerAccessor.platform();
324
}
325
326
}
327
328
// Do not expose this outside of this package.
329
private static volatile LoggerFinder provider;
330
@SuppressWarnings("removal")
331
private static LoggerFinder accessLoggerFinder() {
332
LoggerFinder prov = provider;
333
if (prov == null) {
334
// no need to lock: it doesn't matter if we call
335
// getLoggerFinder() twice - since LoggerFinder already caches
336
// the result.
337
// This is just an optimization to avoid the cost of calling
338
// doPrivileged every time.
339
final SecurityManager sm = System.getSecurityManager();
340
prov = sm == null ? LoggerFinder.getLoggerFinder() :
341
AccessController.doPrivileged(
342
(PrivilegedAction<LoggerFinder>)LoggerFinder::getLoggerFinder);
343
provider = prov;
344
}
345
return prov;
346
}
347
348
// Avoid using lambda here as lazy loggers could be created early
349
// in the bootstrap sequence...
350
private static final BiFunction<String, Module, Logger> loggerSupplier =
351
new BiFunction<>() {
352
@Override
353
public Logger apply(String name, Module module) {
354
return LazyLoggers.getLoggerFromFinder(name, module);
355
}
356
};
357
358
private static final LazyLoggerFactories<Logger> factories =
359
new LazyLoggerFactories<>(loggerSupplier);
360
361
362
363
// A concrete implementation of Logger that delegates to a System.Logger,
364
// but only creates the System.Logger instance lazily when it's used for
365
// the first time.
366
// The JdkLazyLogger uses a LazyLoggerAccessor objects, which relies
367
// on the logic embedded in BootstrapLogger to avoid loading the concrete
368
// logger provider until the VM has finished booting.
369
//
370
private static final class JdkLazyLogger extends LazyLoggerWrapper {
371
JdkLazyLogger(String name, Module module) {
372
this(LazyLoggerAccessor.makeAccessor(name, factories, module),
373
(Void)null);
374
}
375
private JdkLazyLogger(LazyLoggerAccessor holder, Void unused) {
376
super(holder);
377
}
378
}
379
380
/**
381
* Gets a logger from the LoggerFinder. Creates the actual concrete
382
* logger.
383
* @param name name of the logger
384
* @param module module on behalf of which the logger is created
385
* @return The logger returned by the LoggerFinder.
386
*/
387
@SuppressWarnings("removal")
388
static Logger getLoggerFromFinder(String name, Module module) {
389
final SecurityManager sm = System.getSecurityManager();
390
if (sm == null) {
391
return accessLoggerFinder().getLogger(name, module);
392
} else {
393
return AccessController.doPrivileged((PrivilegedAction<Logger>)
394
() -> {return accessLoggerFinder().getLogger(name, module);},
395
null, LOGGERFINDER_PERMISSION);
396
}
397
}
398
399
/**
400
* Returns a (possibly lazy) Logger for the caller.
401
*
402
* @param name the logger name
403
* @param module The module on behalf of which the logger is created.
404
* If the module is not loaded from the Boot ClassLoader,
405
* the LoggerFinder is accessed and the logger returned
406
* by {@link LoggerFinder#getLogger(java.lang.String, java.lang.Module)}
407
* is returned to the caller directly.
408
* Otherwise, the logger returned by
409
* {@link #getLazyLogger(java.lang.String, java.lang.Module)}
410
* is returned to the caller.
411
*
412
* @return a (possibly lazy) Logger instance.
413
*/
414
public static final Logger getLogger(String name, Module module) {
415
if (DefaultLoggerFinder.isSystem(module)) {
416
return getLazyLogger(name, module);
417
} else {
418
return getLoggerFromFinder(name, module);
419
}
420
}
421
422
/**
423
* Returns a (possibly lazy) Logger suitable for system classes.
424
* Whether the returned logger is lazy or not depend on the result
425
* returned by {@link BootstrapLogger#useLazyLoggers()}.
426
*
427
* @param name the logger name
428
* @param module the module on behalf of which the logger is created.
429
* @return a (possibly lazy) Logger instance.
430
*/
431
public static final Logger getLazyLogger(String name, Module module) {
432
433
// BootstrapLogger has the logic to determine whether a LazyLogger
434
// should be used. Usually, it is worth it only if:
435
// - the VM is not yet booted
436
// - or, the backend is JUL and there is no configuration
437
// - or, the backend is a custom backend, as we don't know what
438
// that is going to load...
439
// So if for instance the VM is booted and we use JUL with a custom
440
// configuration, we're not going to delay the creation of loggers...
441
final boolean useLazyLogger = BootstrapLogger.useLazyLoggers();
442
if (useLazyLogger) {
443
return new JdkLazyLogger(name, module);
444
} else {
445
// Directly invoke the LoggerFinder.
446
return getLoggerFromFinder(name, module);
447
}
448
}
449
450
}
451
452