From b99e145f9f1435693a44e513223fac0e88995a8d Mon Sep 17 00:00:00 2001 From: jakubs <jakubs> Date: Tue, 18 Sep 2012 08:07:27 +0000 Subject: [PATCH] BIS-194 add session monitoring SVN: 26655 --- .../authentication/DefaultSessionManager.java | 139 +++++++++++++++++- 1 file changed, 137 insertions(+), 2 deletions(-) diff --git a/authentication/source/java/ch/systemsx/cisd/authentication/DefaultSessionManager.java b/authentication/source/java/ch/systemsx/cisd/authentication/DefaultSessionManager.java index f4bae8c6c3d..3ba1d911eb5 100644 --- a/authentication/source/java/ch/systemsx/cisd/authentication/DefaultSessionManager.java +++ b/authentication/source/java/ch/systemsx/cisd/authentication/DefaultSessionManager.java @@ -16,8 +16,14 @@ package ch.systemsx.cisd.authentication; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.Date; import java.util.LinkedHashMap; import java.util.Map; +import java.util.Properties; + +import javax.annotation.Resource; import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.time.DateUtils; @@ -30,6 +36,8 @@ import ch.systemsx.cisd.common.exceptions.UserFailureException; import ch.systemsx.cisd.common.logging.LogCategory; import ch.systemsx.cisd.common.logging.LogFactory; import ch.systemsx.cisd.common.server.IRemoteHostProvider; +import ch.systemsx.cisd.common.spring.ExposablePropertyPlaceholderConfigurer; +import ch.systemsx.cisd.common.utilities.PropertyUtils; import ch.systemsx.cisd.common.utilities.TokenGenerator; /** @@ -61,8 +69,14 @@ public class DefaultSessionManager<T extends BasicSession> implements ISessionMa private static final Logger operationLog = LogFactory.getLogger(LogCategory.OPERATION, DefaultSessionManager.class); + private static final Logger notifyLog = LogFactory.getLogger(LogCategory.NOTIFY, + DefaultSessionManager.class); + private static final TokenGenerator tokenGenerator = new TokenGenerator(); + @Resource(name = ExposablePropertyPlaceholderConfigurer.PROPERTY_CONFIGURER_BEAN_NAME) + protected ExposablePropertyPlaceholderConfigurer configurer; + private static final class FullSession<S extends BasicSession> { /** Session data. */ @@ -140,6 +154,7 @@ public class DefaultSessionManager<T extends BasicSession> implements ISessionMa final IRemoteHostProvider remoteHostProvider, final int sessionExpirationPeriodMinutes, final boolean tryEmailAsUserName) { + assert sessionFactory != null : "Missing session factory."; assert prefixGenerator != null : "Missing prefix generator"; assert authenticationService != null : "Missing authentication service."; @@ -175,10 +190,129 @@ public class DefaultSessionManager<T extends BasicSession> implements ISessionMa sessionExpirationPeriodMillis); final FullSession<T> createdSession = new FullSession<T>(session); sessions.put(createdSession.getSession().getSessionToken(), createdSession); + + getSessionMonitor().logSessionMonitoringInfo(); + return session; } } + private ISessionMonitor getSessionMonitor() + { + if (sessionMonitor == null) + { + synchronized (this) + { + if (sessionMonitor == null) + { + sessionMonitor = createSessionMonitor(); + } + } + } + return sessionMonitor; + } + + private volatile ISessionMonitor sessionMonitor; + + private ISessionMonitor createSessionMonitor() + { + Properties properties = configurer.getResolvedProps(); + int sessionNotifyThreshold = + PropertyUtils.getInt(properties, SessionMonitor.SESSION_NOTIFY_THRESHOLD_KEY, + SessionMonitor.SESSION_NOTIFY_THRESHOLD_DEFAULT); + int notificationDelayPeriod = + PropertyUtils.getInt(properties, SessionMonitor.SESSION_NOTIFY_DELAY_PERDIOD_KEY, + SessionMonitor.SESSION_NOTIFY_DELAY_PERDIOD_DEFAULT); + + if (sessionNotifyThreshold != 0) + { + operationLog.info("Create session monitor with threshold " + sessionNotifyThreshold); + return new SessionMonitor(sessionNotifyThreshold, notificationDelayPeriod); + } else + { + operationLog.info("Create dummy session monitor"); + return new ISessionMonitor() + { + @Override + public void logSessionMonitoringInfo() + { + } + }; + } + } + + private interface ISessionMonitor + { + void logSessionMonitoringInfo(); + } + + private class SessionMonitor implements ISessionMonitor + { + private static final String SESSION_NOTIFY_THRESHOLD_KEY = "session-notification-threshold"; + + private static final int SESSION_NOTIFY_THRESHOLD_DEFAULT = 0; + + private static final String SESSION_NOTIFY_DELAY_PERDIOD_KEY = + "session-notification-delay-period"; + + private static final int SESSION_NOTIFY_DELAY_PERDIOD_DEFAULT = 30 * 60; + + final DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + + final long lastNotification = 0; + + final int notificationDelayPeriod; + + final int sessionNotifyThreshold; + + public SessionMonitor(int sessionNotifyThreshold, int notificationDelayPeriod) + { + this.notificationDelayPeriod = notificationDelayPeriod; + this.sessionNotifyThreshold = sessionNotifyThreshold; + + if (sessionNotifyThreshold <= 0) + { + throw new IllegalArgumentException("Sessions threshold must be a positive integer"); + } + } + + @Override + public void logSessionMonitoringInfo() + { + int sessionsSize = sessions.size(); + + operationLog.info("Currently active sessions: " + sessionsSize); + + if (sessionsSize > sessionNotifyThreshold) + { + long now = System.currentTimeMillis(); + if (lastNotification + notificationDelayPeriod > now) + return; + + notifyLog.info("Number of active sessions has exceeded the threshold (" + + sessionNotifyThreshold + ")."); + for (FullSession<T> fullSession : sessions.values()) + { + T session = fullSession.getSession(); + session.getSessionStart(); + session.getUserName(); + session.getRemoteHost(); + session.isAnonymous(); + String message = + String.format( + "Session %s:\n User %s%s from %s\n Started at %s, will expire in %d seconds.", + session.getSessionToken(), session.getUserName(), + session.isAnonymous() ? "(anonymous)" : "", + session.getRemoteHost(), + df.format(new Date(session.getSessionStart())), + session.getSessionExpirationTime()); + notifyLog.info(message); + } + } + } + + } + private static void checkIfNotBlank(final String object, final String name) throws UserFailureException { @@ -291,8 +425,9 @@ public class DefaultSessionManager<T extends BasicSession> implements ISessionMa { return getSession(sessionToken, true); } - - private T getSession(final String sessionToken, boolean checkAndTouch) throws InvalidSessionException + + private T getSession(final String sessionToken, boolean checkAndTouch) + throws InvalidSessionException { checkIfNotBlank(sessionToken, "sessionToken"); -- GitLab