psiprobe.tools.ApplicationUtils Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of psi-probe-core Show documentation
Show all versions of psi-probe-core Show documentation
PSI Probe Core - Core logic, data models, and controllers
The newest version!
/*
* 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
*
* https://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 psiprobe.tools;
import jakarta.servlet.ServletContext;
import jakarta.servlet.http.HttpSession;
import java.io.Serializable;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Set;
import javax.naming.NamingException;
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.commons.lang3.reflect.MethodUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.ClassUtils;
import psiprobe.beans.ContainerWrapperBean;
import psiprobe.beans.ResourceResolver;
import psiprobe.model.Application;
import psiprobe.model.ApplicationParam;
import psiprobe.model.ApplicationResource;
import psiprobe.model.ApplicationSession;
import psiprobe.model.Attribute;
import psiprobe.model.FilterInfo;
import psiprobe.model.ServletInfo;
import psiprobe.model.ServletMapping;
/**
* The Class ApplicationUtils.
*/
public final class ApplicationUtils {
/** The Constant logger. */
private static final Logger logger = LoggerFactory.getLogger(ApplicationUtils.class);
/**
* Prevent Instantiation.
*/
private ApplicationUtils() {
// Prevent Instantiation
}
/**
* Gets the application.
*
* @param context the context
* @param containerWrapper the container wrapper
*
* @return the application
*/
public static Application getApplication(Context context, ContainerWrapperBean containerWrapper) {
return getApplication(context, null, false, containerWrapper);
}
/**
* 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 the context from which to create the Application
* @param resourceResolver the resolver to use for resources associated with the given context
* @param calcSize flag which controls whether to calculate session size
* @param containerWrapper the wrapper for the context's root containing server
*
* @return Application object
*/
public static Application getApplication(Context context, ResourceResolver resourceResolver,
boolean calcSize, ContainerWrapperBean containerWrapper) {
// ContainerWrapperBean containerWrapper
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(containerWrapper.getTomcatContainer().getAvailable(context));
app.setDistributable(context.getDistributable());
app.setSessionTimeout(context.getSessionTimeout());
app.setServletVersion(context.getServletContext().getMajorVersion() + "."
+ context.getServletContext().getMinorVersion());
if (resourceResolver != null) {
logger.debug("counting servlet attributes");
app.setContextAttributeCount(
Collections.list(context.getServletContext().getAttributeNames()).size());
if (app.isAvailable()) {
logger.debug("collecting session information");
app.setSessionCount(context.getManager().findSessions().length);
boolean serializable = true;
long sessionAttributeCount = 0;
long size = 0;
for (Session session : context.getManager().findSessions()) {
ApplicationSession appSession = getApplicationSession(session, 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, containerWrapper);
app.setDataSourceBusyScore(scores[0]);
app.setDataSourceEstablishedScore(scores[1]);
}
}
return app;
}
/**
* Calculates Sum of requestCount, errorCount and processingTime for all servlets for the given
* application. It also works out minimum value of minTime and maximum value for maxTime for all
* servlets.
*
* @param context the context whose stats will be collected
* @param app the application in which to store the collected stats
*/
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;
for (Container container : context.findChildren()) {
if (container instanceof StandardWrapper) {
StandardWrapper sw = (StandardWrapper) container;
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);
}
/**
* Gets the application data source usage scores.
*
* @param context the context
* @param resolver the resolver
* @param containerWrapper the container wrapper
*
* @return the application data source usage scores
*/
public static int[] getApplicationDataSourceUsageScores(Context context,
ResourceResolver resolver, ContainerWrapperBean containerWrapper) {
logger.debug("Calculating datasource usage score");
int[] scores = {0, 0};
List appResources;
try {
appResources = resolver.getApplicationResources(context, containerWrapper);
} catch (NamingException e) {
throw new RuntimeException(e);
}
for (ApplicationResource appResource : appResources) {
if (appResource.getDataSourceInfo() != null) {
scores[0] = Math.max(scores[0], appResource.getDataSourceInfo().getBusyScore());
scores[1] = Math.max(scores[1], appResource.getDataSourceInfo().getEstablishedScore());
}
}
return scores;
}
/**
* Gets the application session.
*
* @param session the session
* @param calcSize the calc size
* @param addAttributes the add attributes
*
* @return the application session
*/
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());
// Tomcat 8+ dropped support of getInfo off session. This patch allows it to continue working
// for tomcat 7.
try {
Object info = MethodUtils.invokeMethod(session, "getInfo");
sbean.setInfo(String.valueOf(info));
} catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
sbean.setInfo(session.getClass().getSimpleName());
logger.trace("Cannot determine session info for tomcat 8+", e);
}
boolean sessionSerializable = true;
int attributeCount = 0;
long size = 0;
HttpSession httpSession = session.getSession();
Set