1 /*
   2  * Copyright (c) 2009, 2018, 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 com.sun.javafx.logging;
  27 
  28 import java.lang.ref.WeakReference;
  29 import java.util.Arrays;
  30 import java.util.HashMap;
  31 import java.util.Map;
  32 import java.util.ResourceBundle;
  33 
  34 /**
  35  * Platform logger provides an API for the JavaFX components to log
  36  * messages. It is an internal logger intended to be used by JavaFX modules.
  37  *
  38  * The PlatformLogger uses an underlying System.Logger
  39  * obtained by calling {@link java.lang.System.Logger#getLogger(String)}
  40  *
  41  * PlatformLogger implements System.Logger as to facilitiate logging of
  42  * calling class and method.
  43  * Note : JDK internal loggers know to skip any calls from System.Logger
  44  * classes when looking for the calling class / method.
  45  */
  46 public class PlatformLogger implements System.Logger {
  47 
  48     /**
  49      * PlatformLogger logging levels.
  50      */
  51     public static enum Level {
  52         // The name and value must match that of {@code java.lang.System.Level}s.
  53         // Declare in ascending order of the given value for binary search.
  54         ALL(System.Logger.Level.ALL),
  55         FINEST(System.Logger.Level.TRACE),
  56         FINER(System.Logger.Level.TRACE),
  57         FINE(System.Logger.Level.DEBUG),
  58         CONFIG(System.Logger.Level.DEBUG),
  59         INFO(System.Logger.Level.INFO),
  60         WARNING(System.Logger.Level.WARNING),
  61         SEVERE(System.Logger.Level.ERROR),
  62         OFF(System.Logger.Level.OFF);
  63 
  64         final System.Logger.Level systemLevel;
  65         Level(System.Logger.Level systemLevel) {
  66             this.systemLevel = systemLevel;
  67         }
  68 
  69         // The integer values must match that of {@code java.util.logging.Level}
  70         // objects.
  71         private static final int SEVERITY_OFF     = Integer.MAX_VALUE;
  72         private static final int SEVERITY_SEVERE  = 1000;
  73         private static final int SEVERITY_WARNING = 900;
  74         private static final int SEVERITY_INFO    = 800;
  75         private static final int SEVERITY_CONFIG  = 700;
  76         private static final int SEVERITY_FINE    = 500;
  77         private static final int SEVERITY_FINER   = 400;
  78         private static final int SEVERITY_FINEST  = 300;
  79         private static final int SEVERITY_ALL     = Integer.MIN_VALUE;
  80 
  81         // ascending order for binary search matching the list of enum constants
  82         private static final int[] LEVEL_VALUES = new int[] {
  83             SEVERITY_ALL, SEVERITY_FINEST, SEVERITY_FINER,
  84             SEVERITY_FINE, SEVERITY_CONFIG, SEVERITY_INFO,
  85             SEVERITY_WARNING, SEVERITY_SEVERE, SEVERITY_OFF
  86         };
  87 
  88         public System.Logger.Level systemLevel() {
  89             return systemLevel;
  90         }
  91 
  92         public int intValue() {
  93             return LEVEL_VALUES[this.ordinal()];
  94         }
  95 
  96         /**
  97          * Maps a severity value to an effective logger level.
  98          * @param level The severity of the messages that should be
  99          *        logged with a logger set to the returned level.
 100          * @return The effective logger level, which is the nearest Level value
 101          *         whose severity is greater or equal to the given level.
 102          *         For level > SEVERE (OFF excluded), return SEVERE.
 103          */
 104         public static Level valueOf(int level) {
 105             switch (level) {
 106                 // ordering per the highest occurrences in the jdk source
 107                 // finest, fine, finer, info first
 108                 case SEVERITY_FINEST  : return Level.FINEST;
 109                 case SEVERITY_FINE    : return Level.FINE;
 110                 case SEVERITY_FINER   : return Level.FINER;
 111                 case SEVERITY_INFO    : return Level.INFO;
 112                 case SEVERITY_WARNING : return Level.WARNING;
 113                 case SEVERITY_CONFIG  : return Level.CONFIG;
 114                 case SEVERITY_SEVERE  : return Level.SEVERE;
 115                 case SEVERITY_OFF     : return Level.OFF;
 116                 case SEVERITY_ALL     : return Level.ALL;
 117             }
 118             // return the nearest Level value >= the given level,
 119             // for level > SEVERE, return SEVERE and exclude OFF
 120             int i = Arrays.binarySearch(LEVEL_VALUES, 0, LEVEL_VALUES.length-2, level);
 121             return values()[i >= 0 ? i : (-i-1)];
 122         }
 123     }
 124 
 125     private System.Logger.Level getSystemLoggerLevel(Level l) {
 126             switch (l) {
 127                 case ALL :    return System.Logger.Level.ALL;
 128                 case FINEST:  return System.Logger.Level.TRACE;
 129                 case FINER:   return System.Logger.Level.TRACE;
 130                 case FINE:    return System.Logger.Level.DEBUG;
 131                 case CONFIG:  return System.Logger.Level.DEBUG;
 132                 case INFO:    return System.Logger.Level.INFO;
 133                 case WARNING: return System.Logger.Level.WARNING;
 134                 case SEVERE:  return System.Logger.Level.ERROR;
 135                 case OFF:     return System.Logger.Level.OFF;
 136                 default :     return System.Logger.Level.ALL;
 137             }
 138         }
 139 
 140 
 141     // Table of known loggers.  Maps names to PlatformLoggers.
 142     private static final Map<String,WeakReference<PlatformLogger>> loggers =
 143         new HashMap<>();
 144 
 145     /**
 146      * Returns a PlatformLogger of a given name.
 147      * @param name the name of the logger
 148      * @return a PlatformLogger
 149      */
 150     public static synchronized PlatformLogger getLogger(String name) {
 151         PlatformLogger log = null;
 152         WeakReference<PlatformLogger> ref = loggers.get(name);
 153         if (ref != null) {
 154             log = ref.get();
 155         }
 156         if (log == null) {
 157             log = new PlatformLogger(System.getLogger(name));
 158             loggers.put(name, new WeakReference<>(log));
 159         }
 160         return log;
 161     }
 162 
 163 
 164     private final System.Logger loggerProxy;
 165     private PlatformLogger(System.Logger loggerProxy) {
 166         this.loggerProxy = loggerProxy;
 167     }
 168 
 169     // ------------------------------------------------------------------------
 170     //          From System.Logger interface
 171     // ------------------------------------------------------------------------
 172 
 173     /**
 174      * Gets the name for this platform logger.
 175      * @return the name of the platform logger.
 176      */
 177     @Override
 178     public String getName() {
 179        throw new UnsupportedOperationException("not implemented");
 180     }
 181 
 182     @Override
 183     public boolean isLoggable(System.Logger.Level level) {
 184         throw new UnsupportedOperationException("not implemented");
 185     }
 186 
 187     @Override
 188     public void log(System.Logger.Level level, ResourceBundle bundle, String format, Object... params) {
 189         throw new UnsupportedOperationException("not implemented");
 190     }
 191 
 192     @Override
 193     public void log(System.Logger.Level level, ResourceBundle bundle, String msg, Throwable thrown) {
 194         throw new UnsupportedOperationException("not implemented");
 195     }
 196 
 197     // ------------------------------------------------------------------------
 198 
 199 
 200     /**
 201      * Returns true if a message of the given level would actually
 202      * be logged by this logger.
 203      * @param level the level
 204      * @return whether a message of that level would be logged
 205      */
 206     public boolean isLoggable(Level level) {
 207         if (level == null) {
 208             throw new NullPointerException();
 209         }
 210 
 211         return loggerProxy.isLoggable(getSystemLoggerLevel(level));
 212     }
 213 
 214     /**
 215      * Logs a SEVERE message.
 216      * @param msg the message
 217      */
 218     public void severe(String msg) {
 219         if (!loggingEnabled) return;
 220         loggerProxy.log(System.Logger.Level.ERROR, msg, (Object[])null);
 221     }
 222 
 223     public void severe(String msg, Throwable t) {
 224         if (!loggingEnabled) return;
 225         loggerProxy.log(System.Logger.Level.ERROR, msg, t);
 226     }
 227 
 228     public void severe(String msg, Object... params) {
 229         if (!loggingEnabled) return;
 230         loggerProxy.log(System.Logger.Level.ERROR, msg, params);
 231     }
 232 
 233     /**
 234      * Logs a WARNING message.
 235      * @param msg the message
 236      */
 237     public void warning(String msg) {
 238         if (!loggingEnabled) return;
 239         loggerProxy.log(System.Logger.Level.WARNING, msg, (Object[])null);
 240     }
 241 
 242     public void warning(String msg, Throwable t) {
 243         if (!loggingEnabled) return;
 244         loggerProxy.log(System.Logger.Level.WARNING, msg, t);
 245     }
 246 
 247     public void warning(String msg, Object... params) {
 248         if (!loggingEnabled) return;
 249         loggerProxy.log(System.Logger.Level.WARNING, msg, params);
 250     }
 251 
 252     /**
 253      * Logs an INFO message.
 254      * @param msg the message
 255      */
 256     public void info(String msg) {
 257         if (!loggingEnabled) return;
 258         loggerProxy.log(System.Logger.Level.INFO, msg, (Object[])null);
 259     }
 260 
 261     public void info(String msg, Throwable t) {
 262         if (!loggingEnabled) return;
 263         loggerProxy.log(System.Logger.Level.INFO, msg, t);
 264     }
 265 
 266     public void info(String msg, Object... params) {
 267         if (!loggingEnabled) return;
 268         loggerProxy.log(System.Logger.Level.INFO, msg, params);
 269     }
 270 
 271     /**
 272      * Logs a CONFIG message.
 273      * @param msg the message
 274      */
 275     public void config(String msg) {
 276         if (!loggingEnabled) return;
 277         loggerProxy.log(System.Logger.Level.DEBUG, msg, (Object[])null);
 278     }
 279 
 280     public void config(String msg, Throwable t) {
 281         if (!loggingEnabled) return;
 282         loggerProxy.log(System.Logger.Level.DEBUG, msg, t);
 283     }
 284 
 285     public void config(String msg, Object... params) {
 286         if (!loggingEnabled) return;
 287         loggerProxy.log(System.Logger.Level.DEBUG, msg, params);
 288     }
 289 
 290     /**
 291      * Logs a FINE message.
 292      * @param msg the message
 293      */
 294     public void fine(String msg) {
 295         if (!loggingEnabled) return;
 296         loggerProxy.log(System.Logger.Level.DEBUG, msg, (Object[])null);
 297     }
 298 
 299     public void fine(String msg, Throwable t) {
 300         if (!loggingEnabled) return;
 301         loggerProxy.log(System.Logger.Level.DEBUG, msg, t);
 302     }
 303 
 304     public void fine(String msg, Object... params) {
 305         if (!loggingEnabled) return;
 306         loggerProxy.log(System.Logger.Level.DEBUG, msg, params);
 307     }
 308 
 309     /**
 310      * Logs a FINER message.
 311      * @param msg the message
 312      */
 313     public void finer(String msg) {
 314         if (!loggingEnabled) return;
 315         loggerProxy.log(System.Logger.Level.TRACE, msg, (Object[])null);
 316     }
 317 
 318     public void finer(String msg, Throwable t) {
 319         if (!loggingEnabled) return;
 320         loggerProxy.log(System.Logger.Level.TRACE, msg, t);
 321     }
 322 
 323     public void finer(String msg, Object... params) {
 324         if (!loggingEnabled) return;
 325         loggerProxy.log(System.Logger.Level.TRACE, msg, params);
 326     }
 327 
 328     /**
 329      * Logs a FINEST message.
 330      * @param msg the message
 331      */
 332     public void finest(String msg) {
 333         if (!loggingEnabled) return;
 334         loggerProxy.log(System.Logger.Level.TRACE, msg, (Object[])null);
 335     }
 336 
 337     public void finest(String msg, Throwable t) {
 338         if (!loggingEnabled) return;
 339         loggerProxy.log(System.Logger.Level.TRACE, msg, t);
 340     }
 341 
 342     public void finest(String msg, Object... params) {
 343         if (!loggingEnabled) return;
 344         loggerProxy.log(System.Logger.Level.TRACE, msg, params);
 345     }
 346 
 347     // Methods for unit tests
 348     private boolean loggingEnabled = true;
 349     public void enableLogging() {
 350         loggingEnabled = true;
 351     };
 352 
 353     public void disableLogging() {
 354         loggingEnabled = false;
 355     }
 356 }
 357