net.testdriven.psiprobe.tools.ApplicationUtils.java Source code

Java tutorial

Introduction

Here is the source code for net.testdriven.psiprobe.tools.ApplicationUtils.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.tools;

import net.testdriven.psiprobe.beans.ResourceResolver;
import net.testdriven.psiprobe.model.Application;
import net.testdriven.psiprobe.model.ApplicationParam;
import net.testdriven.psiprobe.model.ApplicationResource;
import net.testdriven.psiprobe.model.ApplicationSession;
import net.testdriven.psiprobe.model.Attribute;
import net.testdriven.psiprobe.model.FilterInfo;
import net.testdriven.psiprobe.model.ServletInfo;
import net.testdriven.psiprobe.model.ServletMapping;
import java.io.Serializable;
import java.net.InetAddress;
import java.util.ArrayList;
import java.util.Date;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import javax.naming.NamingException;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpSession;
import net.sf.javainetlocator.InetAddressLocator;
import org.apache.catalina.Container;
import org.apache.catalina.Context;
import org.apache.catalina.Session;
import org.apache.catalina.Wrapper;
import org.apache.catalina.core.StandardWrapper;
import org.apache.catalina.deploy.ApplicationParameter;
import org.apache.catalina.deploy.FilterDef;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.util.ClassUtils;

/**
 * 
 * @author Vlad Ilyushchenko
 * @author Andy Shapoval
 * @author Mark Lewis
 */
public class ApplicationUtils {

    private static Log logger = LogFactory.getLog(ApplicationUtils.class);

    public static Application getApplication(Context context) {
        return getApplication(context, null, false);
    }

    /**
     * Creates Application instance from Tomcat Context object. If ResourceResolver is passed the method will also collect additional information
     * about the application such as session count, session attribute count, application attribute count, servlet count, servlet stats summary and
     * datasource usage summary. Collecting additional information can be CPU intensive and time consuming so this should be avoided unless absolutely
     * required. Some datasource implementations (c3p0) are known to be prone to internal deadlocks, so this method can also hang is datasource usage
     * stats is to be collected.
     *
     * @param context
     * @param resourceResolver
     * @param calcSize
     * @return Application object
     */
    public static Application getApplication(Context context, ResourceResolver resourceResolver, boolean calcSize) {

        logger.debug("Querying webapp: " + context.getName());

        Application app = new Application();
        app.setName(context.getName().length() > 0 ? context.getName() : "/");
        app.setDocBase(context.getDocBase());
        app.setDisplayName(context.getDisplayName());
        app.setAvailable(context.getAvailable());
        app.setDistributable(context.getDistributable());
        app.setSessionTimeout(context.getSessionTimeout());
        app.setServletVersion(context.getServletContext().getMajorVersion() + "."
                + context.getServletContext().getMinorVersion());

        if (resourceResolver != null) {
            logger.debug("counting servlet attributes");

            int ctxAttrCount = 0;
            for (Enumeration e = context.getServletContext().getAttributeNames(); e.hasMoreElements(); e
                    .nextElement()) {
                ctxAttrCount++;
            }
            app.setContextAttributeCount(ctxAttrCount);

            if (app.isAvailable()) {
                logger.debug("collecting session information");

                app.setSessionCount(context.getManager().findSessions().length);

                boolean serializable = true;
                int sessionAttributeCount = 0;
                long size = 0;

                Session[] sessions = context.getManager().findSessions();
                for (int i = 0; i < sessions.length; i++) {
                    ApplicationSession appSession = getApplicationSession(sessions[i], calcSize, false);
                    if (appSession != null) {
                        sessionAttributeCount += appSession.getObjectCount();
                        serializable = serializable && appSession.isSerializable();
                        size += appSession.getSize();
                    }
                }
                app.setSerializable(serializable);
                app.setSessionAttributeCount(sessionAttributeCount);
                app.setSize(size);
            }

            logger.debug("aggregating servlet stats");

            collectApplicationServletStats(context, app);

            if (resourceResolver.supportsPrivateResources() && app.isAvailable()) {
                int[] scores = getApplicationDataSourceUsageScores(context, resourceResolver);
                app.setDataSourceBusyScore(scores[0]);
                app.setDataSourceEstablishedScore(scores[1]);
            }
        }

        return app;
    }

    /**
     * Calculates Sum of requestCount, errorCount and processingTime for all servlets for the
     * give application. It also works out minimum value of minTime and maximum value for maxTime for
     * all servlets.
     *
     * @param context
     * @param app
     */

    public static void collectApplicationServletStats(Context context, Application app) {
        int svltCount = 0;
        int reqCount = 0;
        int errCount = 0;
        long procTime = 0;
        long minTime = Long.MAX_VALUE;
        long maxTime = 0;

        Container[] cns = context.findChildren();
        for (int i = 0; i < cns.length; i++) {
            if (cns[i] instanceof StandardWrapper) {
                StandardWrapper sw = (StandardWrapper) cns[i];
                svltCount++;
                reqCount += sw.getRequestCount();
                errCount += sw.getErrorCount();
                procTime += sw.getProcessingTime();
                if (sw.getRequestCount() > 0) {
                    minTime = Math.min(minTime, sw.getMinTime());
                }
                maxTime = Math.max(maxTime, sw.getMaxTime());
            }
        }
        app.setServletCount(svltCount);
        app.setRequestCount(reqCount);
        app.setErrorCount(errCount);
        app.setProcessingTime(procTime);
        app.setMinTime(minTime == Long.MAX_VALUE ? 0 : minTime);
        app.setMaxTime(maxTime);
    }

    public static int[] getApplicationDataSourceUsageScores(Context context, ResourceResolver resolver) {
        logger.debug("Calculating datasource usage score");

        int[] scores = new int[] { 0, 0 };
        List appResources;
        try {
            appResources = resolver.getApplicationResources(context);
        } catch (NamingException e) {
            throw new RuntimeException(e);
        }
        for (Iterator it = appResources.iterator(); it.hasNext();) {
            ApplicationResource appResource = (ApplicationResource) it.next();
            if (appResource.getDataSourceInfo() != null) {
                scores[0] = Math.max(scores[0], appResource.getDataSourceInfo().getBusyScore());
                scores[1] = Math.max(scores[1], appResource.getDataSourceInfo().getEstablishedScore());
            }
        }
        return scores;
    }

    public static ApplicationSession getApplicationSession(Session session, boolean calcSize,
            boolean addAttributes) {
        ApplicationSession sbean = null;
        if (session != null && session.isValid()) {
            sbean = new ApplicationSession();

            sbean.setId(session.getId());
            sbean.setCreationTime(new Date(session.getCreationTime()));
            sbean.setLastAccessTime(new Date(session.getLastAccessedTime()));
            sbean.setMaxIdleTime(session.getMaxInactiveInterval() * 1000);
            sbean.setManagerType(session.getManager().getClass().getName());
            sbean.setInfo(session.getInfo());

            boolean sessionSerializable = true;
            int attributeCount = 0;
            long size = 0;

            HttpSession httpSession = session.getSession();
            Set processedObjects = new HashSet(1000);

            //Exclude references back to the session itself
            processedObjects.add(httpSession);
            try {
                for (Enumeration e = httpSession.getAttributeNames(); e.hasMoreElements();) {
                    String name = (String) e.nextElement();
                    Object o = httpSession.getAttribute(name);
                    sessionSerializable = sessionSerializable && o instanceof Serializable;

                    long oSize = 0;
                    if (calcSize) {
                        try {
                            oSize += Instruments.sizeOf(name, processedObjects);
                            oSize += Instruments.sizeOf(o, processedObjects);
                        } catch (Throwable th) {
                            logger.error("Cannot estimate size of attribute \"" + name + "\"", th);
                            //
                            // make sure we always re-throw ThreadDeath
                            //
                            if (e instanceof ThreadDeath) {
                                throw (ThreadDeath) e;
                            }
                        }
                    }

                    if (addAttributes) {
                        Attribute saBean = new Attribute();
                        saBean.setName(name);
                        saBean.setType(ClassUtils.getQualifiedName(o.getClass()));
                        saBean.setValue(o);
                        saBean.setSize(oSize);
                        saBean.setSerializable(o instanceof Serializable);
                        sbean.addAttribute(saBean);
                    }
                    attributeCount++;
                    size += oSize;
                }
                String lastAccessedIP = (String) httpSession.getAttribute(ApplicationSession.LAST_ACCESSED_BY_IP);
                if (lastAccessedIP != null) {
                    sbean.setLastAccessedIP(lastAccessedIP);
                }
                try {
                    sbean.setLastAccessedIPLocale(
                            InetAddressLocator.getLocale(InetAddress.getByName(lastAccessedIP).getAddress()));
                } catch (Throwable e) {
                    logger.error("Cannot determine Locale of " + lastAccessedIP);
                    //
                    // make sure we always re-throw ThreadDeath
                    //
                    if (e instanceof ThreadDeath) {
                        throw (ThreadDeath) e;
                    }
                }

            } catch (IllegalStateException e) {
                logger.info("Session appears to be invalidated, ignore");
            }

            sbean.setObjectCount(attributeCount);
            sbean.setSize(size);
            sbean.setSerializable(sessionSerializable);
        }

        return sbean;
    }

    public static List getApplicationAttributes(Context context) {
        List attrs = new ArrayList();
        ServletContext servletCtx = context.getServletContext();
        for (Enumeration e = servletCtx.getAttributeNames(); e.hasMoreElements();) {
            String attrName = (String) e.nextElement();
            Object attrValue = servletCtx.getAttribute(attrName);

            Attribute attr = new Attribute();
            attr.setName(attrName);
            attr.setValue(attrValue);
            attr.setType(ClassUtils.getQualifiedName(attrValue.getClass()));
            attrs.add(attr);
        }
        return attrs;
    }

