net.testdriven.psiprobe.beans.LogResolverBean.java Source code

Java tutorial

Introduction

Here is the source code for net.testdriven.psiprobe.beans.LogResolverBean.java

Source

/*
 * Licensed under the GPL License.  You may not use this file except in
 * compliance with the License.  You may obtain a copy of the License at
 *
 *     http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
 *
 * THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
 * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 */
package net.testdriven.psiprobe.beans;

import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.LinkedList;
import java.util.List;
import net.testdriven.psiprobe.model.Application;
import net.testdriven.psiprobe.model.DisconnectedLogDestination;
import net.testdriven.psiprobe.tools.ApplicationUtils;
import net.testdriven.psiprobe.tools.Instruments;
import net.testdriven.psiprobe.tools.logging.FileLogAccessor;
import net.testdriven.psiprobe.tools.logging.LogDestination;
import net.testdriven.psiprobe.tools.logging.catalina.CatalinaLoggerAccessor;
import net.testdriven.psiprobe.tools.logging.commons.CommonsLoggerAccessor;
import net.testdriven.psiprobe.tools.logging.jdk.Jdk14LoggerAccessor;
import net.testdriven.psiprobe.tools.logging.jdk.Jdk14ManagerAccessor;
import net.testdriven.psiprobe.tools.logging.log4j.Log4JLoggerAccessor;
import net.testdriven.psiprobe.tools.logging.log4j.Log4JManagerAccessor;
import net.testdriven.psiprobe.tools.logging.logback.LogbackFactoryAccessor;
import net.testdriven.psiprobe.tools.logging.logback.LogbackLoggerAccessor;
import org.apache.catalina.Context;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.util.ClassUtils;

/**
 *
 * @author Mark Lewis
 */
public class LogResolverBean {

    protected final Log logger = LogFactory.getLog(getClass());

    private ContainerWrapperBean containerWrapper;
    private List stdoutFiles = new ArrayList();

    public ContainerWrapperBean getContainerWrapper() {
        return containerWrapper;
    }

    public void setContainerWrapper(ContainerWrapperBean containerWrapper) {
        this.containerWrapper = containerWrapper;
    }

    public List getStdoutFiles() {
        return stdoutFiles;
    }

    public void setStdoutFiles(List stdoutFiles) {
        this.stdoutFiles = stdoutFiles;
    }

    public List<LogDestination> getLogDestinations(boolean all) {
        List<LogDestination> allAppenders = getAllLogDestinations();

        if (allAppenders != null) {
            //
            // this list has to guarantee the order in which elements are added
            //
            List<LogDestination> uniqueList = new LinkedList<>();
            LogComparator cmp = new LogDestinationComparator(all);

            Collections.sort(allAppenders, cmp);
            for (LogDestination dest : allAppenders) {
                if (Collections.binarySearch(uniqueList, dest, cmp) < 0) {
                    if (all || dest.getFile() == null || dest.getFile().exists()) {
                        uniqueList.add(new DisconnectedLogDestination(dest));
                    }
                }
            }
            return uniqueList;
        }
        return null;
    }

    public List<LogDestination> getLogSources(File logFile) {
        List<LogDestination> filtered = new LinkedList<>();
        List<LogDestination> sources = getLogSources();
        for (Object source : sources) {
            LogDestination dest = (LogDestination) source;
            if (logFile.equals(dest.getFile())) {
                filtered.add(dest);
            }
        }
        return filtered;
    }

    public List<LogDestination> getLogSources() {
        List<LogDestination> sources = new LinkedList<>();

        List<LogDestination> allAppenders = getAllLogDestinations();
        if (allAppenders != null) {
            LogComparator cmp = new LogSourceComparator();

            Collections.sort(allAppenders, cmp);
            for (LogDestination dest : allAppenders) {
                if (Collections.binarySearch(sources, dest, cmp) < 0) {
                    sources.add(new DisconnectedLogDestination(dest));
                }
            }
        }
        return sources;
    }

