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 package jdk.internal.logger; 27 28 import java.lang.ref.Reference; 29 import java.lang.ref.WeakReference; 30 import java.util.HashMap; 31 import java.util.Map; 32 import java.util.function.Function; 33 import java.lang.System.LoggerFinder; 34 import java.lang.System.Logger; 35 import java.lang.ref.ReferenceQueue; 36 import java.util.Collection; 37 import java.util.ResourceBundle; 38 39 /** 40 * Internal Service Provider Interface (SPI) that makes it possible to use 41 * {@code java.util.logging} as backend when the {@link 42 * sun.util.logging.internal.LoggingProviderImpl 43 * sun.util.logging.internal.LoggingProviderImpl} is present. 44 * <p> 45 * The JDK default implementation of the {@link LoggerFinder} will 46 * attempt to locate and load an {@linkplain 47 * java.util.ServiceLoader#loadInstalled(java.lang.Class) installed} 48 * implementation of the {@code DefaultLoggerFinder}. If {@code java.util.logging} 49 * is present, this will usually resolve to an instance of {@link 50 * sun.util.logging.internal.LoggingProviderImpl sun.util.logging.internal.LoggingProviderImpl}. 51 * Otherwise, if no concrete service provider is declared for 52 * {@code DefaultLoggerFinder}, the default implementation provided by this class 53 * will be used. 54 * <p> 55 * When the {@link sun.util.logging.internal.LoggingProviderImpl 56 * sun.util.logging.internal.LoggingProviderImpl} is not present then the 57 * default implementation provided by this class is to use a simple logger 58 * that will log messages whose level is INFO and above to the console. 59 * These simple loggers are not configurable. 60 * <p> 61 * When configuration is needed, an application should either link with 62 * {@code java.util.logging} - and use the {@code java.util.logging} for 63 * configuration, or link with {@link LoggerFinder another implementation} 64 * of the {@link LoggerFinder} 65 * that provides the necessary configuration. 66 * 67 * @apiNote Programmers are not expected to call this class directly. 68 * Instead they should rely on the static methods defined by {@link 69 * java.lang.System java.lang.System} or {@link sun.util.logging.PlatformLogger 70 * sun.util.logging.PlatformLogger}. 71 * 72 * @see java.lang.System.LoggerFinder 73 * @see jdk.internal.logger 74 * @see sun.util.logging.internal 75 * 76 */ 77 public class DefaultLoggerFinder extends LoggerFinder { 78 79 static final RuntimePermission LOGGERFINDER_PERMISSION = 80 new RuntimePermission("loggerFinder"); 81 82 /** 83 * Creates a new instance of DefaultLoggerFinder. 84 * @throws SecurityException if the calling code does not have the 85 * {@code RuntimePermission("loggerFinder")} 86 */ 87 protected DefaultLoggerFinder() { 88 this(checkPermission()); 89 } 90 91 private DefaultLoggerFinder(Void unused) { 92 // nothing to do. 93 } 94 95 private static Void checkPermission() { 96 final SecurityManager sm = System.getSecurityManager(); 97 if (sm != null) { 98 sm.checkPermission(LOGGERFINDER_PERMISSION); 99 } 100 return null; 101 } 102 103 // SharedLoggers is a default cache of loggers used when JUL is not 104 // present - in that case we use instances of SimpleConsoleLogger which 105 // cannot be directly configure through public APIs. 106 // 107 // We can therefore afford to simply maintain two domains - one for the 108 // system, and one for the application. 109 // 110 static final class SharedLoggers { 111 private final Map<String, Reference<Logger>> loggers = 112 new HashMap<>(); 113 private final ReferenceQueue<Logger> queue = new ReferenceQueue<>(); 114 115 synchronized Logger get(Function<String, Logger> loggerSupplier, final String name) { 116 Reference<? extends Logger> ref = loggers.get(name); 117 Logger w = ref == null ? null : ref.get(); 118 if (w == null) { 119 w = loggerSupplier.apply(name); 120 loggers.put(name, new WeakReference<>(w, queue)); 121 } 122 123 // Remove stale mapping... 124 Collection<Reference<Logger>> values = null; 125 while ((ref = queue.poll()) != null) { 126 if (values == null) values = loggers.values(); 127 values.remove(ref); 128 } 129 return w; 130 } 131 132 133 final static SharedLoggers system = new SharedLoggers(); 134 final static SharedLoggers application = new SharedLoggers(); 135 } 136 137 @Override 138 public final Logger getLogger(String name, /* Module */ Class<?> caller) { 139 checkPermission(); 140 return demandLoggerFor(name, caller); 141 } 142 143 @Override 144 public final Logger getLocalizedLogger(String name, ResourceBundle bundle, 145 /* Module */ Class<?> caller) { 146 return super.getLocalizedLogger(name, bundle, caller); 147 } 148 149 150 151 /** 152 * Returns a {@link Logger logger} suitable for the caller usage. 153 * 154 * @implSpec The default implementation for this method is to return a 155 * simple logger that will print all messages of INFO level and above 156 * to the console. That simple logger is not configurable. 157 * 158 * @param name The name of the logger. 159 * @param caller The class on behalf of which the logger is created. 160 * @return A {@link Logger logger} suitable for the application usage. 161 * @throws SecurityException if the calling code does not have the 162 * {@code RuntimePermission("loggerFinder")}. 163 */ 164 protected Logger demandLoggerFor(String name, /* Module */ Class<?> caller) { 165 checkPermission(); 166 if (caller.getClassLoader() == null) { 167 return SharedLoggers.system.get(SimpleConsoleLogger::makeSimpleLogger, name); 168 } else { 169 return SharedLoggers.application.get(SimpleConsoleLogger::makeSimpleLogger, name); 170 } 171 } 172 173 }