1 /* 2 * Copyright (c) 2014, 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 sun.util.logger.JdkLoggerProvider; 36 import java.util.logging.LoggingPermission; 37 import sun.util.logging.ConfigurableLoggerBridge; 38 import sun.util.logging.PlatformLogger; 39 import sun.util.logging.ConfigurableLoggerBridge.LoggerConfiguration; 40 import sun.util.logging.PlatformLoggerBridge; 41 42 /** 43 * This {@code JdkLoggingProvider} is the JDK internal implementation of the 44 * {@link sun.util.logger.JdkLoggerProvider} 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 JdkLoggingProvider} 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 JdkLoggerProvider} 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.PlatformLoggerBridge 74 * @see java.lang.System 75 * @see sun.util.logger 76 * @see sun.util.logging.internal 77 * 78 */ 79 public final class JdkLoggingProvider extends JdkLoggerProvider { 80 private static final RuntimePermission LOGGER_CONTROL_PERMISSION = 81 LoggerFinder.LOGGERFINDER_PERMISSION; 82 private static final LoggingPermission LOGGING_CONTROL_PERMISSION = 83 new LoggingPermission("control", null); 84 private static final LoggingPermission LOGGING_DEMANDLOGGER_PERMISSION = 85 new LoggingPermission("demandLogger", null); 86 87 /** 88 * Creates a new instance of JdkLoggingProvider. 89 * @throws SecurityException if the calling code does not have the 90 * {@code RuntimePermission("loggerFinder")}. 91 */ 92 public JdkLoggingProvider() { 93 super(); 94 } 95 96 /** 97 * A logger that delegates to a java.util.logging.Logger delegate. 98 */ 99 static final class JULWrapper extends LoggerConfiguration 100 implements System.Logger, PlatformLoggerBridge, 101 ConfigurableLoggerBridge { 102 103 104 private static final java.util.logging.Level[] spi2JulLevelMapping = { 105 java.util.logging.Level.ALL, // mapped from ALL 106 java.util.logging.Level.FINER, // mapped from TRACE 107 java.util.logging.Level.FINE, // mapped from DEBUG 108 java.util.logging.Level.INFO, // mapped from INFO 109 java.util.logging.Level.WARNING, // mapped from WARNING 110 java.util.logging.Level.SEVERE, // mapped from ERROR 111 java.util.logging.Level.OFF // mapped from OFF 112 }; 113 114 private static final java.util.logging.Level[] platform2JulLevelMapping = { 115 java.util.logging.Level.ALL, // mapped from ALL 116 java.util.logging.Level.FINEST, // mapped from FINEST 117 java.util.logging.Level.FINER, // mapped from FINER 118 java.util.logging.Level.FINE, // mapped from FINE 119 java.util.logging.Level.CONFIG, // mapped from CONFIG 120 java.util.logging.Level.INFO, // mapped from INFO 121 java.util.logging.Level.WARNING, // mapped from WARNING 122 java.util.logging.Level.SEVERE, // mapped from SEVERE 123 java.util.logging.Level.OFF // mapped from OFF 124 }; 125 126 private final java.util.logging.Logger julLogger; 127 128 129 private JULWrapper(java.util.logging.Logger logger) { 130 this.julLogger = logger; 131 } 132 133 @Override 134 public String getName() { 135 return julLogger.getName(); 136 } 137 @Override 138 public void log(sun.util.logging.PlatformLogger.Level level, String msg, Throwable throwable) { 139 julLogger.log(toJUL(level), msg, throwable); 140 } 141 142 @Override 143 public void log(sun.util.logging.PlatformLogger.Level level, String format, Object... params) { 144 julLogger.log(toJUL(level), format, params); 145 } 146 147 @Override 148 public void log(sun.util.logging.PlatformLogger.Level level, String msg) { 149 julLogger.log(toJUL(level), msg); 150 } 151 152 @Override 153 public void log(sun.util.logging.PlatformLogger.Level level, Supplier<String> msgSuppier) { 154 julLogger.log(toJUL(level), msgSuppier); 155 } 156 157 @Override 158 public void log(sun.util.logging.PlatformLogger.Level level, Throwable thrown, Supplier<String> msgSuppier) { 159 julLogger.log(toJUL(level), thrown, msgSuppier); 160 } 161 162 @Override 163 public void logrb(sun.util.logging.PlatformLogger.Level level, ResourceBundle bundle, String key, Throwable throwable) { 164 julLogger.logrb(toJUL(level), bundle, key, throwable); 165 } 166 167 @Override 168 public void logrb(sun.util.logging.PlatformLogger.Level level, ResourceBundle bundle, String key, Object... params) { 169 julLogger.logrb(toJUL(level), bundle, key, params); 170 } 171 172 @Override 173 public void logp(sun.util.logging.PlatformLogger.Level level, String sourceClass, String sourceMethod, String msg) { 174 julLogger.logp(toJUL(level), sourceClass, sourceMethod, msg); 175 } 176 177 @Override 178 public void logp(sun.util.logging.PlatformLogger.Level level, String sourceClass, String sourceMethod, 179 Supplier<String> msgSupplier) { 180 julLogger.logp(toJUL(level), sourceClass, sourceMethod, msgSupplier); 181 } 182 183 @Override 184 public void logp(sun.util.logging.PlatformLogger.Level level, String sourceClass, String sourceMethod, 185 String msg, Object... params) { 186 julLogger.logp(toJUL(level), sourceClass, sourceMethod, msg, params); 187 } 188 189 @Override 190 public void logp(sun.util.logging.PlatformLogger.Level level, String sourceClass, String sourceMethod, 191 String msg, Throwable thrown) { 192 julLogger.logp(toJUL(level), sourceClass, sourceMethod, msg, thrown); 193 } 194 195 @Override 196 public void logp(sun.util.logging.PlatformLogger.Level level, String sourceClass, String sourceMethod, 197 Throwable thrown, Supplier<String> msgSupplier) { 198 julLogger.logp(toJUL(level), sourceClass, sourceMethod, 199 thrown, msgSupplier); 200 } 201 202 @Override 203 public void logrb(sun.util.logging.PlatformLogger.Level level, String sourceClass, String sourceMethod, 204 ResourceBundle bundle, String key, Object... params) { 205 julLogger.logrb(toJUL(level), sourceClass, sourceMethod, 206 bundle, key, params); 207 } 208 209 @Override 210 public void logrb(sun.util.logging.PlatformLogger.Level level, String sourceClass, String sourceMethod, 211 ResourceBundle bundle, String key, Throwable thrown) { 212 julLogger.logrb(toJUL(level), sourceClass, sourceMethod, 213 bundle, key, thrown); 214 } 215 216 @Override 217 public boolean isLoggable(sun.util.logging.PlatformLogger.Level level) { 218 return julLogger.isLoggable(toJUL(level)); 219 } 220 221 // ----------------------------------------------------------------- 222 // Generic methods taking a Level as parameter 223 // ----------------------------------------------------------------- 224 225 226 @Override 227 public boolean isLoggable(Level level) { 228 return julLogger.isLoggable(toJUL(level)); 229 } 230 231 @Override 232 public void log(Level level, String msg) { 233 julLogger.log(toJUL(level), msg); 234 } 235 236 @Override 237 public void log(Level level, 238 Supplier<String> msgSupplier) { 239 julLogger.log(toJUL(level), msgSupplier); 240 } 241 242 @Override 243 public void log(Level level, Object obj) { 244 julLogger.log(toJUL(level), () -> obj.toString()); 245 } 246 247 @Override 248 public void log(Level level, 249 String msg, Throwable thrown) { 250 julLogger.log(toJUL(level), msg, thrown); 251 } 252 253 @Override 254 public void log(Level level, Supplier<String> msgSupplier, 255 Throwable thrown) { 256 julLogger.log(toJUL(level), thrown, msgSupplier); 257 } 258 259 @Override 260 public void log(Level level, 261 String format, Object... params) { 262 julLogger.log(toJUL(level), format, params); 263 } 264 265 @Override 266 public void log(Level level, ResourceBundle bundle, 267 String key, Throwable thrown) { 268 julLogger.logrb(toJUL(level), bundle, key, thrown); 269 } 270 271 @Override 272 public void log(Level level, ResourceBundle bundle, 273 String format, Object... params) { 274 julLogger.logrb(toJUL(level), bundle, format, params); 275 } 276 277 static java.util.logging.Level toJUL(Level level) { 278 if (level == null) return null; 279 assert level.ordinal() < spi2JulLevelMapping.length; 280 return spi2JulLevelMapping[level.ordinal()]; 281 } 282 283 // --------------------------------------------------------- 284 // Methods from PlatformLoggerBridge 285 // --------------------------------------------------------- 286 287 @Override 288 public boolean isEnabled() { 289 return julLogger.getLevel() != java.util.logging.Level.OFF; 290 } 291 292 @Override 293 public PlatformLogger.Level getPlatformLevel() { 294 final java.util.logging.Level javaLevel = julLogger.getLevel(); 295 if (javaLevel == null) return null; 296 try { 297 return PlatformLogger.Level.valueOf(javaLevel.getName()); 298 } catch (IllegalArgumentException e) { 299 return PlatformLogger.Level.valueOf(javaLevel.intValue()); 300 } 301 } 302 303 @Override 304 public void setPlatformLevel(PlatformLogger.Level level) { 305 julLogger.setLevel(toJUL(level)); 306 } 307 308 @Override 309 public LoggerConfiguration getLoggerConfiguration() { 310 return this; 311 } 312 313 static java.util.logging.Level toJUL(PlatformLogger.Level level) { 314 if (level == null) return null; 315 assert level.ordinal() < platform2JulLevelMapping.length; 316 return platform2JulLevelMapping[level.ordinal()]; 317 } 318 319 @Override 320 public boolean equals(Object obj) { 321 return (obj instanceof JULWrapper) 322 && obj.getClass() == this.getClass() 323 && ((JULWrapper)obj).julLogger == this.julLogger; 324 } 325 326 @Override 327 public int hashCode() { 328 return julLogger.hashCode(); 329 } 330 331 // A JULWrapper is just a stateless thin shell over a JUL logger - so 332 // for a given JUL logger, we could always return the same wrapper. 333 // 334 // This is an optimization which may - or may not - be worth the 335 // trouble: if many classes use the same logger, and if each class 336 // keeps a reference to that logger, then caching the wrapper will 337 // be worthwhile. Otherwise, if each logger is only referred once, 338 // then the cache will eat up more memory than would be necessary... 339 // 340 // Here is an example of how we could implement JULWrapper.of(...) 341 // if we wanted to create at most one wrapper instance for each logger 342 // instance: 343 // 344 // static final WeakHashMap<JULWrapper, WeakReference<JULWrapper>> 345 // wrappers = new WeakHashMap<>(); 346 // 347 // static JULWrapper of(java.util.logging.Logger logger) { 348 // 349 // // First access without synchronizing 350 // final JULWrapper candidate = new JULWrapper(logger); 351 // WeakReference<JULWrapper> ref = wrappers.get(candidate); 352 // JULWrapper found = ref.get(); 353 // 354 // // OK - we found it - lets return it. 355 // if (found != null) return found; 356 // 357 // // Not found. Need to synchronize. 358 // synchronized (wrappers) { 359 // ref = wrappers.get(candidate); 360 // found = ref.get(); 361 // if (found == null) { 362 // wrappers.put(candidate, new WeakReference<>(candidate)); 363 // found = candidate; 364 // } 365 // } 366 // assert found != null; 367 // return found; 368 // } 369 // 370 // But given that it may end up eating more memory in the nominal case 371 // (where each class that does logging has its own logger with the 372 // class name as logger name and stashes that logger away in a static 373 // field, thus making the cache redundant - as only one wrapper will 374 // ever be created anyway) - then we will simply return a new wrapper 375 // for each invocation of JULWrapper.of(...) - which may 376 // still prove more efficient in terms of memory consumption... 377 // 378 static JULWrapper of(java.util.logging.Logger logger) { 379 return new JULWrapper(logger); 380 } 381 382 383 } 384 385 /** 386 * Creates a java.util.logging.Logger for the given caller. 387 * @param name the logger name. 388 * @param caller the caller for which the logger should be created. 389 * @return a Logger suitable for use in the given caller. 390 */ 391 private static java.util.logging.Logger demandJULLoggerFor(final String name, 392 /* Module */ 393 final Class<?> caller) { 394 final SecurityManager sm = System.getSecurityManager(); 395 if (sm == null) { 396 return java.util.logging.LogManager.demandLoggerFor(name, caller); 397 } else { 398 return AccessController.doPrivileged( 399 (PrivilegedAction<java.util.logging.Logger>) 400 () -> java.util.logging.LogManager.demandLoggerFor(name, caller), 401 null, LOGGING_DEMANDLOGGER_PERMISSION); 402 } 403 } 404 405 /** 406 * {@inheritDoc} 407 * 408 * @apiNote The logger returned by this method can be configured through 409 * its {@linkplain java.util.logging.LogManager#getLogger(String) 410 * corresponding java.util.logging.Logger backend}. 411 * 412 * @return {@inheritDoc} 413 * @throws SecurityException if the calling code doesn't have the 414 * {@code RuntimePermission("loggerFinder")}. 415 */ 416 @Override 417 protected Logger demandLoggerFor(String name, /* Module */ Class<?> caller) { 418 final SecurityManager sm = System.getSecurityManager(); 419 if (sm != null) { 420 sm.checkPermission(LOGGER_CONTROL_PERMISSION); 421 } 422 return JULWrapper.of(demandJULLoggerFor(name,caller)); 423 } 424 425 }