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. 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 27 package sun.util.logging.internal; 28 29 import java.security.AccessController; 30 import java.security.PrivilegedAction; 31 import java.util.ResourceBundle; 32 import java.util.function.Supplier; 33 import java.lang.System.LoggerFinder; 34 import java.lang.System.Logger; 35 import java.util.Objects; 36 import java.util.logging.LogManager; 37 import jdk.internal.logger.DefaultLoggerFinder; 38 import java.util.logging.LoggingPermission; 39 import sun.util.logging.PlatformLogger; 40 import sun.util.logging.PlatformLogger.ConfigurableBridge.LoggerConfiguration; 41 42 /** 43 * This {@code LoggingProviderImpl} is the JDK internal implementation of the 44 * {@link jdk.internal.logger.DefaultLoggerFinder} which is used by 45 * the default implementation of the {@link Logger} 46 * when no {@link LoggerFinder} is found 47 * and {@code java.util.logging} is present. 48 * When {@code java.util.logging} is present, the {@code LoggingProviderImpl} 49 * is {@linkplain java.util.ServiceLoader#loadInstalled(Class) installed} as 50 * an internal service provider, making it possible to use {@code java.util.logging} 51 * as the backend for loggers returned by the default LoggerFinder implementation. 52 * <p> 53 * This implementation of {@link DefaultLoggerFinder} returns instances of 54 * {@link java.lang.System.Logger} which 55 * delegate to a wrapped instance of {@link java.util.logging.Logger 56 * java.util.logging.Logger}. 57 * <br> 58 * Loggers returned by this class can therefore be configured by accessing 59 * their wrapped implementation through the regular {@code java.util.logging} 60 * APIs - such as {@link java.util.logging.LogManager java.util.logging.LogManager} 61 * and {@link java.util.logging.Logger java.util.logging.Logger}. 62 * 63 * @apiNote Programmers are not expected to call this class directly. 64 * Instead they should rely on the static methods defined by 65 * {@link java.lang.System java.lang.System}. 66 * <p> 67 * To replace this default 68 * {@code java.util.logging} backend, an application is expected to install 69 * its own {@link java.lang.System.LoggerFinder}. 70 * 71 * @see java.lang.System.Logger 72 * @see java.lang.System.LoggerFinder 73 * @see sun.util.logging.PlatformLogger.Bridge 74 * @see java.lang.System 75 * @see jdk.internal.logger 76 * @see jdk.internal.logger 77 * 78 */ 79 public final class LoggingProviderImpl extends DefaultLoggerFinder { 80 static final RuntimePermission LOGGERFINDER_PERMISSION = 81 new RuntimePermission("loggerFinder"); 82 private static final LoggingPermission LOGGING_CONTROL_PERMISSION = 83 new LoggingPermission("control", null); 84 85 /** 86 * Creates a new instance of LoggingProviderImpl. 87 * @throws SecurityException if the calling code does not have the 88 * {@code RuntimePermission("loggerFinder")}. 89 */ LoggingProviderImpl()90 public LoggingProviderImpl() { 91 } 92 93 /** 94 * A logger that delegates to a java.util.logging.Logger delegate. 95 */ 96 static final class JULWrapper extends LoggerConfiguration 97 implements System.Logger, PlatformLogger.Bridge, 98 PlatformLogger.ConfigurableBridge { 99 100 101 private static final java.util.logging.Level[] spi2JulLevelMapping = { 102 java.util.logging.Level.ALL, // mapped from ALL 103 java.util.logging.Level.FINER, // mapped from TRACE 104 java.util.logging.Level.FINE, // mapped from DEBUG 105 java.util.logging.Level.INFO, // mapped from INFO 106 java.util.logging.Level.WARNING, // mapped from WARNING 107 java.util.logging.Level.SEVERE, // mapped from ERROR 108 java.util.logging.Level.OFF // mapped from OFF 109 }; 110 111 private static final java.util.logging.Level[] platform2JulLevelMapping = { 112 java.util.logging.Level.ALL, // mapped from ALL 113 java.util.logging.Level.FINEST, // mapped from FINEST 114 java.util.logging.Level.FINER, // mapped from FINER 115 java.util.logging.Level.FINE, // mapped from FINE 116 java.util.logging.Level.CONFIG, // mapped from CONFIG 117 java.util.logging.Level.INFO, // mapped from INFO 118 java.util.logging.Level.WARNING, // mapped from WARNING 119 java.util.logging.Level.SEVERE, // mapped from SEVERE 120 java.util.logging.Level.OFF // mapped from OFF 121 }; 122 123 private final java.util.logging.Logger julLogger; 124 125 JULWrapper(java.util.logging.Logger logger)126 private JULWrapper(java.util.logging.Logger logger) { 127 this.julLogger = logger; 128 } 129 130 @Override getName()131 public String getName() { 132 return julLogger.getName(); 133 } 134 @Override log(sun.util.logging.PlatformLogger.Level level, String msg, Throwable throwable)135 public void log(sun.util.logging.PlatformLogger.Level level, String msg, Throwable throwable) { 136 julLogger.log(toJUL(level), msg, throwable); 137 } 138 139 @Override log(sun.util.logging.PlatformLogger.Level level, String format, Object... params)140 public void log(sun.util.logging.PlatformLogger.Level level, String format, Object... params) { 141 julLogger.log(toJUL(level), format, params); 142 } 143 144 @Override log(sun.util.logging.PlatformLogger.Level level, String msg)145 public void log(sun.util.logging.PlatformLogger.Level level, String msg) { 146 julLogger.log(toJUL(level), msg); 147 } 148 149 @Override log(sun.util.logging.PlatformLogger.Level level, Supplier<String> msgSuppier)150 public void log(sun.util.logging.PlatformLogger.Level level, Supplier<String> msgSuppier) { 151 julLogger.log(toJUL(level), msgSuppier); 152 } 153 154 @Override log(sun.util.logging.PlatformLogger.Level level, Throwable thrown, Supplier<String> msgSuppier)155 public void log(sun.util.logging.PlatformLogger.Level level, Throwable thrown, Supplier<String> msgSuppier) { 156 julLogger.log(toJUL(level), thrown, msgSuppier); 157 } 158 159 @Override logrb(sun.util.logging.PlatformLogger.Level level, ResourceBundle bundle, String key, Throwable throwable)160 public void logrb(sun.util.logging.PlatformLogger.Level level, ResourceBundle bundle, String key, Throwable throwable) { 161 julLogger.logrb(toJUL(level), bundle, key, throwable); 162 } 163 164 @Override logrb(sun.util.logging.PlatformLogger.Level level, ResourceBundle bundle, String key, Object... params)165 public void logrb(sun.util.logging.PlatformLogger.Level level, ResourceBundle bundle, String key, Object... params) { 166 julLogger.logrb(toJUL(level), bundle, key, params); 167 } 168 169 @Override logp(sun.util.logging.PlatformLogger.Level level, String sourceClass, String sourceMethod, String msg)170 public void logp(sun.util.logging.PlatformLogger.Level level, String sourceClass, String sourceMethod, String msg) { 171 julLogger.logp(toJUL(level), sourceClass, sourceMethod, msg); 172 } 173 174 @Override logp(sun.util.logging.PlatformLogger.Level level, String sourceClass, String sourceMethod, Supplier<String> msgSupplier)175 public void logp(sun.util.logging.PlatformLogger.Level level, String sourceClass, String sourceMethod, 176 Supplier<String> msgSupplier) { 177 julLogger.logp(toJUL(level), sourceClass, sourceMethod, msgSupplier); 178 } 179 180 @Override logp(sun.util.logging.PlatformLogger.Level level, String sourceClass, String sourceMethod, String msg, Object... params)181 public void logp(sun.util.logging.PlatformLogger.Level level, String sourceClass, String sourceMethod, 182 String msg, Object... params) { 183 julLogger.logp(toJUL(level), sourceClass, sourceMethod, msg, params); 184 } 185 186 @Override logp(sun.util.logging.PlatformLogger.Level level, String sourceClass, String sourceMethod, String msg, Throwable thrown)187 public void logp(sun.util.logging.PlatformLogger.Level level, String sourceClass, String sourceMethod, 188 String msg, Throwable thrown) { 189 julLogger.logp(toJUL(level), sourceClass, sourceMethod, msg, thrown); 190 } 191 192 @Override logp(sun.util.logging.PlatformLogger.Level level, String sourceClass, String sourceMethod, Throwable thrown, Supplier<String> msgSupplier)193 public void logp(sun.util.logging.PlatformLogger.Level level, String sourceClass, String sourceMethod, 194 Throwable thrown, Supplier<String> msgSupplier) { 195 julLogger.logp(toJUL(level), sourceClass, sourceMethod, 196 thrown, msgSupplier); 197 } 198 199 @Override logrb(sun.util.logging.PlatformLogger.Level level, String sourceClass, String sourceMethod, ResourceBundle bundle, String key, Object... params)200 public void logrb(sun.util.logging.PlatformLogger.Level level, String sourceClass, String sourceMethod, 201 ResourceBundle bundle, String key, Object... params) { 202 julLogger.logrb(toJUL(level), sourceClass, sourceMethod, 203 bundle, key, params); 204 } 205 206 @Override logrb(sun.util.logging.PlatformLogger.Level level, String sourceClass, String sourceMethod, ResourceBundle bundle, String key, Throwable thrown)207 public void logrb(sun.util.logging.PlatformLogger.Level level, String sourceClass, String sourceMethod, 208 ResourceBundle bundle, String key, Throwable thrown) { 209 julLogger.logrb(toJUL(level), sourceClass, sourceMethod, 210 bundle, key, thrown); 211 } 212 213 @Override isLoggable(sun.util.logging.PlatformLogger.Level level)214 public boolean isLoggable(sun.util.logging.PlatformLogger.Level level) { 215 return julLogger.isLoggable(toJUL(level)); 216 } 217 218 // ----------------------------------------------------------------- 219 // Generic methods taking a Level as parameter 220 // ----------------------------------------------------------------- 221 222 223 @Override isLoggable(Level level)224 public boolean isLoggable(Level level) { 225 return julLogger.isLoggable(toJUL(level)); 226 } 227 228 @Override log(Level level, String msg)229 public void log(Level level, String msg) { 230 julLogger.log(toJUL(level), msg); 231 } 232 233 @Override log(Level level, Supplier<String> msgSupplier)234 public void log(Level level, 235 Supplier<String> msgSupplier) { 236 // We need to check for null here to satisfy the contract 237 // of System.Logger - because the underlying implementation 238 // of julLogger will check for it only if the level is 239 // loggable 240 Objects.requireNonNull(msgSupplier); 241 julLogger.log(toJUL(level), msgSupplier); 242 } 243 244 @Override log(Level level, Object obj)245 public void log(Level level, Object obj) { 246 // We need to check for null here to satisfy the contract 247 // of System.Logger - because the underlying implementation 248 // of julLogger will check for it only if the level is 249 // loggable 250 Objects.requireNonNull(obj); 251 julLogger.log(toJUL(level), () -> obj.toString()); 252 } 253 254 @Override log(Level level, String msg, Throwable thrown)255 public void log(Level level, 256 String msg, Throwable thrown) { 257 julLogger.log(toJUL(level), msg, thrown); 258 } 259 260 @Override log(Level level, Supplier<String> msgSupplier, Throwable thrown)261 public void log(Level level, Supplier<String> msgSupplier, 262 Throwable thrown) { 263 // We need to check for null here to satisfy the contract 264 // of System.Logger - because the underlying implementation 265 // of julLogger will check for it only if the level is 266 // loggable 267 Objects.requireNonNull(msgSupplier); 268 julLogger.log(toJUL(level), thrown, msgSupplier); 269 } 270 271 @Override log(Level level, String format, Object... params)272 public void log(Level level, 273 String format, Object... params) { 274 julLogger.log(toJUL(level), format, params); 275 } 276 277 @Override log(Level level, ResourceBundle bundle, String key, Throwable thrown)278 public void log(Level level, ResourceBundle bundle, 279 String key, Throwable thrown) { 280 julLogger.logrb(toJUL(level), bundle, key, thrown); 281 } 282 283 @Override log(Level level, ResourceBundle bundle, String format, Object... params)284 public void log(Level level, ResourceBundle bundle, 285 String format, Object... params) { 286 julLogger.logrb(toJUL(level), bundle, format, params); 287 } 288 toJUL(Level level)289 static java.util.logging.Level toJUL(Level level) { 290 if (level == null) return null; 291 assert level.ordinal() < spi2JulLevelMapping.length; 292 return spi2JulLevelMapping[level.ordinal()]; 293 } 294 295 // --------------------------------------------------------- 296 // Methods from PlatformLogger.Bridge 297 // --------------------------------------------------------- 298 299 @Override 300 public boolean isEnabled() { 301 return julLogger.getLevel() != java.util.logging.Level.OFF; 302 } 303 304 @Override 305 public PlatformLogger.Level getPlatformLevel() { 306 final java.util.logging.Level javaLevel = julLogger.getLevel(); 307 if (javaLevel == null) return null; 308 try { 309 return PlatformLogger.Level.valueOf(javaLevel.getName()); 310 } catch (IllegalArgumentException e) { 311 return PlatformLogger.Level.valueOf(javaLevel.intValue()); 312 } 313 } 314 315 @Override 316 public void setPlatformLevel(PlatformLogger.Level level) { 317 // null is allowed here 318 julLogger.setLevel(toJUL(level)); 319 } 320 321 @Override 322 public LoggerConfiguration getLoggerConfiguration() { 323 return this; 324 } 325 326 static java.util.logging.Level toJUL(PlatformLogger.Level level) { 327 // The caller will throw if null is invalid in its context. 328 // There's at least one case where a null level is valid. 329 if (level == null) return null; 330 assert level.ordinal() < platform2JulLevelMapping.length; 331 return platform2JulLevelMapping[level.ordinal()]; 332 } 333 334 @Override 335 public boolean equals(Object obj) { 336 return (obj instanceof JULWrapper) 337 && obj.getClass() == this.getClass() 338 && ((JULWrapper)obj).julLogger == this.julLogger; 339 } 340 341 @Override 342 public int hashCode() { 343 return julLogger.hashCode(); 344 } 345 346 // A JULWrapper is just a stateless thin shell over a JUL logger - so 347 // for a given JUL logger, we could always return the same wrapper. 348 // 349 // This is an optimization which may - or may not - be worth the 350 // trouble: if many classes use the same logger, and if each class 351 // keeps a reference to that logger, then caching the wrapper will 352 // be worthwhile. Otherwise, if each logger is only referred once, 353 // then the cache will eat up more memory than would be necessary... 354 // 355 // Here is an example of how we could implement JULWrapper.of(...) 356 // if we wanted to create at most one wrapper instance for each logger 357 // instance: 358 // 359 // static final WeakHashMap<JULWrapper, WeakReference<JULWrapper>> 360 // wrappers = new WeakHashMap<>(); 361 // 362 // static JULWrapper of(java.util.logging.Logger logger) { 363 // 364 // // First access without synchronizing 365 // final JULWrapper candidate = new JULWrapper(logger); 366 // WeakReference<JULWrapper> ref = wrappers.get(candidate); 367 // JULWrapper found = ref.get(); 368 // 369 // // OK - we found it - lets return it. 370 // if (found != null) return found; 371 // 372 // // Not found. Need to synchronize. 373 // synchronized (wrappers) { 374 // ref = wrappers.get(candidate); 375 // found = ref.get(); 376 // if (found == null) { 377 // wrappers.put(candidate, new WeakReference<>(candidate)); 378 // found = candidate; 379 // } 380 // } 381 // assert found != null; 382 // return found; 383 // } 384 // 385 // But given that it may end up eating more memory in the nominal case 386 // (where each class that does logging has its own logger with the 387 // class name as logger name and stashes that logger away in a static 388 // field, thus making the cache redundant - as only one wrapper will 389 // ever be created anyway) - then we will simply return a new wrapper 390 // for each invocation of JULWrapper.of(...) - which may 391 // still prove more efficient in terms of memory consumption... 392 // 393 static JULWrapper of(java.util.logging.Logger logger) { 394 return new JULWrapper(logger); 395 } 396 397 398 } 399 400 /** 401 * Creates a java.util.logging.Logger for the given module. 402 * @param name the logger name. 403 * @param module the module for which the logger should be created. 404 * @return a Logger suitable for use in the given module. 405 */ 406 private static java.util.logging.Logger demandJULLoggerFor(final String name, 407 Module module) { 408 final LogManager manager = LogManager.getLogManager(); 409 final SecurityManager sm = System.getSecurityManager(); 410 if (sm == null) { 411 return logManagerAccess.demandLoggerFor(manager, name, module); 412 } else { 413 final PrivilegedAction<java.util.logging.Logger> pa = 414 () -> logManagerAccess.demandLoggerFor(manager, name, module); 415 return AccessController.doPrivileged(pa, null, LOGGING_CONTROL_PERMISSION); 416 } 417 } 418 419 /** 420 * {@inheritDoc} 421 * 422 * @apiNote The logger returned by this method can be configured through 423 * its {@linkplain java.util.logging.LogManager#getLogger(String) 424 * corresponding java.util.logging.Logger backend}. 425 * 426 * @return {@inheritDoc} 427 * @throws SecurityException if the calling code doesn't have the 428 * {@code RuntimePermission("loggerFinder")}. 429 */ 430 @Override 431 protected Logger demandLoggerFor(String name, Module module) { 432 final SecurityManager sm = System.getSecurityManager(); 433 if (sm != null) { 434 sm.checkPermission(LOGGERFINDER_PERMISSION); 435 } 436 return JULWrapper.of(demandJULLoggerFor(name,module)); 437 } 438 439 public static interface LogManagerAccess { 440 java.util.logging.Logger demandLoggerFor(LogManager manager, 441 String name, Module module); 442 } 443 444 // Hook for tests 445 public static LogManagerAccess getLogManagerAccess() { 446 final SecurityManager sm = System.getSecurityManager(); 447 if (sm != null) { 448 sm.checkPermission(LOGGING_CONTROL_PERMISSION); 449 } 450 // Triggers initialization of accessJulLogger if not set. 451 if (logManagerAccess == null) LogManager.getLogManager(); 452 return logManagerAccess; 453 } 454 455 456 private static volatile LogManagerAccess logManagerAccess; 457 public static void setLogManagerAccess(LogManagerAccess accesLoggers) { 458 final SecurityManager sm = System.getSecurityManager(); 459 if (sm != null) { 460 sm.checkPermission(LOGGING_CONTROL_PERMISSION); 461 } 462 logManagerAccess = accesLoggers; 463 } 464 465 } 466