    public static List getApplicationInitParams(Context context) {
        // We'll try to determine if a parameter value comes from a deployment descriptor or a context descriptor.
        // assumption: Context.findParameter() returns only values of parameters that are declared in a deployment descriptor.
        // If a parameter is declared in a context descriptor with override=false and redeclared in a deployment descriptor,
        // Context.findParameter() still returns its value, even though the value is taken from a context descriptor.
        // context.findApplicationParameters() returns all parameters that are declared in a context descriptor regardless
        // of whether they are overridden in a deployment descriptor or not or not.

        // creating a set of parameter names that are declared in a context descriptor
        // and can not be ovevridden in a deployment descriptor.
        Set nonOverridableParams = new HashSet();
        ApplicationParameter[] appParams = context.findApplicationParameters();
        for (int i = 0; i < appParams.length; i++) {
            if (appParams[i] != null && !appParams[i].getOverride()) {
                nonOverridableParams.add(appParams[i].getName());
            }
        }

        List initParams = new ArrayList();
        ServletContext servletCtx = context.getServletContext();
        for (Enumeration e = servletCtx.getInitParameterNames(); e.hasMoreElements();) {
            String paramName = (String) e.nextElement();

            ApplicationParam param = new ApplicationParam();
            param.setName(paramName);
            param.setValue(servletCtx.getInitParameter(paramName));
            // if the parameter is declared in a deployment descriptor
            // and it is not declared in a context descriptor with override=false,
            // the value comes from the deployment descriptor
            param.setFromDeplDescr(
                    context.findParameter(paramName) != null && !nonOverridableParams.contains(paramName));
            initParams.add(param);
        }

        return initParams;
    }

    public static ServletInfo getApplicationServlet(Context context, String servletName) {
        Container c = context.findChild(servletName);

        if (c instanceof Wrapper) {
            Wrapper w = (Wrapper) c;
            return getServletInfo(w, context.getName());
        } else {
            return null;
        }
    }

    private static ServletInfo getServletInfo(Wrapper w, String contextName) {
        ServletInfo si = new ServletInfo();
        si.setApplicationName(contextName.length() > 0 ? contextName : "/");
        si.setServletName(w.getName());
        si.setServletClass(w.getServletClass());
        si.setAvailable(!w.isUnavailable());
        si.setLoadOnStartup(w.getLoadOnStartup());
        si.setRunAs(w.getRunAs());
        String[] ms = w.findMappings();
        for (int i = 0; i < ms.length; i++) {
            si.getMappings().add(ms[i]);
        }
        if (w instanceof StandardWrapper) {
            StandardWrapper sw = (StandardWrapper) w;
            si.setAllocationCount(sw.getCountAllocated());
            si.setErrorCount(sw.getErrorCount());
            si.setLoadTime(sw.getLoadTime());
            si.setMaxInstances(sw.getMaxInstances());
            si.setMaxTime(sw.getMaxTime());
            si.setMinTime(sw.getMinTime() == Long.MAX_VALUE ? 0 : sw.getMinTime());
            si.setProcessingTime(sw.getProcessingTime());
            si.setRequestCount(sw.getRequestCount());
            si.setSingleThreaded(sw.isSingleThreadModel());
        }
        return si;
    }

    public static List getApplicationServlets(Context context) {
        Container[] cns = context.findChildren();
        List servlets = new ArrayList(cns.length);
        for (int i = 0; i < cns.length; i++) {
            if (cns[i] instanceof Wrapper) {
                Wrapper w = (Wrapper) cns[i];
                servlets.add(getServletInfo(w, context.getName()));
            }
        }
        return servlets;
    }

    public static List getApplicationServletMaps(Context context) {
        String[] sms = context.findServletMappings();
        List servletMaps = new ArrayList(sms.length);
        for (int i = 0; i < sms.length; i++) {
            if (sms[i] != null) {
                String sn = context.findServletMapping(sms[i]);
                if (sn != null) {
                    ServletMapping sm = new ServletMapping();
                    sm.setApplicationName(context.getName().length() > 0 ? context.getName() : "/");
                    sm.setUrl(sms[i]);
                    sm.setServletName(sn);
                    Container c = context.findChild(sn);
                    if (c instanceof Wrapper) {
                        Wrapper w = (Wrapper) c;
                        sm.setServletClass(w.getServletClass());
                        sm.setAvailable(!w.isUnavailable());
                    }
                    servletMaps.add(sm);
                }
            }
        }
        return servletMaps;
    }

    public static FilterInfo getApplicationFilter(Context context, String filterName) {
        FilterDef fd = context.findFilterDef(filterName);
        if (fd != null) {
            return getFilterInfo(fd);
        } else {
            return null;
        }
    }

    private static FilterInfo getFilterInfo(FilterDef fd) {
        FilterInfo fi = new FilterInfo();
        fi.setFilterName(fd.getFilterName());
        fi.setFilterClass(fd.getFilterClass());
        fi.setFilterDesc(fd.getDescription());
        return fi;
    }

    public static List getApplicationFilters(Context context) {
        FilterDef[] fds = context.findFilterDefs();
        List filterDefs = new ArrayList(fds.length);
        for (int i = 0; i < fds.length; i++) {
            if (fds[i] != null) {
                FilterInfo fi = getFilterInfo(fds[i]);
                filterDefs.add(fi);
            }
        }
        return filterDefs;
    }

}