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