Skip to content
Snippets Groups Projects
Commit b99e145f authored by jakubs's avatar jakubs
Browse files

BIS-194 add session monitoring

SVN: 26655
parent ec4b6c32
No related branches found
No related tags found
No related merge requests found
...@@ -16,8 +16,14 @@ ...@@ -16,8 +16,14 @@
package ch.systemsx.cisd.authentication; package ch.systemsx.cisd.authentication;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.Map; import java.util.Map;
import java.util.Properties;
import javax.annotation.Resource;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.time.DateUtils; import org.apache.commons.lang.time.DateUtils;
...@@ -30,6 +36,8 @@ import ch.systemsx.cisd.common.exceptions.UserFailureException; ...@@ -30,6 +36,8 @@ import ch.systemsx.cisd.common.exceptions.UserFailureException;
import ch.systemsx.cisd.common.logging.LogCategory; import ch.systemsx.cisd.common.logging.LogCategory;
import ch.systemsx.cisd.common.logging.LogFactory; import ch.systemsx.cisd.common.logging.LogFactory;
import ch.systemsx.cisd.common.server.IRemoteHostProvider; 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; import ch.systemsx.cisd.common.utilities.TokenGenerator;
/** /**
...@@ -61,8 +69,14 @@ public class DefaultSessionManager<T extends BasicSession> implements ISessionMa ...@@ -61,8 +69,14 @@ public class DefaultSessionManager<T extends BasicSession> implements ISessionMa
private static final Logger operationLog = LogFactory.getLogger(LogCategory.OPERATION, private static final Logger operationLog = LogFactory.getLogger(LogCategory.OPERATION,
DefaultSessionManager.class); DefaultSessionManager.class);
private static final Logger notifyLog = LogFactory.getLogger(LogCategory.NOTIFY,
DefaultSessionManager.class);
private static final TokenGenerator tokenGenerator = new TokenGenerator(); 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> private static final class FullSession<S extends BasicSession>
{ {
/** Session data. */ /** Session data. */
...@@ -140,6 +154,7 @@ public class DefaultSessionManager<T extends BasicSession> implements ISessionMa ...@@ -140,6 +154,7 @@ public class DefaultSessionManager<T extends BasicSession> implements ISessionMa
final IRemoteHostProvider remoteHostProvider, final int sessionExpirationPeriodMinutes, final IRemoteHostProvider remoteHostProvider, final int sessionExpirationPeriodMinutes,
final boolean tryEmailAsUserName) final boolean tryEmailAsUserName)
{ {
assert sessionFactory != null : "Missing session factory."; assert sessionFactory != null : "Missing session factory.";
assert prefixGenerator != null : "Missing prefix generator"; assert prefixGenerator != null : "Missing prefix generator";
assert authenticationService != null : "Missing authentication service."; assert authenticationService != null : "Missing authentication service.";
...@@ -175,10 +190,129 @@ public class DefaultSessionManager<T extends BasicSession> implements ISessionMa ...@@ -175,10 +190,129 @@ public class DefaultSessionManager<T extends BasicSession> implements ISessionMa
sessionExpirationPeriodMillis); sessionExpirationPeriodMillis);
final FullSession<T> createdSession = new FullSession<T>(session); final FullSession<T> createdSession = new FullSession<T>(session);
sessions.put(createdSession.getSession().getSessionToken(), createdSession); sessions.put(createdSession.getSession().getSessionToken(), createdSession);
getSessionMonitor().logSessionMonitoringInfo();
return session; 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) private static void checkIfNotBlank(final String object, final String name)
throws UserFailureException throws UserFailureException
{ {
...@@ -291,8 +425,9 @@ public class DefaultSessionManager<T extends BasicSession> implements ISessionMa ...@@ -291,8 +425,9 @@ public class DefaultSessionManager<T extends BasicSession> implements ISessionMa
{ {
return getSession(sessionToken, true); 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"); checkIfNotBlank(sessionToken, "sessionToken");
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment