/*
* Copyright 2013 Andrej Petras <andrej@ajka-andrej.com>.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.lorislab.smonitor.connector.tomcat.util;
import org.lorislab.smonitor.connector.model.Application;
import org.lorislab.smonitor.connector.model.ApplicationDetails;
import org.lorislab.smonitor.connector.model.Attribute;
import org.lorislab.smonitor.connector.model.Host;
import org.lorislab.smonitor.connector.model.Server;
import org.lorislab.smonitor.connector.model.Session;
import org.lorislab.smonitor.connector.model.SessionDetails;
import org.lorislab.smonitor.profiler.utils.ObjectProfile;
import org.lorislab.smonitor.profiler.utils.ObjectProfiler;
import java.security.Principal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.apache.catalina.Container;
import org.apache.catalina.Context;
import org.apache.catalina.Engine;
import org.apache.catalina.Manager;
import org.apache.catalina.Service;
import org.apache.catalina.core.StandardContext;
import org.apache.catalina.core.StandardHost;
import org.apache.catalina.realm.GenericPrincipal;
import org.apache.catalina.session.StandardSession;
import org.lorislab.smonitor.connector.tomcat.listener.TrackingContainerListener;
/**
* The tomcat utility.
*
* @author Andrej Petras <andrej@ajka-andrej.com>
*/
public final class TomcatUtil {
/**
* The logger for this class.
*/
private static final Logger LOGGER = Logger.getLogger(TomcatUtil.class.getName());
/**
* The application prefix.
*/
private static final String APP_PREFIX = "/";
/**
* The root application.
*/
private static final String ROOT_NAME = "ROOT";
/**
* The root id.
*/
private static final String ROOT_ID = "";
/**
* The default constructor.
*/
private TomcatUtil() {
// empty constructor
}
/**
* Creates the session details.
*
* @param host the host.
* @param application the application.
* @param sessionId the session id.
* @return the session details.
*/
public static SessionDetails createSessionDetails(Service service, String host, String application, String sessionId) {
String id = TomcatUtil.createTomcatApplicationId(application);
StandardSession session = getSession(service, host, id, sessionId);
SessionDetails result = null;
if (session != null) {
result = new SessionDetails();
// session info
result.setInfo(session.getInfo());
// create session basic information
Session tmp = createSession(host, application, session);
result.setSession(tmp);
// load user roles
GenericPrincipal principal = (GenericPrincipal) session.getPrincipal();
if (principal != null) {
String[] roles = principal.getRoles();
if (roles != null) {
result.setRoles(Arrays.asList(roles));
}
}
if (session instanceof StandardSession) {
StandardSession standardSession = (StandardSession) session;
// is new session flag
result.setNewSession(standardSession.isNew());
double size = 0;
double sizeSerializable = 0;
List<Attribute> attributes = new ArrayList<Attribute>();
Enumeration enumerator = standardSession.getAttributeNames();
while (enumerator.hasMoreElements()) {
String name = (String) enumerator.nextElement();
Attribute attr = createAttribute(name, standardSession.getAttribute(name));
attributes.add(attr);
size = size + attr.getSize();
sizeSerializable = sizeSerializable + attr.getSerializableSize();
}
result.setSize(size);
result.setSizeSerializable(sizeSerializable);
result.setAttributes(attributes);
}
}
return result;
}
/**
* Creates the attribute.
*
* @param name the name.
* @param value the value.
* @return the attribute.
*/
private static Attribute createAttribute(String name, Object value) {
Attribute attr = new Attribute();
attr.setName(name);
// load object information
ObjectProfile objectInfo = ObjectProfiler.createObjectInfo(value);
attr.setType(objectInfo.getClazz());
attr.setSize(objectInfo.getSize());
attr.setSerializable(objectInfo.isSerializable());
attr.setSerializableSize(objectInfo.getSerializableSize());
return attr;
}
/**
* Creates the application details.
*
* @param context the context.
* @return the application details.
*/
public static ApplicationDetails createApplicationDetails(Service service, String host, String application) {
String id = TomcatUtil.createTomcatApplicationId(application);
StandardContext context = getContext(service, host, id);
ApplicationDetails result = null;
if (context != null) {
result = new ApplicationDetails();
Application app = createApplication(context);
result.setId(app.getId());
result.setName(app.getName());
result.setHost(app.getHost());
result.setContext(context.getEncodedPath());
result.setStartTime(new Date(context.getStartTime()));
Manager manager = context.getManager();
if (manager != null) {
// The distributable flag for the sessions supported by this Manager
result.setDistributable(manager.getDistributable());
// Gets the number of sessions that have expired
result.setExpiredSessions(manager.getExpiredSessions());
// Gets the maximum number of sessions that have been active at the same time
result.setMaxActive(manager.getMaxActive());
// Return the default maximum inactive interval (in seconds) for Sessions created by this Manager.
result.setMaxInactiveInterval(manager.getMaxInactiveInterval());
// Gets the number of sessions that were not created because the maximum number of active sessions was reached.
result.setRejectedSessions(manager.getRejectedSessions());
// Gets the average time (in seconds) that expired sessions had been alive.
result.setSessionAverageAliveTime(manager.getSessionAverageAliveTime());
// Returns the total number of sessions created by this manager.
result.setSessionCounter(manager.getSessionCounter());
// Gets the session id length (in bytes) of Sessions created by this Manager.
result.setSessionIdLength(manager.getSessionIdLength());
// Gets the longest time (in seconds) that an expired session had been alive.
result.setSessionMaxAliveTime(manager.getSessionMaxAliveTime());
// Gets the number of currently active sessions.
result.setActiveSessions(manager.getActiveSessions());
// load sessions
List<Session> tmp = createSessions(app.getHost(), app.getName(), manager.findSessions());
result.setSessions(tmp);
}
}
return result;
}
/**
* Creates the session.
*
* @param session the session.
* @return the session.
*/
public static Session createSession(Service service, String host, String application, String sessionId) {
String id = createTomcatApplicationId(application);
StandardSession session = getSession(service, host, id, sessionId);
return createSession(host, application, session);
}
private static Session createSession(String host, String application, org.apache.catalina.Session session) {
Session result = null;
if (session != null) {
result = new Session();
result.setHost(host);
result.setApplication(getApplicationName(application));
//Return the session identifier for this session.
result.setId(session.getId());
//Return the isValid flag for this session.
result.setValid(session.isValid());
if (session.isValid()) {
//Return the creation time for this session.
result.setCreationTime(new Date(session.getCreationTime()));
//Return the last time the client sent a request associated with this session, as the number of milliseconds since midnight, January 1, 1970 GMT.
result.setLastAccessedTime(new Date(session.getLastAccessedTime()));
//Return the last client access time without invalidation check
result.setLastAccessedTimeInternal(session.getLastAccessedTimeInternal());
//Return the maximum time interval, in seconds, between client requests before the servlet container will invalidate the session.
result.setMaxInactiveInterval(session.getMaxInactiveInterval());
// Get user principal
Principal principal = (Principal) session.getPrincipal();
if (principal != null) {
result.setUser(principal.getName());
}
}
}
return result;
}
/**
* Creates the server.
*
* @param service the tomcat server service.
* @return the server.
*/
public static Server createServer(Service service) {
Server result = null;
if (service != null) {
Container root = service.getContainer();
if (root != null) {
Engine engine = (Engine) root;
result = new Server();
result.setId(engine.getName());
result.setName(engine.getName());
List<Host> hosts = new ArrayList<Host>();
for (Container container : engine.findChildren()) {
Host host = new Host();
host.setName(container.getName());
host.setId(container.getName());
hosts.add(host);
List<Application> applications = new ArrayList<Application>();
for (Container appContainer : container.findChildren()) {
Application app = createApplication(appContainer);
if (app != null) {
applications.add(app);
}
}
host.setApplications(applications);
}
result.setHosts(hosts);
}
}
return result;
}
/**
* Creates the application.
*
* @param context the container.
* @return the application.
*/
private static Application createApplication(Container context) {
Application result = null;
if (context != null) {
result = new Application();
result.setId(getTomcatApplicationId(context));
Container parent = context.getParent();
if (parent != null) {
result.setHost(parent.getName());
}
// The name string (suitable for use by humans)
result.setName(getApplicationName(context.getName()));
}
return result;
}
/**
* Gets the list of sessions.
*
* @param sessions the tomcat list of session.
* @return the list of sessions.
*/
public static List<Session> getSessions(Service service, String host, String application) {
String id = TomcatUtil.createTomcatApplicationId(application);
org.apache.catalina.Session[] sessions = getTomcatSessions(service, host, id);
List<Session> result = createSessions(host, application, sessions);
return result;
}
/**
* Gets the list of sessions.
*
* @param sessions the tomcat list of session.
* @return the list of sessions.
*/
private static List<Session> createSessions(String host, String application, org.apache.catalina.Session[] sessions) {
List<Session> result = new ArrayList<Session>();
if (sessions != null) {
for (org.apache.catalina.Session session : sessions) {
Session item = createSession(host, application, session);
if (item != null) {
result.add(item);
}
}
}
return result;
}
/**
* Gets the list of applications.
*
* @param contexts the list of containers.
* @return the list of applications.
*/
public static List<Application> getApplications(Service service) {
Container[] contexts = getContexts(service);
List<Application> result = new ArrayList<Application>();
if (contexts != null) {
for (Container tmp : contexts) {
Application app = createApplication(tmp);
if (app != null) {
result.add(app);
}
}
}
return result;
}
/**
* Gets the standard context for the host and application name.
*
* @param host the host.
* @param webApp the application name.
* @return the standard context.
*/
private static StandardContext getContext(Service service, String host, String webApp) {
StandardContext result = null;
StandardHost hostContainer = getHost(service, host);
if (hostContainer != null) {
result = (StandardContext) hostContainer.findChild(webApp);
} else {
LOGGER.log(Level.SEVERE, "No host {0} found", new Object[]{host});
}
return result;
}
/**
* Gets the list of contexts.
*
* @param host the host name.
* @return the list of context corresponding to the host name.
*/
private static Container[] getContexts(Service service, String host) {
Container[] result = null;
StandardHost hostContainer = getHost(service, host);
if (hostContainer != null) {
result = hostContainer.findChildren();
} else {
LOGGER.log(Level.SEVERE, "No host {0} found", new Object[]{host});
}
return result;
}
/**
* Gets the list of applications.
*
* @param contexts the list of containers.
* @return the list of applications.
*/
public static List<Application> getApplications(Service service, String host) {
Container[] contexts = getContexts(service, host);
List<Application> result = new ArrayList<Application>();
if (contexts != null) {
for (Container tmp : contexts) {
Application app = createApplication(tmp);
if (app != null) {
result.add(app);
}
}
}
return result;
}
/**
* Gets the host by name.
*
* @param host the host name.
* @return the host corresponding to the name.
*/
private static StandardHost getHost(Service service, String host) {
StandardHost result = null;
Engine engineService = (Engine) service.getContainer();
if (engineService != null) {
result = (StandardHost) engineService.findChild(host);
}
return result;
}
/**
* Gets the list of contexts.
*
* @return the list of contexts.
*/
private static Container[] getContexts(Service service) {
List<Container> result = new ArrayList<Container>();
Container root = service.getContainer();
if (root != null) {
Container[] hosts = root.findChildren();
if (hosts != null) {
for (Container host : hosts) {
Container[] items = host.findChildren();
result.addAll(Arrays.asList(items));
}
}
}
return result.toArray(new Container[result.size()]);
}
/**
* Gets the application name.
*
* @param name the tomcat application name.
* @return the application name.
*/
private static String getApplicationName(String name) {
String result = name;
if (name == null || name.isEmpty()) {
result = ROOT_NAME;
} else {
if (name.startsWith(APP_PREFIX)) {
result = name.substring(APP_PREFIX.length());
}
}
return result;
}
/**
* Gets the tomcat application id.
*
* @param container the container.
* @return the tomcat application id.
*/
private static String getTomcatApplicationId(Container container) {
String result = null;
if (container != null) {
result = getApplicationName(container.getName());
}
return result;
}
/**
* Creates the tomcat application id.
*
* @param name the application name.
* @return the tomcat application id.
*/
public static String createTomcatApplicationId(String name) {
String result = name;
if (ROOT_NAME.equals(name)) {
result = ROOT_ID;
} else {
if (name != null && !name.isEmpty()) {
if (!name.startsWith(APP_PREFIX)) {
result = APP_PREFIX + name;
}
}
}
return result;
}
/**
* Creates list of session for the search result.
*
* @param search the search result.
* @return the list of sessions.
*/
private static List<Session> createSearchResult(Map<String, Map<String, org.apache.catalina.Session[]>> search) {
List<Session> result = new ArrayList<Session>();
if (search != null) {
if (!search.isEmpty()) {
Set<String> hosts = search.keySet();
for (String host : hosts) {
Map<String, org.apache.catalina.Session[]> tmp = search.get(host);
if (!tmp.isEmpty()) {
Set<String> apps = tmp.keySet();
for (String app : apps) {
List<Session> sessions = createSessions(host, app, tmp.get(app));
if (sessions != null && !sessions.isEmpty()) {
result.addAll(sessions);
}
}
}
}
}
}
return result;
}
/**
* Gets the standard session for host, application and session id.
*
* @param host the host.
* @param webApp the application.
* @param sessionId the session id.
* @return the standard context corresponding to the host, application and
* session id.
*/
private static StandardSession getSession(Service service, String host, String webApp, String sessionId) {
StandardSession result = null;
StandardContext context = getContext(service, host, webApp);
if (context != null) {
Manager manager = context.getManager();
if (manager != null) {
try {
result = (StandardSession) manager.findSession(sessionId);
} catch (Exception ex) {
LOGGER.log(Level.SEVERE, "Error by reading the session " + sessionId, ex);
}
} else {
LOGGER.log(Level.SEVERE, "No mananager found for web application {0}, host {1}", new Object[]{webApp, host});
}
} else {
LOGGER.log(Level.SEVERE, "No context found for web application {0}, host {1}", new Object[]{webApp, host});
}
return result;
}
/**
* Deletes the session for host, application and session id.
*
* @param host the host.
* @param webApp the application.
* @param sessionId the session id.
* @return the deleted session to the host, application and session id.
*/
public static Session deleteSession(Service service, String host, String application, String sessionId) {
String id = createTomcatApplicationId(application);
Session result = null;
StandardSession tmp = getSession(service, host, id, sessionId);
if (tmp != null) {
tmp.invalidate();
result = createSession(host, application, tmp);
LOGGER.log(Level.INFO, "The session id {0}, application {1} and host {2} was deleted", new Object[]{sessionId, application, host});
} else {
LOGGER.log(Level.FINEST, "No session found for id {0}, application {0} and host {1}", new Object[]{sessionId, application, host});
}
return result;
}
/**
* Gets the list of sessions for the host and application.
*
* @param host the host.
* @param webApp the application.
* @return the list of sessions.
*/
private static org.apache.catalina.Session[] getTomcatSessions(Service service, String host, String webApp) {
org.apache.catalina.Session[] result = null;
StandardContext context = getContext(service, host, webApp);
result = getSessions(context);
return result;
}
/**
* Gets all session for the context.
*
* @param context the application context.
* @return the list of sessions.
*/
private static org.apache.catalina.Session[] getSessions(StandardContext context) {
org.apache.catalina.Session[] result = null;
if (context != null) {
Manager manager = context.getManager();
if (manager != null) {
try {
result = manager.findSessions();
} catch (Exception ex) {
LOGGER.log(Level.SEVERE, "Error by reading the list of sessions", ex);
}
} else {
LOGGER.log(Level.SEVERE, "No mananager found for web application");
}
} else {
LOGGER.log(Level.SEVERE, "No context found for web application");
}
return result;
}
public static List<Session> findSessionByCriteria(Service service, Set<String> applications) {
Map<String, Map<String, org.apache.catalina.Session[]>> tmp = findSession(service, applications);
return createSearchResult(tmp);
}
/**
* Gets all sessions for the web-application.
*
* @param webApps the web application name.
* @return the result of host and sessions.
*/
private static Map<String, Map<String, org.apache.catalina.Session[]>> findSession(Service service, Set<String> applications) {
Map<String, Map<String, org.apache.catalina.Session[]>> result = new HashMap<String, Map<String, org.apache.catalina.Session[]>>();
Container[] hosts = getHosts(service);
if (hosts != null) {
for (Container host : hosts) {
// search web application and sessions in the current host
Map<String, org.apache.catalina.Session[]> tmp = new HashMap<String, org.apache.catalina.Session[]>();
if (applications != null && !applications.isEmpty()) {
for (String app : applications) {
String id = TomcatUtil.createTomcatApplicationId(app);
Container container = host.findChild(id);
if (container != null) {
StandardContext context = (StandardContext) container;
tmp.put(id, getSessions(context));
}
}
} else {
Container[] containers = host.findChildren();
if (containers != null) {
for (Container container : containers) {
StandardContext context = (StandardContext) container;
tmp.put(container.getName(), getSessions(context));
}
}
}
// put to the host result
if (!tmp.isEmpty()) {
result.put(host.getName(), tmp);
}
}
}
return result;
}
/**
* Gets the list of hosts.
*
* @return the list of hosts.
*/
private static Container[] getHosts(Service service) {
Container[] result = null;
Engine engineService = (Engine) service.getContainer();
if (engineService != null) {
result = engineService.findChildren();
}
return result;
}
public static void addContainerListener(Service service, TrackingContainerListener listener) {
Container[] containers = getHosts(service);
if (containers != null) {
for (Container container : containers) {
container.addContainerListener(listener);
}
}
containers = getContexts(service);
if (containers != null) {
for (Container container : containers) {
listener.register((Context) container);
}
}
}
public static void removeContainerListener(Service service, TrackingContainerListener listener) {
Container[] containers = getHosts(service);
if (containers != null) {
for (Container container : containers) {
container.removeContainerListener(listener);
}
}
containers = getContexts(service);
if (containers != null) {
for (Container container : containers) {
listener.unregister((Context) container);
}
}
}
}