diff --git a/pom.xml b/pom.xml
index fab0bec..6156c33 100644
--- a/pom.xml
+++ b/pom.xml
@@ -4,7 +4,7 @@
4.0.0
tomcat-cluster-redis-session-manager
tomcat-cluster-redis-session-manager
- 3.0.3
+ 3.0.4
jar
tomcat-cluster-redis-session-manager
diff --git a/src/main/java/tomcat/request/session/annotation/Property.java b/src/main/java/tomcat/request/session/annotation/Property.java
new file mode 100644
index 0000000..3c452a2
--- /dev/null
+++ b/src/main/java/tomcat/request/session/annotation/Property.java
@@ -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
+ }
+}
diff --git a/src/main/java/tomcat/request/session/SessionConstants.java b/src/main/java/tomcat/request/session/constant/SessionConstants.java
similarity index 76%
rename from src/main/java/tomcat/request/session/SessionConstants.java
rename to src/main/java/tomcat/request/session/constant/SessionConstants.java
index cf1a6dc..0ee190b 100644
--- a/src/main/java/tomcat/request/session/SessionConstants.java
+++ b/src/main/java/tomcat/request/session/constant/SessionConstants.java
@@ -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;
diff --git a/src/main/java/tomcat/request/session/data/cache/DataCacheConstants.java b/src/main/java/tomcat/request/session/data/cache/DataCacheConstants.java
deleted file mode 100644
index 69b9936..0000000
--- a/src/main/java/tomcat/request/session/data/cache/DataCacheConstants.java
+++ /dev/null
@@ -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
- }
-}
diff --git a/src/main/java/tomcat/request/session/data/cache/DataCacheFactory.java b/src/main/java/tomcat/request/session/data/cache/DataCacheFactory.java
index 3e330c0..fe65fa3 100644
--- a/src/main/java/tomcat/request/session/data/cache/DataCacheFactory.java
+++ b/src/main/java/tomcat/request/session/data/cache/DataCacheFactory.java
@@ -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);
}
}
diff --git a/src/main/java/tomcat/request/session/data/cache/impl/StandardDataCache.java b/src/main/java/tomcat/request/session/data/cache/impl/StandardDataCache.java
index 3ba7f62..e56d4ee 100644
--- a/src/main/java/tomcat/request/session/data/cache/impl/StandardDataCache.java
+++ b/src/main/java/tomcat/request/session/data/cache/impl/StandardDataCache.java
@@ -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();
}
diff --git a/src/main/java/tomcat/request/session/data/cache/impl/redis/RedisCache.java b/src/main/java/tomcat/request/session/data/cache/impl/redis/RedisCache.java
index b2c8c25..19e7e76 100644
--- a/src/main/java/tomcat/request/session/data/cache/impl/redis/RedisCache.java
+++ b/src/main/java/tomcat/request/session/data/cache/impl/redis/RedisCache.java
@@ -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) nodes, password, timeout, poolConfig);
+ this.dataCache = new RedisClusterManager((Set) nodes,
+ config.getRedisPassword(),
+ config.getRedisTimeout(),
+ poolConfig);
break;
case SENTINEL:
- String masterName = String.valueOf(DataCacheFactory.getProperty(properties, DataCacheConstants.REDIS_SENTINEL_MASTER));
- dataCache = new RedisSentinelManager((Set) nodes, masterName, password, database, timeout, poolConfig);
+ this.dataCache = new RedisSentinelManager((Set) nodes,
+ config.getRedisSentinelMaster(),
+ config.getRedisPassword(),
+ config.getRedisDatabase(),
+ config.getRedisTimeout(),
+ poolConfig);
break;
default:
- dataCache = new RedisStandardManager(((List) nodes).get(0), Integer.parseInt(((List) nodes).get(1)), password, database, timeout, poolConfig);
+ this.dataCache = new RedisStandardManager(((List) nodes).get(0),
+ Integer.parseInt(((List) 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;
}
diff --git a/src/main/java/tomcat/request/session/data/cache/impl/redis/RedisClusterManager.java b/src/main/java/tomcat/request/session/data/cache/impl/redis/RedisClusterManager.java
index 96b035c..6f2316a 100644
--- a/src/main/java/tomcat/request/session/data/cache/impl/redis/RedisClusterManager.java
+++ b/src/main/java/tomcat/request/session/data/cache/impl/redis/RedisClusterManager.java
@@ -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 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} */
diff --git a/src/main/java/tomcat/request/session/data/cache/impl/redis/RedisManager.java b/src/main/java/tomcat/request/session/data/cache/impl/redis/RedisManager.java
index c9aafb3..9a30bf6 100644
--- a/src/main/java/tomcat/request/session/data/cache/impl/redis/RedisManager.java
+++ b/src/main/java/tomcat/request/session/data/cache/impl/redis/RedisManager.java
@@ -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 pool;
- private final long failiureWaitTime;
+ private static final String REDIS_CONN_FAILED_RETRY_MSG = "Jedis connection failed, retrying...";
- RedisManager(Pool pool, long failiureWaitTime) {
+ private final Pool pool;
+ private final long failureWaitTime;
+
+ RedisManager(Pool 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();
}
diff --git a/src/main/java/tomcat/request/session/data/cache/impl/redis/RedisSentinelManager.java b/src/main/java/tomcat/request/session/data/cache/impl/redis/RedisSentinelManager.java
index 92e024b..d0f45f7 100644
--- a/src/main/java/tomcat/request/session/data/cache/impl/redis/RedisSentinelManager.java
+++ b/src/main/java/tomcat/request/session/data/cache/impl/redis/RedisSentinelManager.java
@@ -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 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);
}
}
diff --git a/src/main/java/tomcat/request/session/data/cache/impl/redis/RedisStandardManager.java b/src/main/java/tomcat/request/session/data/cache/impl/redis/RedisStandardManager.java
index 911c9b2..62eecb7 100644
--- a/src/main/java/tomcat/request/session/data/cache/impl/redis/RedisStandardManager.java
+++ b/src/main/java/tomcat/request/session/data/cache/impl/redis/RedisStandardManager.java
@@ -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);
}
}
diff --git a/src/main/java/tomcat/request/session/model/Config.java b/src/main/java/tomcat/request/session/model/Config.java
new file mode 100644
index 0000000..f731394
--- /dev/null
+++ b/src/main/java/tomcat/request/session/model/Config.java
@@ -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;
+ }
+}
diff --git a/src/main/java/tomcat/request/session/Session.java b/src/main/java/tomcat/request/session/model/Session.java
similarity index 99%
rename from src/main/java/tomcat/request/session/Session.java
rename to src/main/java/tomcat/request/session/model/Session.java
index 4fe87c8..6f4235e 100644
--- a/src/main/java/tomcat/request/session/Session.java
+++ b/src/main/java/tomcat/request/session/model/Session.java
@@ -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 {
diff --git a/src/main/java/tomcat/request/session/SessionContext.java b/src/main/java/tomcat/request/session/model/SessionContext.java
similarity index 96%
rename from src/main/java/tomcat/request/session/SessionContext.java
rename to src/main/java/tomcat/request/session/model/SessionContext.java
index 21feb07..502a73c 100644
--- a/src/main/java/tomcat/request/session/SessionContext.java
+++ b/src/main/java/tomcat/request/session/model/SessionContext.java
@@ -1,4 +1,4 @@
-package tomcat.request.session;
+package tomcat.request.session.model;
/** author: Ranjith Manickam @ 12 Jul' 2018 */
public class SessionContext {
diff --git a/src/main/java/tomcat/request/session/SessionMetadata.java b/src/main/java/tomcat/request/session/model/SessionMetadata.java
similarity index 97%
rename from src/main/java/tomcat/request/session/SessionMetadata.java
rename to src/main/java/tomcat/request/session/model/SessionMetadata.java
index 7559f30..b1cdfdd 100644
--- a/src/main/java/tomcat/request/session/SessionMetadata.java
+++ b/src/main/java/tomcat/request/session/model/SessionMetadata.java
@@ -1,4 +1,4 @@
-package tomcat.request.session;
+package tomcat.request.session.model;
import java.io.IOException;
import java.io.ObjectInputStream;
diff --git a/src/main/java/tomcat/request/session/redis/SessionHandlerValve.java b/src/main/java/tomcat/request/session/redis/SessionHandlerValve.java
index 782074d..aa891bc 100644
--- a/src/main/java/tomcat/request/session/redis/SessionHandlerValve.java
+++ b/src/main/java/tomcat/request/session/redis/SessionHandlerValve.java
@@ -31,7 +31,7 @@ public class SessionHandlerValve extends ValveBase {
LOGGER.error("Error processing request", ex);
throw new BackendException();
} finally {
- manager.afterRequest();
+ this.manager.afterRequest();
}
}
}
diff --git a/src/main/java/tomcat/request/session/redis/SessionManager.java b/src/main/java/tomcat/request/session/redis/SessionManager.java
index 90793d7..faf9bec 100644
--- a/src/main/java/tomcat/request/session/redis/SessionManager.java
+++ b/src/main/java/tomcat/request/session/redis/SessionManager.java
@@ -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;
- }
}
diff --git a/src/main/java/tomcat/request/session/util/ConfigUtil.java b/src/main/java/tomcat/request/session/util/ConfigUtil.java
new file mode 100644
index 0000000..b2ae4ad
--- /dev/null
+++ b/src/main/java/tomcat/request/session/util/ConfigUtil.java
@@ -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;
+ }
+}
diff --git a/src/main/java/tomcat/request/session/SerializationUtil.java b/src/main/java/tomcat/request/session/util/SerializationUtil.java
similarity index 95%
rename from src/main/java/tomcat/request/session/SerializationUtil.java
rename to src/main/java/tomcat/request/session/util/SerializationUtil.java
index 33d3612..223624c 100644
--- a/src/main/java/tomcat/request/session/SerializationUtil.java
+++ b/src/main/java/tomcat/request/session/util/SerializationUtil.java
@@ -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;