added session details manager.

session-42
Ranjith Manickam 2019-08-12 22:44:14 +05:30
parent 8902534782
commit 7212b4a559
9 changed files with 124 additions and 9 deletions

View File

@ -6,6 +6,8 @@ public interface SessionConstants {
String CATALINA_BASE = "catalina.base";
String CONF = "conf";
String SESSION_PERSISTENT_POLICIES = "session.persistent.policies";
String SESSION_ID_PREFIX = "session.id.prefix";
String EMPTY_STRING = "";
enum SessionPolicy {
DEFAULT, SAVE_ON_CHANGE, ALWAYS_SAVE_AFTER_REQUEST;

View File

@ -1,5 +1,7 @@
package tomcat.request.session.data.cache;
import java.util.Set;
/** author: Ranjith Manickam @ 12 Jul' 2018 */
public interface DataCache {
@ -45,4 +47,12 @@ public interface DataCache {
* @return - Returns the number of keys that were removed.
*/
Long delete(String key);
/**
* Returns the keys from data-cache.
*
* @param pattern - key pattern.
* @return - Returns the keys list.
*/
Set<String> keys(String pattern);
}

View File

@ -11,6 +11,7 @@ import java.io.Serializable;
import java.util.Date;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
@ -112,6 +113,21 @@ public class StandardDataCache extends RedisCache {
return (value == null) ? 0L : 1L;
}
/** {@inheritDoc} */
@Override
public Set<String> keys(String pattern) {
handleSessionData();
if (this.sessionData.isEmpty()) {
try {
return super.keys(pattern);
} catch (RuntimeException ex) {
this.processDataSync = true;
throw ex;
}
}
return this.sessionData.keySet();
}
/** Session data. */
private static class SessionData implements Serializable {
private byte[] value;

View File

@ -3,6 +3,7 @@ package tomcat.request.session.data.cache.impl.redis;
import redis.clients.jedis.HostAndPort;
import redis.clients.jedis.JedisPoolConfig;
import redis.clients.jedis.Protocol;
import tomcat.request.session.SessionConstants;
import tomcat.request.session.data.cache.DataCache;
import tomcat.request.session.data.cache.DataCacheConstants;
import tomcat.request.session.data.cache.DataCacheConstants.RedisConfigType;
@ -19,39 +20,48 @@ import java.util.Set;
public class RedisCache implements DataCache {
private DataCache dataCache;
private final String sessionIdPrefix;
public RedisCache(Properties properties) {
initialize(properties);
String sessionKeyPrefix = properties.getProperty(SessionConstants.SESSION_ID_PREFIX, SessionConstants.EMPTY_STRING);
this.sessionIdPrefix = sessionKeyPrefix.equals(SessionConstants.EMPTY_STRING) ? sessionKeyPrefix : sessionKeyPrefix.concat("-");
}
/** {@inheritDoc} */
@Override
public byte[] set(String key, byte[] value) {
return dataCache.set(key, value);
return this.dataCache.set(this.sessionIdPrefix.concat(key), value);
}
/** {@inheritDoc} */
@Override
public Long setnx(String key, byte[] value) {
return dataCache.setnx(key, value);
return this.dataCache.setnx(this.sessionIdPrefix.concat(key), value);
}
/** {@inheritDoc} */
@Override
public Long expire(String key, int seconds) {
return dataCache.expire(key, seconds);
return this.dataCache.expire(this.sessionIdPrefix.concat(key), seconds);
}
/** {@inheritDoc} */
@Override
public byte[] get(String key) {
return dataCache.get(key);
return this.dataCache.get(this.sessionIdPrefix.concat(key));
}
/** {@inheritDoc} */
@Override
public Long delete(String key) {
return dataCache.delete(key);
return this.dataCache.delete(this.sessionIdPrefix.concat(key));
}
/** {@inheritDoc} */
@Override
public Set<String> keys(String pattern) {
return this.dataCache.keys(pattern);
}
private void initialize(Properties properties) {
@ -78,14 +88,14 @@ public class RedisCache implements DataCache {
JedisPoolConfig poolConfig = getPoolConfig(properties);
switch (configType) {
case CLUSTER:
dataCache = new RedisClusterManager((Set<HostAndPort>) nodes, password, timeout, poolConfig);
this.dataCache = new RedisClusterManager((Set<HostAndPort>) nodes, password, timeout, poolConfig);
break;
case SENTINEL:
String masterName = String.valueOf(DataCacheFactory.getProperty(properties, DataCacheConstants.REDIS_SENTINEL_MASTER));
dataCache = new RedisSentinelManager((Set<String>) nodes, masterName, password, database, timeout, poolConfig);
this.dataCache = new RedisSentinelManager((Set<String>) nodes, masterName, password, database, timeout, poolConfig);
break;
default:
dataCache = new RedisStandardManager(((List<String>) nodes).get(0), Integer.parseInt(((List<String>) nodes).get(1)), password, database, timeout, poolConfig);
this.dataCache = new RedisStandardManager(((List<String>) nodes).get(0), Integer.parseInt(((List<String>) nodes).get(1)), password, database, timeout, poolConfig);
break;
}
}

View File

@ -115,4 +115,22 @@ class RedisClusterManager extends RedisManager {
} while (retry && tries <= NUM_RETRIES);
return retVal;
}
/** {@inheritDoc} */
@Override
public Set<String> keys(String pattern) {
int tries = 0;
boolean retry = true;
Set<String> retVal = null;
do {
tries++;
try {
retVal = cluster.keys(pattern);
retry = false;
} catch (JedisRedirectionException | JedisConnectionException ex) {
handleException(tries, ex);
}
} while (retry && tries <= NUM_RETRIES);
return retVal;
}
}

View File

@ -8,6 +8,8 @@ import redis.clients.jedis.util.Pool;
import tomcat.request.session.data.cache.DataCache;
import tomcat.request.session.data.cache.DataCacheConstants;
import java.util.Set;
/** author: Ranjith Manickam @ 12 Jul' 2018 */
abstract class RedisManager implements DataCache {
@ -112,6 +114,24 @@ abstract class RedisManager implements DataCache {
return retVal;
}
/** {@inheritDoc} */
@Override
public Set<String> keys(String pattern) {
int tries = 0;
boolean retry = true;
Set<String> retVal = null;
do {
tries++;
try (Jedis jedis = this.pool.getResource()) {
retVal = jedis.keys(pattern);
retry = false;
} catch (JedisConnectionException ex) {
handleException(tries, ex);
}
} while (retry && tries <= NUM_RETRIES);
return retVal;
}
/**
* To handle jedis exception.
*

View File

@ -0,0 +1,29 @@
package tomcat.request.session.manager;
import tomcat.request.session.SessionConstants;
import tomcat.request.session.data.cache.DataCache;
import java.util.Set;
/** author: Ranjith Manickam @ 12 Aug' 2019 */
public class SessionDetailsManager {
private final DataCache dataCache;
private final String sessionIdPrefix;
public SessionDetailsManager(DataCache dataCache, String sessionIdPrefix) {
this.dataCache = dataCache;
this.sessionIdPrefix = sessionIdPrefix.equals(SessionConstants.EMPTY_STRING) ? sessionIdPrefix : sessionIdPrefix.concat("-*");
}
/** Returns active session count. */
public int getActiveSessionCount() {
Set<String> activeSessionIds = getActiveSessionIds();
return activeSessionIds == null ? 0 : activeSessionIds.size();
}
/** Returns active session ids. */
private Set<String> getActiveSessionIds() {
return this.dataCache.keys(this.sessionIdPrefix);
}
}

View File

@ -18,6 +18,7 @@ import tomcat.request.session.SessionMetadata;
import tomcat.request.session.data.cache.DataCache;
import tomcat.request.session.data.cache.DataCacheConstants;
import tomcat.request.session.data.cache.DataCacheFactory;
import tomcat.request.session.manager.SessionDetailsManager;
import java.io.File;
import java.io.FileInputStream;
@ -33,12 +34,17 @@ import java.util.Set;
public class SessionManager extends ManagerBase implements Lifecycle {
private static final Logger LOGGER = LoggerFactory.getLogger(SessionManager.class);
private static SessionDetailsManager sessionDetailsManager;
private DataCache dataCache;
private SerializationUtil serializer;
private ThreadLocal<SessionContext> sessionContext = new ThreadLocal<>();
private Set<SessionPolicy> sessionPolicy = EnumSet.of(SessionPolicy.DEFAULT);
public static SessionDetailsManager getSessionDetailsManagerInstance() {
return sessionDetailsManager;
}
public boolean getSaveOnChange() {
return this.sessionPolicy.contains(SessionPolicy.SAVE_ON_CHANGE);
}
@ -220,6 +226,7 @@ public class SessionManager extends ManagerBase implements Lifecycle {
this.serializer.setClassLoader(loader);
setSessionPersistentPolicies(properties);
sessionDetailsManager = new SessionDetailsManager(this.dataCache, properties.getProperty(SessionConstants.SESSION_ID_PREFIX, SessionConstants.EMPTY_STRING));
} catch (Exception ex) {
LOGGER.error("Error occurred while initializing the session manager..", ex);
throw ex;

View File

@ -31,4 +31,7 @@ lb.sticky-session.enabled=false
# policies - DEFAULT, SAVE_ON_CHANGE, ALWAYS_SAVE_AFTER_REQUEST
# 1. SAVE_ON_CHANGE: every time session.setAttribute() or session.removeAttribute() is called the session will be saved.
# 2. ALWAYS_SAVE_AFTER_REQUEST: force saving after every request, regardless of whether or not the manager has detected changes to the session.
session.persistent.policies=DEFAULT
session.persistent.policies=DEFAULT
#- session id prefix. By default, the JSESSIONID value is used as the key. And this prefix value is mandatory to monitor the active sessions. (ex: jsessionid)
#session.id.prefix=jsessionid