    private List<LogDestination> getAllLogDestinations() {
        if (Instruments.isInitialized()) {
            List<LogDestination> allAppenders = new ArrayList<>();

            //
            // interrogate classloader hierarchy
            //
            ClassLoader cl2 = Thread.currentThread().getContextClassLoader().getParent();
            while (cl2 != null) {
                interrogateClassLoader(cl2, null, allAppenders);
                cl2 = cl2.getParent();
            }

            //
            // check for known stdout files, such as "catalina.out"
            //
            interrogateStdOutFiles(allAppenders);

            //
            // interrogate webapp classloaders and avilable loggers
            //
            List contexts = getContainerWrapper().getTomcatContainer().findContexts();
            for (Object context : contexts) {
                Context ctx = (Context) context;
                interrogateContext(ctx, allAppenders);
            }

            return allAppenders;
        }
        return null;
    }

    public LogDestination getLogDestination(String logType, String webapp, boolean context, boolean root,
            String logName, String logIndex) {
        Context ctx = null;
        Application application = null;
        if (webapp != null) {
            ctx = getContainerWrapper().getTomcatContainer().findContext(webapp);
            if (ctx != null) {
                application = ApplicationUtils.getApplication(ctx);
            }
        }

        if ("stdout".equals(logType) && logName != null) {
            return getStdoutLogDestination(logName);
        } else if ("catalina".equals(logType) && ctx != null) {
            return getCatalinaLogDestination(ctx, application);
        } else if (logIndex != null
                && ("jdk".equals(logType) || "log4j".equals(logType) || "logback".equals(logType))) {
            if (context && ctx != null) {
                return getCommonsLogDestination(ctx, application, logIndex);
            }
            ClassLoader cl;
            ClassLoader prevCl = null;
            if (ctx != null) {
                cl = ctx.getLoader().getClassLoader();
                prevCl = ClassUtils.overrideThreadContextClassLoader(cl);
            } else {
                cl = Thread.currentThread().getContextClassLoader().getParent();
            }
            try {
                if ((root || logName != null)) {
                    if ("jdk".equals(logType)) {
                        return getJdk14LogDestination(cl, application, root, logName, logIndex);
                    } else if ("log4j".equals(logType)) {
                        return getLog4JLogDestination(cl, application, root, logName, logIndex);
                    } else if ("logback".equals(logType)) {
                        return getLogbackLogDestination(cl, application, root, logName, logIndex);
                    }
                }
            } finally {
                if (prevCl != null) {
                    ClassUtils.overrideThreadContextClassLoader(prevCl);
                }
            }
        }
        return null;
    }

    private void interrogateContext(Context ctx, List<LogDestination> allAppenders) {
        Application application = ApplicationUtils.getApplication(ctx);
        ClassLoader cl = ctx.getLoader().getClassLoader();

        try {
            Object contextLogger = getContainerWrapper().getTomcatContainer().getLogger(ctx);
            if (contextLogger != null) {
                if (contextLogger.getClass().getName().startsWith("org.apache.commons.logging")) {
                    CommonsLoggerAccessor commonsAccessor = new CommonsLoggerAccessor();
                    commonsAccessor.setTarget(contextLogger);
                    commonsAccessor.setApplication(application);
                    allAppenders.addAll(commonsAccessor.getDestinations());
                } else if (contextLogger.getClass().getName().startsWith("org.apache.catalina.logger")) {
                    CatalinaLoggerAccessor catalinaAccessor = new CatalinaLoggerAccessor();
                    catalinaAccessor.setApplication(application);
                    catalinaAccessor.setTarget(contextLogger);
                    allAppenders.add(catalinaAccessor);
                }
            }
        } catch (Throwable e) {
            logger.error("Could not interrogate context logger for " + ctx.getName()
                    + ". Enable debug logging to see the trace stack");
            logger.debug("  Stack trace:", e);
            //
            // make sure we always re-throw ThreadDeath
            //
            if (e instanceof ThreadDeath) {
                throw (ThreadDeath) e;
            }
        }

        if (application.isAvailable()) {
            ClassLoader prevCl = ClassUtils.overrideThreadContextClassLoader(cl);
            try {
                interrogateClassLoader(cl, application, allAppenders);
            } catch (Exception e) {
                logger.error("Could not interrogate classloader loggers for " + ctx.getName()
                        + ". Enable debug logging to see the trace stack");
                logger.debug("  Stack trace:", e);
            } finally {
                if (prevCl != null) {
                    ClassUtils.overrideThreadContextClassLoader(prevCl);
                }
            }
        }
    }

