All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.xhtmlrenderer.util.JDKXRLogger Maven / Gradle / Ivy

Go to download

Flying Saucer is a CSS 2.1 renderer written in Java. This artifact contains the core rendering and layout code as well as Java2D output.

There is a newer version: 9.11.0
Show newest version
/*
 * {{{ header & license
 * Copyright (c) 2004, 2005 Joshua Marinacci
 * Copyright (c) 2007 Wisconsin Court System
 * Copyright (c) 2008 Patrick Wright
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public License
 * as published by the Free Software Foundation; either version 2.1
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 * }}}
 */
package org.xhtmlrenderer.util;

import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.logging.Formatter;
import java.util.logging.Handler;
import java.util.logging.Level;
import java.util.logging.Logger;

import static java.lang.Boolean.parseBoolean;

/**
 * An {@link XRLogger} interface that uses {@code java.util.logging}.
 */
public class JDKXRLogger implements XRLogger {

    private static boolean initPending = true;

    @Override
    public void log(String where, Level level, String msg) {
        if (initPending) {
            init();
        }

        getLogger(where).log(level, msg);
    }

    @Override
    public void log(String where, Level level, String msg, Throwable th) {
        if (initPending) {
            init();
        }

        getLogger(where).log(level, msg, th);
    }

    @Override
    public void setLevel(String logger, Level level) {
        getLogger(logger).setLevel(level);
    }

    /**
     * Same purpose as Logger.getLogger(), except that the static initialization
     * for XRLog will initialize the LogManager with logging levels and other
     * configuration. Use this instead of Logger.getLogger()
     */
    private static Logger getLogger(String log) {
        return Logger.getLogger(log);
    }

    private static void init() {
        synchronized (JDKXRLogger.class) {
            if (!initPending) {
                return;
            }
            //now change this immediately, in case something fails
            initPending = false;
            try {
                Properties props = retrieveLoggingProperties();

                if (!XRLog.isLoggingEnabled()) {
                    Configuration.setConfigLogger(Logger.getLogger(XRLog.CONFIG));
                    return;
                }
                initializeJDKLogManager(props);

                Configuration.setConfigLogger(Logger.getLogger(XRLog.CONFIG));
            } catch (SecurityException e) {
                // may happen in a sandbox environment
            }
        }
    }

    private static Properties retrieveLoggingProperties() {
        // pull logging properties from configuration
        // they are all prefixed as shown
        String prefix = "xr.util-logging.";
        Properties props = new Properties();
        Iterator iter = Configuration.keysByPrefix(prefix);
        while (iter.hasNext()) {
            String fullKey = iter.next();
            String key = fullKey.substring(prefix.length());
            String value = Configuration.valueFor(fullKey);
            props.setProperty(key, value);
        }
        return props;
    }

    private static void initializeJDKLogManager(final Properties fsLoggingProperties) {
        final List loggers = retrieveLoggers();

        configureLoggerHandlerForwarding(fsLoggingProperties, loggers);

        // load our properties into our log manager
        Map handlers = new HashMap<>();
        Map handlerFormatterMap = new HashMap<>();

        for (Object k : fsLoggingProperties.keySet()) {
            String key = (String) k;
            String prop = fsLoggingProperties.getProperty(key);
            if (key.endsWith("level")) {
                configureLogLevel(key.substring(0, key.lastIndexOf('.')), prop);
            } else if (key.endsWith("handlers")) {
                handlers = configureLogHandlers(loggers, prop);
            } else if (key.endsWith("formatter")) {
                String k2 = key.substring(0, key.length() - ".formatter".length());
                handlerFormatterMap.put(k2, prop);
            }
        }

        // formatters apply to a specific handler we have initialized previously,
        // hence we need to wait until we've parsed the handler class
        for (Map.Entry entry : handlerFormatterMap.entrySet()) {
            String formatterClassName = entry.getValue();
            assignFormatter(handlers, entry.getKey(), formatterClassName);
        }
    }

    private static void configureLoggerHandlerForwarding(Properties fsLoggingProperties, List loggers) {
        String val = fsLoggingProperties.getProperty("use-parent-handler");

        boolean flag = parseBoolean(val);
        for (Logger logger : loggers) {
            logger.setUseParentHandlers(flag);
        }
    }

    private static void assignFormatter(Map handlers, String handlerClassName, String formatterClassName) {
        Handler handler = handlers.get(handlerClassName);

        if (handler != null) {
            try {
                @SuppressWarnings("unchecked")
                Class fclass = (Class) Class.forName(formatterClassName);
                Formatter formatter = fclass.getConstructor().newInstance();
                handler.setFormatter(formatter);
            } catch (ClassNotFoundException | IllegalAccessException | InstantiationException | NoSuchMethodException | InvocationTargetException e) {
                throw new XRRuntimeException("Could not initialize logging properties; " +
                        "Can't instantiate Formatter class " + formatterClassName + ": " + e.getClass().getSimpleName(), e);
            }
        }
    }

    /**
     * Returns a List of all Logger instances used by Flying Saucer from the JDK LogManager; these will
     * be automatically created if they aren't already available.
     */
    private static List retrieveLoggers() {
        List loggerNames = XRLog.listRegisteredLoggers();
        List loggers = new ArrayList<>(loggerNames.size());

        for (String loggerName : loggerNames) {
            loggers.add(Logger.getLogger(loggerName));
        }

        return loggers;
    }

    /**
     * For each logger provided, assigns the logger an instance of the named log output handlers. Will attempt
     * to instantiate each handler; any which can't be instantiated will cause the method to throw a RuntimeException.
     *
     * @param loggers          List of Logger instances.
     * @param handlerClassList A space-separated string (following the configuration convention for JDK logging
     *                         configuration files, for handlers) of FQN of log handlers.
     * @return Map of handler class names to handler instances.
     */
    private static Map configureLogHandlers(List loggers, final String handlerClassList) {
        final String[] names = handlerClassList.split(" ");
        final Map handlers = new HashMap<>(names.length);

        for (final String name : names) {
            try {
                @SuppressWarnings("unchecked")
                Class handlerClass = (Class) Class.forName(name);
                Handler handler = handlerClass.getConstructor().newInstance();
                handlers.put(name, handler);
                String hl = Configuration.valueFor("xr.util-logging." + name + ".level", "INFO");
                handler.setLevel(LoggerUtil.parseLogLevel(hl, Level.INFO));
            } catch (ClassNotFoundException | IllegalAccessException | InstantiationException | NoSuchMethodException | InvocationTargetException e) {
                throw new XRRuntimeException("Could not initialize logging properties; " +
                        "Can't instantiate Handler class " + name + ": " + e.getClass().getSimpleName(), e);
            }
        }

        // now assign each handler to each FS logger
        for (Logger logger : loggers) {
            for (Handler handler : handlers.values()) {
                logger.addHandler(handler);
            }
        }
        return handlers;
    }

    /**
     * Parses the levelValue into a Level instance and assigns to the Logger instance named by loggerName; if
     * the levelValue is invalid (e.g. misspelled), assigns Level.OFF to the logger.
     */
    private static void configureLogLevel(String loggerName, String levelValue) {
        final Level level = LoggerUtil.parseLogLevel(levelValue, Level.OFF);
        final Logger logger = Logger.getLogger(loggerName);
        logger.setLevel(level);
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy