added session details manager.
parent
8902534782
commit
7212b4a559
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
*
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue