application config system property support changes
parent
b73c1b78c2
commit
f45e1b23a9
2
pom.xml
2
pom.xml
|
@ -4,7 +4,7 @@
|
|||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>tomcat-cluster-redis-session-manager</groupId>
|
||||
<artifactId>tomcat-cluster-redis-session-manager</artifactId>
|
||||
<version>3.0.3</version>
|
||||
<version>3.0.4</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>tomcat-cluster-redis-session-manager</name>
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
package tomcat.request.session.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/** author: Ranjith Manickam @ 5 Feb' 2020 */
|
||||
@Target(ElementType.FIELD)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface Property {
|
||||
String name() default "";
|
||||
|
||||
String defaultValue() default "";
|
||||
|
||||
PropertyType type() default PropertyType.STRING;
|
||||
|
||||
enum PropertyType {
|
||||
STRING,
|
||||
BOOLEAN,
|
||||
INTEGER,
|
||||
LONG
|
||||
}
|
||||
}
|
|
@ -1,11 +1,8 @@
|
|||
package tomcat.request.session;
|
||||
package tomcat.request.session.constant;
|
||||
|
||||
/** author: Ranjith Manickam @ 12 Jul' 2018 */
|
||||
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,40 +0,0 @@
|
|||
package tomcat.request.session.data.cache;
|
||||
|
||||
/** author: Ranjith Manickam @ 3 Dec' 2018 */
|
||||
public interface DataCacheConstants {
|
||||
|
||||
// redis properties file name
|
||||
String APPLICATION_PROPERTIES_FILE = "redis-data-cache.properties";
|
||||
|
||||
// redis properties
|
||||
String REDIS_HOSTS = "redis.hosts";
|
||||
String REDIS_CLUSTER_ENABLED = "redis.cluster.enabled:false";
|
||||
String REDIS_SENTINEL_ENABLED = "redis.sentinel.enabled:false";
|
||||
String LB_STICKY_SESSION_ENABLED = "lb.sticky-session.enabled:false";
|
||||
|
||||
String REDIS_MAX_ACTIVE = "redis.max.active:10";
|
||||
String REDIS_TEST_ONBORROW = "redis.test.onBorrow:true";
|
||||
String REDIS_TEST_ONRETURN = "redis.test.onReturn:true";
|
||||
String REDIS_MAX_IDLE = "redis.max.idle:5";
|
||||
String REDIS_MIN_IDLE = "redis.min.idle:1";
|
||||
String REDIS_TEST_WHILEIDLE = "redis.test.whileIdle:true";
|
||||
String REDIS_TEST_NUMPEREVICTION = "redis.test.numPerEviction:10";
|
||||
String REDIS_TIME_BETWEENEVICTION = "redis.time.betweenEviction:60000";
|
||||
|
||||
String REDIS_PASSWORD = "redis.password";
|
||||
String REDIS_DATABASE = "redis.database:0";
|
||||
String REDIS_TIMEOUT = "redis.timeout:2000";
|
||||
|
||||
String REDIS_SENTINEL_MASTER = "redis.sentinel.master:mymaster";
|
||||
|
||||
String REDIS_CONN_FAILED_RETRY_MSG = "Jedis connection failed, retrying...";
|
||||
|
||||
String SESSION_EXPIRY_JOB_INTERVAL = "redis.session.expiry.job.interval:60";
|
||||
String SESSION_DATA_SYNC_JOB_INTERVAL = "redis.session.data-sync.job.interval:10";
|
||||
|
||||
enum RedisConfigType {
|
||||
DEFAULT,
|
||||
SENTINEL,
|
||||
CLUSTER
|
||||
}
|
||||
}
|
|
@ -2,49 +2,24 @@ package tomcat.request.session.data.cache;
|
|||
|
||||
import tomcat.request.session.data.cache.impl.StandardDataCache;
|
||||
import tomcat.request.session.data.cache.impl.redis.RedisCache;
|
||||
|
||||
import java.util.Properties;
|
||||
import tomcat.request.session.model.Config;
|
||||
|
||||
/** author: Ranjith Manickam @ 3 Dec' 2018 */
|
||||
public class DataCacheFactory {
|
||||
|
||||
private final Properties properties;
|
||||
private final Config config;
|
||||
private final int sessionExpiryTime;
|
||||
|
||||
public DataCacheFactory(Properties properties, int sessionExpiryTime) {
|
||||
this.properties = properties;
|
||||
public DataCacheFactory(Config config, int sessionExpiryTime) {
|
||||
this.config = config;
|
||||
this.sessionExpiryTime = sessionExpiryTime;
|
||||
}
|
||||
|
||||
/** To get data cache. */
|
||||
public DataCache getDataCache() {
|
||||
if (Boolean.parseBoolean(getProperty(this.properties, DataCacheConstants.LB_STICKY_SESSION_ENABLED))) {
|
||||
return new StandardDataCache(this.properties, this.sessionExpiryTime);
|
||||
if (this.config.getLbStickySessionEnabled()) {
|
||||
return new StandardDataCache(this.config, this.sessionExpiryTime);
|
||||
}
|
||||
return new RedisCache(this.properties);
|
||||
}
|
||||
|
||||
/**
|
||||
* To get property with the specified key in this properties list.
|
||||
*
|
||||
* @param properties - properties list.
|
||||
* @param key - search key.
|
||||
* @return - Returns the property value.
|
||||
*/
|
||||
public static String getProperty(Properties properties, String key) {
|
||||
return getProperty(properties, key, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* To get property with the specified key in this properties list.
|
||||
*
|
||||
* @param properties - properties list.
|
||||
* @param key - search key.
|
||||
* @param defaultValue - default value.
|
||||
* @return - - Returns the property value.
|
||||
*/
|
||||
public static String getProperty(Properties properties, String key, String defaultValue) {
|
||||
String[] keyValue = key.split(":");
|
||||
return properties.getProperty(keyValue[0], (keyValue.length > 1 && defaultValue == null) ? keyValue[1] : defaultValue);
|
||||
return new RedisCache(this.config);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,14 +3,12 @@ package tomcat.request.session.data.cache.impl;
|
|||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
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.data.cache.impl.redis.RedisCache;
|
||||
import tomcat.request.session.model.Config;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.Executors;
|
||||
|
@ -32,15 +30,15 @@ public class StandardDataCache extends RedisCache {
|
|||
private final Executor expiryJobExecutor;
|
||||
private final Executor dataSyncJobExecutor;
|
||||
|
||||
public StandardDataCache(Properties properties, int sessionExpiryTime) {
|
||||
super(properties);
|
||||
public StandardDataCache(Config config, int sessionExpiryTime) {
|
||||
super(config);
|
||||
this.sessionExpiryTime = sessionExpiryTime;
|
||||
this.sessionData = new ConcurrentHashMap<>();
|
||||
this.expiryJob = new Date().getTime();
|
||||
this.dataSyncJob = new Date().getTime();
|
||||
this.processDataSync = false;
|
||||
this.expiryJobTriggerInterval = TimeUnit.MINUTES.toMillis(Integer.parseInt(DataCacheFactory.getProperty(properties, DataCacheConstants.SESSION_EXPIRY_JOB_INTERVAL)));
|
||||
this.dataSyncJobTriggerInterval = TimeUnit.MINUTES.toMillis(Integer.parseInt(DataCacheFactory.getProperty(properties, DataCacheConstants.SESSION_DATA_SYNC_JOB_INTERVAL)));
|
||||
this.expiryJobTriggerInterval = TimeUnit.MINUTES.toMillis(config.getRedisSessionExpiryJobInterval());
|
||||
this.dataSyncJobTriggerInterval = TimeUnit.MINUTES.toMillis(config.getRedisSessionDataSyncJobInterval());
|
||||
this.expiryJobExecutor = Executors.newSingleThreadExecutor();
|
||||
this.dataSyncJobExecutor = Executors.newSingleThreadExecutor();
|
||||
}
|
||||
|
|
|
@ -2,17 +2,14 @@ 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.data.cache.DataCache;
|
||||
import tomcat.request.session.data.cache.DataCacheConstants;
|
||||
import tomcat.request.session.data.cache.DataCacheConstants.RedisConfigType;
|
||||
import tomcat.request.session.data.cache.DataCacheFactory;
|
||||
import tomcat.request.session.model.Config;
|
||||
import tomcat.request.session.model.Config.RedisConfigType;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
|
||||
/** author: Ranjith Manickam @ 12 Jul' 2018 */
|
||||
|
@ -20,8 +17,8 @@ public class RedisCache implements DataCache {
|
|||
|
||||
private DataCache dataCache;
|
||||
|
||||
public RedisCache(Properties properties) {
|
||||
initialize(properties);
|
||||
public RedisCache(Config config) {
|
||||
initialize(config);
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
|
@ -54,38 +51,31 @@ public class RedisCache implements DataCache {
|
|||
return dataCache.delete(key);
|
||||
}
|
||||
|
||||
private void initialize(Properties properties) {
|
||||
RedisConfigType configType;
|
||||
if (Boolean.parseBoolean(DataCacheFactory.getProperty(properties, DataCacheConstants.REDIS_CLUSTER_ENABLED))) {
|
||||
configType = RedisConfigType.CLUSTER;
|
||||
} else if (Boolean.parseBoolean(DataCacheFactory.getProperty(properties, DataCacheConstants.REDIS_SENTINEL_ENABLED))) {
|
||||
configType = RedisConfigType.SENTINEL;
|
||||
} else {
|
||||
configType = RedisConfigType.DEFAULT;
|
||||
}
|
||||
|
||||
String hosts = DataCacheFactory.getProperty(properties, DataCacheConstants.REDIS_HOSTS, String.format("%s:%s", Protocol.DEFAULT_HOST, Protocol.DEFAULT_PORT));
|
||||
Collection<?> nodes = getJedisNodes(hosts, configType);
|
||||
|
||||
String password = DataCacheFactory.getProperty(properties, DataCacheConstants.REDIS_PASSWORD);
|
||||
password = (password != null && !password.isEmpty()) ? password : null;
|
||||
|
||||
int database = Integer.parseInt(DataCacheFactory.getProperty(properties, DataCacheConstants.REDIS_DATABASE));
|
||||
|
||||
int timeout = Integer.parseInt(DataCacheFactory.getProperty(properties, DataCacheConstants.REDIS_TIMEOUT));
|
||||
timeout = Math.max(timeout, Protocol.DEFAULT_TIMEOUT);
|
||||
|
||||
JedisPoolConfig poolConfig = getPoolConfig(properties);
|
||||
switch (configType) {
|
||||
private void initialize(Config config) {
|
||||
Collection<?> nodes = getJedisNodes(config.getRedisHosts(), config.getRedisConfigType());
|
||||
JedisPoolConfig poolConfig = getPoolConfig(config);
|
||||
switch (config.getRedisConfigType()) {
|
||||
case CLUSTER:
|
||||
dataCache = new RedisClusterManager((Set<HostAndPort>) nodes, password, timeout, poolConfig);
|
||||
this.dataCache = new RedisClusterManager((Set<HostAndPort>) nodes,
|
||||
config.getRedisPassword(),
|
||||
config.getRedisTimeout(),
|
||||
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,
|
||||
config.getRedisSentinelMaster(),
|
||||
config.getRedisPassword(),
|
||||
config.getRedisDatabase(),
|
||||
config.getRedisTimeout(),
|
||||
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)),
|
||||
config.getRedisPassword(),
|
||||
config.getRedisDatabase(),
|
||||
config.getRedisTimeout(),
|
||||
poolConfig);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -93,34 +83,19 @@ public class RedisCache implements DataCache {
|
|||
/**
|
||||
* To get redis pool config.
|
||||
*
|
||||
* @param properties - Redis data cache properties.
|
||||
* @param config - Application config.
|
||||
* @return - Returns the redis pool config.
|
||||
*/
|
||||
private JedisPoolConfig getPoolConfig(Properties properties) {
|
||||
private JedisPoolConfig getPoolConfig(Config config) {
|
||||
JedisPoolConfig poolConfig = new JedisPoolConfig();
|
||||
int maxActive = Integer.parseInt(DataCacheFactory.getProperty(properties, DataCacheConstants.REDIS_MAX_ACTIVE));
|
||||
poolConfig.setMaxTotal(maxActive);
|
||||
|
||||
boolean testOnBorrow = Boolean.parseBoolean(DataCacheFactory.getProperty(properties, DataCacheConstants.REDIS_TEST_ONBORROW));
|
||||
poolConfig.setTestOnBorrow(testOnBorrow);
|
||||
|
||||
boolean testOnReturn = Boolean.parseBoolean(DataCacheFactory.getProperty(properties, DataCacheConstants.REDIS_TEST_ONRETURN));
|
||||
poolConfig.setTestOnReturn(testOnReturn);
|
||||
|
||||
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));
|
||||
poolConfig.setMinIdle(minIdle);
|
||||
|
||||
boolean testWhileIdle = Boolean.parseBoolean(DataCacheFactory.getProperty(properties, DataCacheConstants.REDIS_TEST_WHILEIDLE));
|
||||
poolConfig.setTestWhileIdle(testWhileIdle);
|
||||
|
||||
int testNumPerEviction = Integer.parseInt(DataCacheFactory.getProperty(properties, DataCacheConstants.REDIS_TEST_NUMPEREVICTION));
|
||||
poolConfig.setNumTestsPerEvictionRun(testNumPerEviction);
|
||||
|
||||
long timeBetweenEviction = Long.parseLong(DataCacheFactory.getProperty(properties, DataCacheConstants.REDIS_TIME_BETWEENEVICTION));
|
||||
poolConfig.setTimeBetweenEvictionRunsMillis(timeBetweenEviction);
|
||||
poolConfig.setMaxTotal(config.getRedisMaxActive());
|
||||
poolConfig.setTestOnBorrow(config.getRedisTestOnBorrow());
|
||||
poolConfig.setTestOnReturn(config.getRedisTestOnReturn());
|
||||
poolConfig.setMaxIdle(config.getRedisMaxIdle());
|
||||
poolConfig.setMinIdle(config.getRedisMinIdle());
|
||||
poolConfig.setTestWhileIdle(config.getRedisTestWhileIdle());
|
||||
poolConfig.setNumTestsPerEvictionRun(config.getRedisTestNumPerEviction());
|
||||
poolConfig.setTimeBetweenEvictionRunsMillis(config.getRedisTimeBetweenEviction());
|
||||
return poolConfig;
|
||||
}
|
||||
|
||||
|
|
|
@ -15,15 +15,15 @@ class RedisClusterManager extends RedisManager {
|
|||
private final JedisCluster cluster;
|
||||
|
||||
private static final int NUM_RETRIES = 30;
|
||||
private static final int DEFAULT_MAX_REDIRECTIONS = 5;
|
||||
private static final long FAILIURE_WAIT_TIME = 4000L;
|
||||
private static final int DEFAULT_MAX_RE_DIRECTIONS = 5;
|
||||
private static final long FAILURE_WAIT_TIME = 4000L;
|
||||
|
||||
RedisClusterManager(Set<HostAndPort> nodes,
|
||||
String password,
|
||||
int timeout,
|
||||
JedisPoolConfig poolConfig) {
|
||||
super(null, FAILIURE_WAIT_TIME);
|
||||
this.cluster = new JedisCluster(nodes, timeout, Protocol.DEFAULT_TIMEOUT, DEFAULT_MAX_REDIRECTIONS, password, poolConfig);
|
||||
super(null, FAILURE_WAIT_TIME);
|
||||
this.cluster = new JedisCluster(nodes, timeout, Protocol.DEFAULT_TIMEOUT, DEFAULT_MAX_RE_DIRECTIONS, password, poolConfig);
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
|
|
|
@ -6,7 +6,6 @@ import redis.clients.jedis.Jedis;
|
|||
import redis.clients.jedis.exceptions.JedisConnectionException;
|
||||
import redis.clients.jedis.util.Pool;
|
||||
import tomcat.request.session.data.cache.DataCache;
|
||||
import tomcat.request.session.data.cache.DataCacheConstants;
|
||||
|
||||
/** author: Ranjith Manickam @ 12 Jul' 2018 */
|
||||
abstract class RedisManager implements DataCache {
|
||||
|
@ -14,12 +13,14 @@ abstract class RedisManager implements DataCache {
|
|||
private static final int NUM_RETRIES = 3;
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(RedisManager.class);
|
||||
|
||||
private final Pool<Jedis> pool;
|
||||
private final long failiureWaitTime;
|
||||
private static final String REDIS_CONN_FAILED_RETRY_MSG = "Jedis connection failed, retrying...";
|
||||
|
||||
RedisManager(Pool<Jedis> pool, long failiureWaitTime) {
|
||||
private final Pool<Jedis> pool;
|
||||
private final long failureWaitTime;
|
||||
|
||||
RedisManager(Pool<Jedis> pool, long failureWaitTime) {
|
||||
this.pool = pool;
|
||||
this.failiureWaitTime = failiureWaitTime;
|
||||
this.failureWaitTime = failureWaitTime;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
|
@ -119,12 +120,12 @@ abstract class RedisManager implements DataCache {
|
|||
* @param ex - jedis exception.
|
||||
*/
|
||||
void handleException(int tries, RuntimeException ex) {
|
||||
LOGGER.error(DataCacheConstants.REDIS_CONN_FAILED_RETRY_MSG + tries);
|
||||
LOGGER.error(REDIS_CONN_FAILED_RETRY_MSG + tries);
|
||||
if (tries == NUM_RETRIES) {
|
||||
throw ex;
|
||||
}
|
||||
try {
|
||||
Thread.sleep(this.failiureWaitTime);
|
||||
Thread.sleep(this.failureWaitTime);
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ import java.util.Set;
|
|||
/** author: Ranjith Manickam @ 3 Dec' 2018 */
|
||||
class RedisSentinelManager extends RedisManager {
|
||||
|
||||
private static final long FAILIURE_WAIT_TIME = 2000L;
|
||||
private static final long FAILURE_WAIT_TIME = 2000L;
|
||||
|
||||
RedisSentinelManager(Set<String> nodes,
|
||||
String masterName,
|
||||
|
@ -16,6 +16,6 @@ class RedisSentinelManager extends RedisManager {
|
|||
int database,
|
||||
int timeout,
|
||||
JedisPoolConfig poolConfig) {
|
||||
super(new JedisSentinelPool(masterName, nodes, poolConfig, timeout, password, database), FAILIURE_WAIT_TIME);
|
||||
super(new JedisSentinelPool(masterName, nodes, poolConfig, timeout, password, database), FAILURE_WAIT_TIME);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@ import redis.clients.jedis.JedisPoolConfig;
|
|||
/** author: Ranjith Manickam @ 12 Jul' 2018 */
|
||||
class RedisStandardManager extends RedisManager {
|
||||
|
||||
private static final long FAILIURE_WAIT_TIME = 2000L;
|
||||
private static final long FAILURE_WAIT_TIME = 2000L;
|
||||
|
||||
RedisStandardManager(String host,
|
||||
int port,
|
||||
|
@ -14,6 +14,6 @@ class RedisStandardManager extends RedisManager {
|
|||
int database,
|
||||
int timeout,
|
||||
JedisPoolConfig poolConfig) {
|
||||
super(new JedisPool(poolConfig, host, port, timeout, password, database), FAILIURE_WAIT_TIME);
|
||||
super(new JedisPool(poolConfig, host, port, timeout, password, database), FAILURE_WAIT_TIME);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,253 @@
|
|||
package tomcat.request.session.model;
|
||||
|
||||
import redis.clients.jedis.Protocol;
|
||||
import tomcat.request.session.annotation.Property;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import static tomcat.request.session.annotation.Property.PropertyType.BOOLEAN;
|
||||
import static tomcat.request.session.annotation.Property.PropertyType.INTEGER;
|
||||
|
||||
/** author: Ranjith Manickam @ 5 Feb' 2020 */
|
||||
public class Config implements Serializable {
|
||||
|
||||
public static final String APPLICATION_PROPERTIES_FILE = "redis-data-cache.properties";
|
||||
|
||||
/** Redis config type. */
|
||||
public enum RedisConfigType {
|
||||
DEFAULT,
|
||||
SENTINEL,
|
||||
CLUSTER
|
||||
}
|
||||
|
||||
@Property(name = "redis.hosts", defaultValue = "127.0.0.1:6379")
|
||||
private String redisHosts;
|
||||
|
||||
@Property(name = "redis.cluster.enabled", type = BOOLEAN, defaultValue = "false")
|
||||
private Boolean redisClusterEnabled;
|
||||
|
||||
@Property(name = "redis.sentinel.enabled", type = BOOLEAN, defaultValue = "false")
|
||||
private Boolean redisSentinelEnabled;
|
||||
|
||||
@Property(name = "lb.sticky-session.enabled", type = BOOLEAN, defaultValue = "false")
|
||||
private Boolean lbStickySessionEnabled;
|
||||
|
||||
@Property(name = "redis.max.active", type = INTEGER, defaultValue = "10")
|
||||
private Integer redisMaxActive;
|
||||
|
||||
@Property(name = "redis.test.onBorrow", type = BOOLEAN, defaultValue = "true")
|
||||
private Boolean redisTestOnBorrow;
|
||||
|
||||
@Property(name = "redis.test.onReturn", type = BOOLEAN, defaultValue = "true")
|
||||
private Boolean redisTestOnReturn;
|
||||
|
||||
@Property(name = "redis.max.idle", type = INTEGER, defaultValue = "5")
|
||||
private Integer redisMaxIdle;
|
||||
|
||||
@Property(name = "redis.min.idle", type = INTEGER, defaultValue = "1")
|
||||
private Integer redisMinIdle;
|
||||
|
||||
@Property(name = "redis.test.whileIdle", type = BOOLEAN, defaultValue = "true")
|
||||
private Boolean redisTestWhileIdle;
|
||||
|
||||
@Property(name = "redis.test.numPerEviction", type = INTEGER, defaultValue = "10")
|
||||
private Integer redisTestNumPerEviction;
|
||||
|
||||
@Property(name = "redis.time.betweenEviction", type = INTEGER, defaultValue = "60000")
|
||||
private Integer redisTimeBetweenEviction;
|
||||
|
||||
@Property(name = "redis.password")
|
||||
private String redisPassword;
|
||||
|
||||
@Property(name = "redis.database", type = INTEGER, defaultValue = "0")
|
||||
private Integer redisDatabase;
|
||||
|
||||
@Property(name = "redis.timeout", type = INTEGER, defaultValue = "2000")
|
||||
private Integer redisTimeout;
|
||||
|
||||
@Property(name = "redis.sentinel.master", defaultValue = "mymaster")
|
||||
private String redisSentinelMaster;
|
||||
|
||||
@Property(name = "redis.session.expiry.job.interval", type = INTEGER, defaultValue = "60")
|
||||
private Integer redisSessionExpiryJobInterval;
|
||||
|
||||
@Property(name = "redis.session.data-sync.job.interval", type = INTEGER, defaultValue = "10")
|
||||
private Integer redisSessionDataSyncJobInterval;
|
||||
|
||||
@Property(name = "session.persistent.policies", defaultValue = "DEFAULT")
|
||||
private String sessionPersistentPolicies;
|
||||
|
||||
public Config() {
|
||||
}
|
||||
|
||||
public Config(String redisHosts,
|
||||
Boolean redisClusterEnabled,
|
||||
Boolean redisSentinelEnabled,
|
||||
Boolean lbStickySessionEnabled,
|
||||
Integer redisMaxActive,
|
||||
Boolean redisTestOnBorrow,
|
||||
Boolean redisTestOnReturn,
|
||||
Integer redisMaxIdle,
|
||||
Integer redisMinIdle,
|
||||
Boolean redisTestWhileIdle,
|
||||
Integer redisTestNumPerEviction,
|
||||
Integer redisTimeBetweenEviction,
|
||||
String redisPassword,
|
||||
Integer redisDatabase,
|
||||
Integer redisTimeout,
|
||||
String redisSentinelMaster,
|
||||
Integer redisSessionExpiryJobInterval,
|
||||
Integer redisSessionDataSyncJobInterval,
|
||||
String sessionPersistentPolicies) {
|
||||
this.redisHosts = redisHosts;
|
||||
this.redisClusterEnabled = redisClusterEnabled;
|
||||
this.redisSentinelEnabled = redisSentinelEnabled;
|
||||
this.lbStickySessionEnabled = lbStickySessionEnabled;
|
||||
this.redisMaxActive = redisMaxActive;
|
||||
this.redisTestOnBorrow = redisTestOnBorrow;
|
||||
this.redisTestOnReturn = redisTestOnReturn;
|
||||
this.redisMaxIdle = redisMaxIdle;
|
||||
this.redisMinIdle = redisMinIdle;
|
||||
this.redisTestWhileIdle = redisTestWhileIdle;
|
||||
this.redisTestNumPerEviction = redisTestNumPerEviction;
|
||||
this.redisTimeBetweenEviction = redisTimeBetweenEviction;
|
||||
this.redisPassword = redisPassword;
|
||||
this.redisDatabase = redisDatabase;
|
||||
this.redisTimeout = redisTimeout;
|
||||
this.redisSentinelMaster = redisSentinelMaster;
|
||||
this.redisSessionExpiryJobInterval = redisSessionExpiryJobInterval;
|
||||
this.redisSessionDataSyncJobInterval = redisSessionDataSyncJobInterval;
|
||||
this.sessionPersistentPolicies = sessionPersistentPolicies;
|
||||
}
|
||||
|
||||
/** To get 'redis.hosts' value. */
|
||||
public String getRedisHosts() {
|
||||
return redisHosts;
|
||||
}
|
||||
|
||||
/** To get 'redis.cluster.enabled' value. */
|
||||
public Boolean getRedisClusterEnabled() {
|
||||
return redisClusterEnabled;
|
||||
}
|
||||
|
||||
/** To get 'redis.sentinel.enabled' value. */
|
||||
public Boolean getRedisSentinelEnabled() {
|
||||
return redisSentinelEnabled;
|
||||
}
|
||||
|
||||
/** To get 'lb.sticky-session.enabled' value. */
|
||||
public Boolean getLbStickySessionEnabled() {
|
||||
return lbStickySessionEnabled;
|
||||
}
|
||||
|
||||
/** To get 'redis.max.active' value. */
|
||||
public Integer getRedisMaxActive() {
|
||||
return redisMaxActive;
|
||||
}
|
||||
|
||||
/** To get 'redis.test.onBorrow' value. */
|
||||
public Boolean getRedisTestOnBorrow() {
|
||||
return redisTestOnBorrow;
|
||||
}
|
||||
|
||||
/** To get 'redis.test.onReturn' value. */
|
||||
public Boolean getRedisTestOnReturn() {
|
||||
return redisTestOnReturn;
|
||||
}
|
||||
|
||||
/** To get 'redis.max.idle' value. */
|
||||
public Integer getRedisMaxIdle() {
|
||||
return redisMaxIdle;
|
||||
}
|
||||
|
||||
/** To get 'redis.min.idle' value. */
|
||||
public Integer getRedisMinIdle() {
|
||||
return redisMinIdle;
|
||||
}
|
||||
|
||||
/** To get 'redis.test.whileIdle' value. */
|
||||
public Boolean getRedisTestWhileIdle() {
|
||||
return redisTestWhileIdle;
|
||||
}
|
||||
|
||||
/** To get 'redis.test.numPerEviction' value. */
|
||||
public Integer getRedisTestNumPerEviction() {
|
||||
return redisTestNumPerEviction;
|
||||
}
|
||||
|
||||
/** To get 'redis.time.betweenEviction' value. */
|
||||
public Integer getRedisTimeBetweenEviction() {
|
||||
return redisTimeBetweenEviction;
|
||||
}
|
||||
|
||||
/** To get 'redis.password' value. */
|
||||
public String getRedisPassword() {
|
||||
return (redisPassword == null || redisPassword.isEmpty()) ? null : redisPassword;
|
||||
}
|
||||
|
||||
/** To get 'redis.database' value. */
|
||||
public Integer getRedisDatabase() {
|
||||
return redisDatabase;
|
||||
}
|
||||
|
||||
/** To get 'redis.timeout' value. */
|
||||
public Integer getRedisTimeout() {
|
||||
return Math.max(redisTimeout, Protocol.DEFAULT_TIMEOUT);
|
||||
}
|
||||
|
||||
/** To get 'redis.sentinel.master' value. */
|
||||
public String getRedisSentinelMaster() {
|
||||
return redisSentinelMaster;
|
||||
}
|
||||
|
||||
/** To get 'redis.session.expiry.job.interval' value. */
|
||||
public Integer getRedisSessionExpiryJobInterval() {
|
||||
return redisSessionExpiryJobInterval;
|
||||
}
|
||||
|
||||
/** To get 'redis.session.data-sync.job.interval' value. */
|
||||
public Integer getRedisSessionDataSyncJobInterval() {
|
||||
return redisSessionDataSyncJobInterval;
|
||||
}
|
||||
|
||||
/** To get 'session.persistent.policies' value */
|
||||
public String getSessionPersistentPolicies() {
|
||||
return sessionPersistentPolicies;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Config{" +
|
||||
"redisHosts='" + redisHosts + '\'' +
|
||||
", redisClusterEnabled=" + redisClusterEnabled +
|
||||
", redisSentinelEnabled=" + redisSentinelEnabled +
|
||||
", lbStickySessionEnabled=" + lbStickySessionEnabled +
|
||||
", redisMaxActive=" + redisMaxActive +
|
||||
", redisTestOnBorrow=" + redisTestOnBorrow +
|
||||
", redisTestOnReturn=" + redisTestOnReturn +
|
||||
", redisMaxIdle=" + redisMaxIdle +
|
||||
", redisMinIdle=" + redisMinIdle +
|
||||
", redisTestWhileIdle=" + redisTestWhileIdle +
|
||||
", redisTestNumPerEviction=" + redisTestNumPerEviction +
|
||||
", redisTimeBetweenEviction=" + redisTimeBetweenEviction +
|
||||
", redisPassword='" + redisPassword + '\'' +
|
||||
", redisDatabase=" + redisDatabase +
|
||||
", redisTimeout=" + redisTimeout +
|
||||
", redisSentinelMaster='" + redisSentinelMaster + '\'' +
|
||||
", redisSessionExpiryJobInterval=" + redisSessionExpiryJobInterval +
|
||||
", redisSessionDataSyncJobInterval=" + redisSessionDataSyncJobInterval +
|
||||
", sessionPersistentPolicies='" + sessionPersistentPolicies + '\'' +
|
||||
'}';
|
||||
}
|
||||
|
||||
/** To get redis config type. */
|
||||
public RedisConfigType getRedisConfigType() {
|
||||
if (this.getRedisClusterEnabled()) {
|
||||
return RedisConfigType.CLUSTER;
|
||||
} else if (this.getRedisSentinelEnabled()) {
|
||||
return RedisConfigType.SENTINEL;
|
||||
}
|
||||
return RedisConfigType.DEFAULT;
|
||||
}
|
||||
}
|
|
@ -1,4 +1,8 @@
|
|||
package tomcat.request.session;
|
||||
package tomcat.request.session.model;
|
||||
|
||||
import org.apache.catalina.Manager;
|
||||
import org.apache.catalina.session.StandardSession;
|
||||
import tomcat.request.session.redis.SessionManager;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
|
@ -8,11 +12,6 @@ import java.util.Enumeration;
|
|||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.catalina.Manager;
|
||||
import org.apache.catalina.session.StandardSession;
|
||||
|
||||
import tomcat.request.session.redis.SessionManager;
|
||||
|
||||
/** author: Ranjith Manickam @ 12 Jul' 2018 */
|
||||
public class Session extends StandardSession {
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package tomcat.request.session;
|
||||
package tomcat.request.session.model;
|
||||
|
||||
/** author: Ranjith Manickam @ 12 Jul' 2018 */
|
||||
public class SessionContext {
|
|
@ -1,4 +1,4 @@
|
|||
package tomcat.request.session;
|
||||
package tomcat.request.session.model;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
|
@ -31,7 +31,7 @@ public class SessionHandlerValve extends ValveBase {
|
|||
LOGGER.error("Error processing request", ex);
|
||||
throw new BackendException();
|
||||
} finally {
|
||||
manager.afterRequest();
|
||||
this.manager.afterRequest();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,24 +9,21 @@ import org.apache.catalina.Valve;
|
|||
import org.apache.catalina.session.ManagerBase;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import tomcat.request.session.SerializationUtil;
|
||||
import tomcat.request.session.Session;
|
||||
import tomcat.request.session.SessionConstants;
|
||||
import tomcat.request.session.SessionConstants.SessionPolicy;
|
||||
import tomcat.request.session.SessionContext;
|
||||
import tomcat.request.session.SessionMetadata;
|
||||
import tomcat.request.session.constant.SessionConstants;
|
||||
import tomcat.request.session.constant.SessionConstants.SessionPolicy;
|
||||
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.model.Config;
|
||||
import tomcat.request.session.model.Session;
|
||||
import tomcat.request.session.model.SessionContext;
|
||||
import tomcat.request.session.model.SessionMetadata;
|
||||
import tomcat.request.session.util.ConfigUtil;
|
||||
import tomcat.request.session.util.SerializationUtil;
|
||||
|
||||
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 */
|
||||
|
@ -211,15 +208,15 @@ public class SessionManager extends ManagerBase implements Lifecycle {
|
|||
/** To initialize the session manager. */
|
||||
private void initialize() {
|
||||
try {
|
||||
Properties properties = getApplicationProperties();
|
||||
this.dataCache = new DataCacheFactory(properties, getSessionTimeout(null)).getDataCache();
|
||||
Config config = ConfigUtil.getConfig();
|
||||
this.dataCache = new DataCacheFactory(config, 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);
|
||||
setSessionPersistentPolicies(config);
|
||||
} catch (Exception ex) {
|
||||
LOGGER.error("Error occurred while initializing the session manager..", ex);
|
||||
throw ex;
|
||||
|
@ -326,8 +323,8 @@ public class SessionManager extends ManagerBase implements Lifecycle {
|
|||
}
|
||||
|
||||
/** To set session persistent policies */
|
||||
private void setSessionPersistentPolicies(Properties properties) {
|
||||
String sessionPolicies = properties.getProperty(SessionConstants.SESSION_PERSISTENT_POLICIES);
|
||||
private void setSessionPersistentPolicies(Config config) {
|
||||
String sessionPolicies = config.getSessionPersistentPolicies();
|
||||
if (sessionPolicies == null || sessionPolicies.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
@ -338,31 +335,4 @@ public class SessionManager extends ManagerBase implements Lifecycle {
|
|||
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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,154 @@
|
|||
package tomcat.request.session.util;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import tomcat.request.session.annotation.Property;
|
||||
import tomcat.request.session.model.Config;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Properties;
|
||||
|
||||
/** author: Ranjith Manickam @ 5 Feb' 2020 */
|
||||
public class ConfigUtil {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(ConfigUtil.class);
|
||||
|
||||
private static final String CONF = "conf";
|
||||
private static final String CATALINA_BASE = "catalina.base";
|
||||
|
||||
/** To get application config. */
|
||||
public static Config getConfig() {
|
||||
Properties properties = getApplicationProperties();
|
||||
Config config = new Config();
|
||||
|
||||
for (Field field : Config.class.getDeclaredFields()) {
|
||||
Property property = field.getAnnotation(Property.class);
|
||||
if (property == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
String propertyName = property.name();
|
||||
Property.PropertyType propertyType = property.type();
|
||||
|
||||
if (propertyName.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
String value = properties.getProperty(propertyName);
|
||||
if (isSystemProperty(value)) {
|
||||
value = getSystemProperty(value);
|
||||
}
|
||||
|
||||
if (value == null || value.isEmpty()) {
|
||||
value = property.defaultValue();
|
||||
|
||||
if (value.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
field.setAccessible(true);
|
||||
try {
|
||||
switch (propertyType) {
|
||||
case BOOLEAN:
|
||||
field.set(config, Boolean.parseBoolean(value));
|
||||
break;
|
||||
case INTEGER:
|
||||
field.set(config, Integer.parseInt(value));
|
||||
break;
|
||||
case LONG:
|
||||
field.set(config, Long.parseLong(value));
|
||||
break;
|
||||
case STRING:
|
||||
default:
|
||||
field.set(config, value);
|
||||
break;
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
LOGGER.error("Error while initializing application properties", ex);
|
||||
}
|
||||
}
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
/** To get redis data cache properties. */
|
||||
private static Properties getApplicationProperties() {
|
||||
Properties properties = new Properties();
|
||||
try {
|
||||
String filePath = System.getProperty(CATALINA_BASE)
|
||||
.concat(File.separator)
|
||||
.concat(CONF).concat(File.separator)
|
||||
.concat(Config.APPLICATION_PROPERTIES_FILE);
|
||||
|
||||
InputStream resourceStream = null;
|
||||
try {
|
||||
resourceStream = (!filePath.isEmpty() && new File(filePath).exists()) ? new FileInputStream(filePath) : null;
|
||||
if (resourceStream == null) {
|
||||
LOGGER.info("Initializing tomcat redis session manager with default properties");
|
||||
ClassLoader loader = Thread.currentThread().getContextClassLoader();
|
||||
resourceStream = loader.getResourceAsStream(Config.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;
|
||||
}
|
||||
|
||||
/**
|
||||
* To get property with the specified key from system property.
|
||||
*
|
||||
* @param key - search key.
|
||||
* @return - Returns the system property value.
|
||||
*/
|
||||
private static String getSystemProperty(String key) {
|
||||
int fromIndex = 0;
|
||||
|
||||
while (true) {
|
||||
int beginIndex = key.indexOf("${", fromIndex);
|
||||
int endIndex = key.indexOf("}", fromIndex);
|
||||
|
||||
if (beginIndex < 0 || endIndex < 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
String expression = key.substring(beginIndex + 2, endIndex);
|
||||
String value = System.getProperty(expression);
|
||||
|
||||
if (value == null || value.isEmpty()) {
|
||||
fromIndex = endIndex + 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
key = key.replace(String.format("${%s}", expression), value);
|
||||
}
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
/**
|
||||
* To check if the value is from system property.
|
||||
*
|
||||
* @param key - search key.
|
||||
* @return - Returns true if the key start with '${' and ends with '}'.
|
||||
*/
|
||||
private static boolean isSystemProperty(String key) {
|
||||
if (key == null || key.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int beginIndex = key.indexOf("${");
|
||||
int endIndex = key.indexOf("}");
|
||||
return beginIndex >= 0 && endIndex >= 0 && beginIndex < endIndex;
|
||||
}
|
||||
}
|
|
@ -1,6 +1,8 @@
|
|||
package tomcat.request.session;
|
||||
package tomcat.request.session.util;
|
||||
|
||||
import org.apache.catalina.util.CustomObjectInputStream;
|
||||
import tomcat.request.session.model.Session;
|
||||
import tomcat.request.session.model.SessionMetadata;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.BufferedOutputStream;
|
Loading…
Reference in New Issue