parent
4eb0e433b1
commit
7ea845ebca
|
@ -5,6 +5,7 @@ public interface SessionConstants {
|
|||
byte[] NULL_SESSION = "null".getBytes();
|
||||
String CATALINA_BASE = "catalina.base";
|
||||
String CONF = "conf";
|
||||
String SESSION_PERSISTENT_POLICIES = "session.persistent.policies";
|
||||
|
||||
enum SessionPolicy {
|
||||
DEFAULT, SAVE_ON_CHANGE, ALWAYS_SAVE_AFTER_REQUEST;
|
||||
|
|
|
@ -1,64 +1,27 @@
|
|||
package tomcat.request.session.data.cache;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import tomcat.request.session.SessionConstants;
|
||||
import tomcat.request.session.data.cache.impl.StandardDataCache;
|
||||
import tomcat.request.session.data.cache.impl.redis.RedisCache;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Properties;
|
||||
|
||||
/** author: Ranjith Manickam @ 3 Dec' 2018 */
|
||||
public class DataCacheFactory {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(DataCacheFactory.class);
|
||||
|
||||
private final Properties properties;
|
||||
private final int sessionExpiryTime;
|
||||
|
||||
public DataCacheFactory(int sessionExpiryTime) {
|
||||
public DataCacheFactory(Properties properties, int sessionExpiryTime) {
|
||||
this.properties = properties;
|
||||
this.sessionExpiryTime = sessionExpiryTime;
|
||||
}
|
||||
|
||||
/** To get data cache. */
|
||||
public DataCache getDataCache() {
|
||||
Properties properties = getApplicationProperties();
|
||||
|
||||
if (Boolean.valueOf(getProperty(properties, DataCacheConstants.LB_STICKY_SESSION_ENABLED))) {
|
||||
return new StandardDataCache(properties, this.sessionExpiryTime);
|
||||
if (Boolean.parseBoolean(getProperty(this.properties, DataCacheConstants.LB_STICKY_SESSION_ENABLED))) {
|
||||
return new StandardDataCache(this.properties, this.sessionExpiryTime);
|
||||
}
|
||||
|
||||
return new RedisCache(properties);
|
||||
}
|
||||
|
||||
/** To get redis data cache properties. */
|
||||
private Properties getApplicationProperties() {
|
||||
Properties properties = new Properties();
|
||||
try {
|
||||
String filePath = System.getProperty(SessionConstants.CATALINA_BASE).concat(File.separator)
|
||||
.concat(SessionConstants.CONF).concat(File.separator)
|
||||
.concat(DataCacheConstants.APPLICATION_PROPERTIES_FILE);
|
||||
|
||||
InputStream resourceStream = null;
|
||||
try {
|
||||
resourceStream = (!filePath.isEmpty() && new File(filePath).exists()) ? new FileInputStream(filePath) : null;
|
||||
if (resourceStream == null) {
|
||||
ClassLoader loader = Thread.currentThread().getContextClassLoader();
|
||||
resourceStream = loader.getResourceAsStream(DataCacheConstants.APPLICATION_PROPERTIES_FILE);
|
||||
}
|
||||
properties.load(resourceStream);
|
||||
} finally {
|
||||
if (resourceStream != null) {
|
||||
resourceStream.close();
|
||||
}
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
LOGGER.error("Error while retrieving application properties", ex);
|
||||
}
|
||||
return properties;
|
||||
return new RedisCache(this.properties);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -113,7 +113,7 @@ public class StandardDataCache extends RedisCache {
|
|||
}
|
||||
|
||||
/** Session data. */
|
||||
private class SessionData implements Serializable {
|
||||
private static class SessionData implements Serializable {
|
||||
private byte[] value;
|
||||
private long lastAccessedOn;
|
||||
|
||||
|
@ -157,7 +157,7 @@ public class StandardDataCache extends RedisCache {
|
|||
}
|
||||
|
||||
/** Session data redis sync thread. */
|
||||
private class SessionDataSyncThread implements Runnable {
|
||||
private static class SessionDataSyncThread implements Runnable {
|
||||
|
||||
private final Logger LOGGER = LoggerFactory.getLogger(SessionDataSyncThread.class);
|
||||
|
||||
|
@ -190,7 +190,7 @@ public class StandardDataCache extends RedisCache {
|
|||
}
|
||||
|
||||
/** Session data expiry thread. This will takes care of the session expired data removal. */
|
||||
private class SessionDataExpiryThread implements Runnable {
|
||||
private static class SessionDataExpiryThread implements Runnable {
|
||||
|
||||
private final Logger LOGGER = LoggerFactory.getLogger(SessionDataExpiryThread.class);
|
||||
|
||||
|
|
|
@ -56,9 +56,9 @@ public class RedisCache implements DataCache {
|
|||
|
||||
private void initialize(Properties properties) {
|
||||
RedisConfigType configType;
|
||||
if (Boolean.valueOf(DataCacheFactory.getProperty(properties, DataCacheConstants.REDIS_CLUSTER_ENABLED))) {
|
||||
if (Boolean.parseBoolean(DataCacheFactory.getProperty(properties, DataCacheConstants.REDIS_CLUSTER_ENABLED))) {
|
||||
configType = RedisConfigType.CLUSTER;
|
||||
} else if (Boolean.valueOf(DataCacheFactory.getProperty(properties, DataCacheConstants.REDIS_SENTINEL_ENABLED))) {
|
||||
} else if (Boolean.parseBoolean(DataCacheFactory.getProperty(properties, DataCacheConstants.REDIS_SENTINEL_ENABLED))) {
|
||||
configType = RedisConfigType.SENTINEL;
|
||||
} else {
|
||||
configType = RedisConfigType.DEFAULT;
|
||||
|
@ -73,7 +73,7 @@ public class RedisCache implements DataCache {
|
|||
int database = Integer.parseInt(DataCacheFactory.getProperty(properties, DataCacheConstants.REDIS_DATABASE));
|
||||
|
||||
int timeout = Integer.parseInt(DataCacheFactory.getProperty(properties, DataCacheConstants.REDIS_TIMEOUT));
|
||||
timeout = (timeout < Protocol.DEFAULT_TIMEOUT) ? Protocol.DEFAULT_TIMEOUT : timeout;
|
||||
timeout = Math.max(timeout, Protocol.DEFAULT_TIMEOUT);
|
||||
|
||||
JedisPoolConfig poolConfig = getPoolConfig(properties);
|
||||
switch (configType) {
|
||||
|
@ -107,7 +107,7 @@ public class RedisCache implements DataCache {
|
|||
boolean testOnReturn = Boolean.parseBoolean(DataCacheFactory.getProperty(properties, DataCacheConstants.REDIS_TEST_ONRETURN));
|
||||
poolConfig.setTestOnReturn(testOnReturn);
|
||||
|
||||
int maxIdle = Integer.parseInt(DataCacheFactory.getProperty(properties, DataCacheConstants.REDIS_MAX_ACTIVE));
|
||||
int maxIdle = Integer.parseInt(DataCacheFactory.getProperty(properties, DataCacheConstants.REDIS_MAX_IDLE));
|
||||
poolConfig.setMaxIdle(maxIdle);
|
||||
|
||||
int minIdle = Integer.parseInt(DataCacheFactory.getProperty(properties, DataCacheConstants.REDIS_MIN_IDLE));
|
||||
|
@ -143,14 +143,14 @@ public class RedisCache implements DataCache {
|
|||
switch (configType) {
|
||||
case CLUSTER:
|
||||
nodes = (nodes == null) ? new HashSet<>() : nodes;
|
||||
nodes.add(new HostAndPort(hostPortArr[0], Integer.valueOf(hostPortArr[1])));
|
||||
nodes.add(new HostAndPort(hostPortArr[0], Integer.parseInt(hostPortArr[1])));
|
||||
break;
|
||||
case SENTINEL:
|
||||
nodes = (nodes == null) ? new HashSet<>() : nodes;
|
||||
nodes.add(new HostAndPort(hostPortArr[0], Integer.valueOf(hostPortArr[1])).toString());
|
||||
nodes.add(new HostAndPort(hostPortArr[0], Integer.parseInt(hostPortArr[1])).toString());
|
||||
break;
|
||||
default:
|
||||
int port = Integer.valueOf(hostPortArr[1]);
|
||||
int port = Integer.parseInt(hostPortArr[1]);
|
||||
if (!hostPortArr[0].isEmpty() && port > 0) {
|
||||
List<String> node = new ArrayList<>();
|
||||
node.add(hostPortArr[0]);
|
||||
|
|
|
@ -16,29 +16,37 @@ import tomcat.request.session.SessionConstants.SessionPolicy;
|
|||
import tomcat.request.session.SessionContext;
|
||||
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 java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Arrays;
|
||||
import java.util.EnumSet;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
|
||||
/** author: Ranjith Manickam @ 12 Jul' 2018 */
|
||||
public class SessionManager extends ManagerBase implements Lifecycle {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(SessionManager.class);
|
||||
|
||||
private DataCache dataCache;
|
||||
private SerializationUtil serializer;
|
||||
|
||||
private ThreadLocal<SessionContext> sessionContext = new ThreadLocal<>();
|
||||
private Set<SessionPolicy> sessionPolicy = EnumSet.of(SessionPolicy.DEFAULT);
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(SessionManager.class);
|
||||
|
||||
public boolean getSaveOnChange() {
|
||||
return this.sessionPolicy.contains(SessionPolicy.SAVE_ON_CHANGE);
|
||||
}
|
||||
|
||||
private boolean getAlwaysSaveAfterRequest() {
|
||||
return this.sessionPolicy.contains(SessionPolicy.ALWAYS_SAVE_AFTER_REQUEST);
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public void addLifecycleListener(LifecycleListener listener) {
|
||||
|
@ -203,11 +211,15 @@ public class SessionManager extends ManagerBase implements Lifecycle {
|
|||
/** To initialize the session manager. */
|
||||
private void initialize() {
|
||||
try {
|
||||
this.dataCache = new DataCacheFactory(getSessionTimeout(null)).getDataCache();
|
||||
Properties properties = getApplicationProperties();
|
||||
this.dataCache = new DataCacheFactory(properties, getSessionTimeout(null)).getDataCache();
|
||||
this.serializer = new SerializationUtil();
|
||||
|
||||
Context context = getContextIns();
|
||||
ClassLoader loader = (context != null && context.getLoader() != null) ? context.getLoader().getClassLoader() : null;
|
||||
this.serializer.setClassLoader(loader);
|
||||
|
||||
setSessionPersistentPolicies(properties);
|
||||
} catch (Exception ex) {
|
||||
LOGGER.error("Error occurred while initializing the session manager..", ex);
|
||||
throw ex;
|
||||
|
@ -252,7 +264,7 @@ public class SessionManager extends ManagerBase implements Lifecycle {
|
|||
session = (this.sessionContext.get() != null) ? this.sessionContext.get().getSession() : null;
|
||||
if (session != null) {
|
||||
if (session.isValid()) {
|
||||
save(session, this.sessionPolicy.contains(SessionPolicy.ALWAYS_SAVE_AFTER_REQUEST));
|
||||
save(session, getAlwaysSaveAfterRequest());
|
||||
} else {
|
||||
remove(session);
|
||||
}
|
||||
|
@ -270,7 +282,7 @@ public class SessionManager extends ManagerBase implements Lifecycle {
|
|||
private int getSessionTimeout(Session session) {
|
||||
int timeout = getContextIns().getSessionTimeout() * 60;
|
||||
int sessionTimeout = (session == null) ? 0 : session.getMaxInactiveInterval();
|
||||
return (sessionTimeout < timeout) ? ((timeout < 1800) ? 1800 : timeout) : sessionTimeout;
|
||||
return (sessionTimeout < timeout) ? (Math.max(timeout, 1800)) : sessionTimeout;
|
||||
}
|
||||
|
||||
/** To set values to session context. */
|
||||
|
@ -312,4 +324,45 @@ public class SessionManager extends ManagerBase implements Lifecycle {
|
|||
}
|
||||
throw new RuntimeException("Error occurred while creating container instance");
|
||||
}
|
||||
|
||||
/** To set session persistent policies */
|
||||
private void setSessionPersistentPolicies(Properties properties) {
|
||||
String sessionPolicies = properties.getProperty(SessionConstants.SESSION_PERSISTENT_POLICIES);
|
||||
if (sessionPolicies == null || sessionPolicies.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
sessionPolicies = sessionPolicies.replaceAll("\\s", "");
|
||||
String[] sessionPolicyNames = sessionPolicies.split(",");
|
||||
for (String sessionPolicyName : sessionPolicyNames) {
|
||||
this.sessionPolicy.add(SessionPolicy.fromName(sessionPolicyName));
|
||||
}
|
||||
}
|
||||
|
||||
/** To get redis data cache properties. */
|
||||
private Properties getApplicationProperties() {
|
||||
Properties properties = new Properties();
|
||||
try {
|
||||
String filePath = System.getProperty(SessionConstants.CATALINA_BASE).concat(File.separator)
|
||||
.concat(SessionConstants.CONF).concat(File.separator)
|
||||
.concat(DataCacheConstants.APPLICATION_PROPERTIES_FILE);
|
||||
|
||||
InputStream resourceStream = null;
|
||||
try {
|
||||
resourceStream = (!filePath.isEmpty() && new File(filePath).exists()) ? new FileInputStream(filePath) : null;
|
||||
if (resourceStream == null) {
|
||||
ClassLoader loader = Thread.currentThread().getContextClassLoader();
|
||||
resourceStream = loader.getResourceAsStream(DataCacheConstants.APPLICATION_PROPERTIES_FILE);
|
||||
}
|
||||
properties.load(resourceStream);
|
||||
} finally {
|
||||
if (resourceStream != null) {
|
||||
resourceStream.close();
|
||||
}
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
LOGGER.error("Error while retrieving application properties", ex);
|
||||
}
|
||||
return properties;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,23 +1,23 @@
|
|||
#-- Redis data-cache configuration
|
||||
|
||||
#- redis hosts ex: 127.0.0.1:6379, 127.0.0.2:6379, 127.0.0.2:6380, ....
|
||||
#- redis hosts. ex: 127.0.0.1:6379, 127.0.0.2:6379, 127.0.0.2:6380, ....
|
||||
redis.hosts=127.0.0.1:6379
|
||||
|
||||
#- redis password
|
||||
#- redis password.
|
||||
#redis.password=
|
||||
|
||||
#- set true to enable redis cluster mode (default value: false)
|
||||
#- set true to enable redis cluster mode. (default value: false)
|
||||
redis.cluster.enabled=false
|
||||
|
||||
#- set true to enable redis sentinel mode (default value: false)
|
||||
#- set true to enable redis sentinel mode. (default value: false)
|
||||
redis.sentinel.enabled=false
|
||||
# redis sentinel master name (default value: mymaster)
|
||||
# redis sentinel master name. (default value: mymaster)
|
||||
redis.sentinel.master=mymaster
|
||||
|
||||
#- redis database (default value: 0)
|
||||
#- redis database. (default value: 0)
|
||||
#redis.database=0
|
||||
|
||||
#- redis connection timeout (default value: 2000 ms)
|
||||
#- redis connection timeout. (default value: 2000 ms)
|
||||
#redis.timeout=2000
|
||||
|
||||
#- enable redis and standard session mode. (default value: false)
|
||||
|
@ -26,3 +26,9 @@ redis.sentinel.master=mymaster
|
|||
# 2. Session values are stored in local jvm and redis.
|
||||
# 3. If redis is down/not responding, requests uses jvm stored session values to process user requests. Redis comes back the values will be synced.
|
||||
lb.sticky-session.enabled=false
|
||||
|
||||
#- session persistent policies. (default value: DEFAULT) ex: DEFAULT, SAVE_ON_CHANGE
|
||||
# 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
|
Loading…
Reference in New Issue