    private void interrogateClassLoader(ClassLoader cl, Application application, List<LogDestination> appenders) {
        String applicationName = (application != null ? "application \"" + application.getName() + "\"" : "server");

        //check for JDK loggers
        try {
            Jdk14ManagerAccessor jdk14accessor = new Jdk14ManagerAccessor(cl);
            jdk14accessor.setApplication(application);
            appenders.addAll(jdk14accessor.getHandlers());
        } catch (Throwable t) {
            //
            // make sure we always re-throw ThreadDeath
            //
            if (t instanceof ThreadDeath) {
                throw (ThreadDeath) t;
            }
            logger.debug("Could not resolve JDK loggers for " + applicationName, t);
        }

        // check for Log4J loggers
        try {
            Log4JManagerAccessor log4JAccessor = new Log4JManagerAccessor(cl);
            log4JAccessor.setApplication(application);
            appenders.addAll(log4JAccessor.getAppenders());
        } catch (Throwable t) {
            //
            // make sure we always re-throw ThreadDeath
            //
            if (t instanceof ThreadDeath) {
                throw (ThreadDeath) t;
            }
            logger.debug("Could not resolve log4j loggers for " + applicationName, t);
        }

        // check for Logback loggers
        try {
            LogbackFactoryAccessor logbackAccessor = new LogbackFactoryAccessor(cl);
            logbackAccessor.setApplication(application);
            appenders.addAll(logbackAccessor.getAppenders());
        } catch (Throwable t) {
            //
            // make sure we always re-throw ThreadDeath
            //
            if (t instanceof ThreadDeath) {
                throw (ThreadDeath) t;
            }
            logger.debug("Could not resolve logback loggers for " + applicationName, t);
        }
    }

    private void interrogateStdOutFiles(List<LogDestination> appenders) {
        for (Object stdoutFile : stdoutFiles) {
            String fileName = (String) stdoutFile;
            FileLogAccessor fla = resolveStdoutLogDestination(fileName);
            if (fla != null) {
                appenders.add(fla);
            }
        }
    }

    private LogDestination getStdoutLogDestination(String logName) {
        for (Object stdoutFile : stdoutFiles) {
            String fileName = (String) stdoutFile;
            if (fileName.equals(logName)) {
                FileLogAccessor fla = resolveStdoutLogDestination(fileName);
                if (fla != null) {
                    return fla;
                }
            }
        }
        return null;
    }

    private FileLogAccessor resolveStdoutLogDestination(String fileName) {
        File stdout = new File(System.getProperty("catalina.base"), "logs/" + fileName);
        if (stdout.exists()) {
            FileLogAccessor fla = new FileLogAccessor();
            fla.setName(fileName);
            fla.setFile(stdout);
            return fla;
        }
        return null;
    }

    private LogDestination getCatalinaLogDestination(Context ctx, Application application) {
        Object log = getContainerWrapper().getTomcatContainer().getLogger(ctx);
        if (log != null) {
            CatalinaLoggerAccessor logAccessor = new CatalinaLoggerAccessor();
            logAccessor.setTarget(log);
            logAccessor.setApplication(application);
            if (logAccessor.getFile().exists()) {
                return logAccessor;
            }
        }
        return null;
    }

    private LogDestination getCommonsLogDestination(Context ctx, Application application, String logIndex) {
        Object contextLogger = getContainerWrapper().getTomcatContainer().getLogger(ctx);
        CommonsLoggerAccessor commonsAccessor = new CommonsLoggerAccessor();
        commonsAccessor.setTarget(contextLogger);
        commonsAccessor.setApplication(application);
        return commonsAccessor.getDestination(logIndex);
    }

    private LogDestination getJdk14LogDestination(ClassLoader cl, Application application, boolean root,
            String logName, String handlerIndex) {
        try {
            Jdk14ManagerAccessor manager = new Jdk14ManagerAccessor(cl);
            manager.setApplication(application);
            Jdk14LoggerAccessor log = (root ? manager.getRootLogger() : manager.getLogger(logName));
            if (log != null) {
                return log.getHandler(handlerIndex);
            }
        } catch (Throwable t) {
            //always re-throw ThreadDeath when catching Throwable
            if (t instanceof ThreadDeath) {
                throw (ThreadDeath) t;
            }
            logger.debug("getJdk14LogDestination failed", t);
        }
        return null;
    }

    private LogDestination getLog4JLogDestination(ClassLoader cl, Application application, boolean root,
            String logName, String appenderName) {
        try {
            Log4JManagerAccessor manager = new Log4JManagerAccessor(cl);
            manager.setApplication(application);
            Log4JLoggerAccessor log = (root ? manager.getRootLogger() : manager.getLogger(logName));
            if (log != null) {
                return log.getAppender(appenderName);
            }
        } catch (Throwable t) {
            //always re-throw ThreadDeath when catching Throwable
            if (t instanceof ThreadDeath) {
                throw (ThreadDeath) t;
            }
            logger.debug("getLog4JLogDestination failed", t);
        }
        return null;
    }

    private LogDestination getLogbackLogDestination(ClassLoader cl, Application application, boolean root,
            String logName, String appenderName) {
        try {
            LogbackFactoryAccessor manager = new LogbackFactoryAccessor(cl);
            manager.setApplication(application);
            LogbackLoggerAccessor log = (root ? manager.getRootLogger() : manager.getLogger(logName));
            if (log != null) {
                return log.getAppender(appenderName);
            }
        } catch (Throwable t) {
            //always re-throw ThreadDeath when catching Throwable
            if (t instanceof ThreadDeath) {
                throw (ThreadDeath) t;
            }
            logger.debug("getLogbackLogDestination failed", t);
        }
        return null;
    }

    private static abstract class LogComparator implements Comparator<LogDestination> {

        protected static final char DELIM = '!';

        public final int compare(LogDestination d1, LogDestination d2) {
            boolean eitherAppIsNull = (d1.getApplication() == null || d2.getApplication() == null);
            String name1 = convertToString(d1, eitherAppIsNull);
            String name2 = convertToString(d2, eitherAppIsNull);
            return name1.compareTo(name2);
        }

        protected abstract String convertToString(LogDestination d1, boolean eitherAppIsNull);

    }

    private static class LogDestinationComparator extends LogComparator {

        private boolean all;

        public LogDestinationComparator(boolean all) {
            this.all = all;
        }

        protected String convertToString(LogDestination dest, boolean eitherAppIsNull) {
            File file = dest.getFile();
            String fileName = (file == null ? "" : file.getAbsolutePath());
            String name;
            if (all) {
                Application app = dest.getApplication();
                if (eitherAppIsNull) {
                    app = null;
                }
                String appName = (app == null ? "" : app.getName());
                String context = (dest.isContext() ? "is" : "not");
                String root = (dest.isRoot() ? "is" : "not");
                String logType = dest.getLogType();
                name = appName + DELIM + context + DELIM + root + DELIM + logType + DELIM + fileName;
            } else {
                name = fileName;
            }
            return name;
        }

    }

    private static class LogSourceComparator extends LogComparator {

        protected String convertToString(LogDestination dest, boolean eitherAppIsNull) {
            File file = dest.getFile();
            String fileName = (file == null ? "" : file.getAbsolutePath());
            Application app = dest.getApplication();
            if (eitherAppIsNull) {
                app = null;
            }
            String appName = (app == null ? "" : app.getName());
            String logType = dest.getLogType();
            String context = (dest.isContext() ? "is" : "not");
            String root = (dest.isRoot() ? "is" : "not");
            String logName = dest.getName();
            return appName + DELIM + logType + DELIM + context + DELIM + root + DELIM + logName + DELIM + fileName;
        }

    }

}