diff --git a/pom.xml b/pom.xml
index 7090f49..7cdb108 100644
--- a/pom.xml
+++ b/pom.xml
@@ -1,68 +1,82 @@
- 4.0.0
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ 4.0.0
- tomcat-cluster-redis-session-manager
- tomcat-cluster-redis-session-manager
- 2.0.5
- jar
+ tomcat-cluster-redis-session-manager
+ tomcat-cluster-redis-session-manager
+ 2.0.5
+ jar
- tomcat-cluster-redis-session-manager
- http://maven.apache.org
+ tomcat-cluster-redis-session-manager
+ http://maven.apache.org
-
- UTF-8
- UTF-8
- 1.7
-
+
+ UTF-8
+ UTF-8
+ 1.7
-
-
- redis.clients
- jedis
- 2.9.0
-
-
- org.apache.commons
- commons-pool2
- 2.4.2
-
-
- commons-logging
- commons-logging
- 1.2
-
+ 2.9.0
+ 2.4.2
+ 1.2
-
-
-
-
+ 3.6.1
+ 1.7
+ ${source-java.version}
-
-
-
- org.apache.maven.plugins
- maven-compiler-plugin
- 3.6.1
-
- 1.7
- 1.7
-
-
-
-
+
+ apache-tomcat-8.5.32
+ apache-tomcat-8.5.32
+ apache-tomcat-8.5.32
+
+
+
+
+
+ redis.clients
+ jedis
+ ${jedis.version}
+
+
+ org.apache.commons
+ commons-pool2
+ ${commons-pool2.version}
+
+
+ commons-logging
+ commons-logging
+ ${commons-logging.version}
+
+
+
+
+ apache-tomcat
+ catalina
+ ${tomcat-catalina.version}
+
+
+ apache-tomcat
+ servlet-api
+ ${tomcat-servlet-api.version}
+
+
+ apache-tomcat
+ tomcat-api
+ ${tomcat-api.version}
+
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+ ${maven-compiler.version}
+
+ ${source-java.version}
+ ${target-java.version}
+
+
+
+
diff --git a/src/main/java/tomcat/request/session/SerializationUtil.java b/src/main/java/tomcat/request/session/SerializationUtil.java
index 48c2557..2d7fd4c 100644
--- a/src/main/java/tomcat/request/session/SerializationUtil.java
+++ b/src/main/java/tomcat/request/session/SerializationUtil.java
@@ -1,5 +1,7 @@
package tomcat.request.session;
+import org.apache.catalina.util.CustomObjectInputStream;
+
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
@@ -11,81 +13,66 @@ import java.security.MessageDigest;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
-import org.apache.catalina.util.CustomObjectInputStream;
-/**
- * Tomcat clustering with Redis data-cache implementation.
- *
- * Session serialization utility.
- *
- * @author Ranjith Manickam
- * @since 2.0
- */
+/** author: Ranjith Manickam @ 12 Jul' 2018 */
public class SerializationUtil {
- private ClassLoader loader;
+ private ClassLoader loader;
- /**
- * To set class loader
- */
- public void setClassLoader(ClassLoader loader) {
- this.loader = loader;
- }
-
- /**
- * To get session attributes hash code
- */
- public byte[] getSessionAttributesHashCode(Session session) throws IOException {
- byte[] serialized;
- Map attributes = new HashMap<>();
-
- for (Enumeration enumerator = session.getAttributeNames();
- enumerator.hasMoreElements(); ) {
- String key = enumerator.nextElement();
- attributes.put(key, session.getAttribute(key));
+ /** To set class loader. */
+ public void setClassLoader(ClassLoader loader) {
+ this.loader = loader;
}
- try (ByteArrayOutputStream bos = new ByteArrayOutputStream();
- ObjectOutputStream oos = new ObjectOutputStream(new BufferedOutputStream(bos))) {
- oos.writeUnshared(attributes);
- oos.flush();
- serialized = bos.toByteArray();
+ /** To get session attributes hash code. */
+ public byte[] getSessionAttributesHashCode(Session session) throws IOException {
+ byte[] serialized;
+ Map attributes = new HashMap<>();
+
+ for (Enumeration enumerator = session.getAttributeNames();
+ enumerator.hasMoreElements(); ) {
+ String key = enumerator.nextElement();
+ attributes.put(key, session.getAttribute(key));
+ }
+
+ try (ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ ObjectOutputStream oos = new ObjectOutputStream(new BufferedOutputStream(bos))) {
+ oos.writeUnshared(attributes);
+ oos.flush();
+ serialized = bos.toByteArray();
+ }
+
+ MessageDigest digester;
+ try {
+ digester = MessageDigest.getInstance("MD5");
+ } catch (Exception ex) {
+ throw new RuntimeException("Unable to get MessageDigest instance for MD5", ex);
+ }
+ return digester.digest(serialized);
}
- MessageDigest digester;
- try {
- digester = MessageDigest.getInstance("MD5");
- } catch (Exception ex) {
- throw new RuntimeException("Unable to get MessageDigest instance for MD5", ex);
+ /** To serialize session object. */
+ public byte[] serializeSessionData(Session session, SessionMetadata metadata) throws IOException {
+ byte[] serialized;
+ try (ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ ObjectOutputStream oos = new ObjectOutputStream(new BufferedOutputStream(bos))) {
+ oos.writeObject(metadata);
+ session.writeObjectData(oos);
+ oos.flush();
+ serialized = bos.toByteArray();
+ }
+ return serialized;
}
- return digester.digest(serialized);
- }
- /**
- * To serialize session object
- */
- public byte[] serializeSessionData(Session session, SessionMetadata metadata) throws IOException {
- byte[] serialized;
- try (ByteArrayOutputStream bos = new ByteArrayOutputStream();
- ObjectOutputStream oos = new ObjectOutputStream(new BufferedOutputStream(bos))) {
- oos.writeObject(metadata);
- session.writeObjectData(oos);
- oos.flush();
- serialized = bos.toByteArray();
+ /** To de-serialize session object. */
+ public void deserializeSessionData(byte[] data, Session session, SessionMetadata metadata)
+ throws IOException, ClassNotFoundException {
+ try (BufferedInputStream bis = new BufferedInputStream(new ByteArrayInputStream(data));
+ ObjectInputStream ois = new CustomObjectInputStream(bis, this.loader)) {
+ SessionMetadata serializedMetadata = (SessionMetadata) ois.readObject();
+ metadata.copyFieldsFrom(serializedMetadata);
+ session.readObjectData(ois);
+ }
}
- return serialized;
- }
- /**
- * To de-serialize session object
- */
- public void deserializeSessionData(byte[] data, Session session, SessionMetadata metadata)
- throws IOException, ClassNotFoundException {
- try (BufferedInputStream bis = new BufferedInputStream(new ByteArrayInputStream(data));
- ObjectInputStream ois = new CustomObjectInputStream(bis, this.loader)) {
- SessionMetadata serializedMetadata = (SessionMetadata) ois.readObject();
- metadata.copyFieldsFrom(serializedMetadata);
- session.readObjectData(ois);
- }
- }
-}
\ No newline at end of file
+}
diff --git a/src/main/java/tomcat/request/session/Session.java b/src/main/java/tomcat/request/session/Session.java
index 55f71b2..cd6f7bb 100644
--- a/src/main/java/tomcat/request/session/Session.java
+++ b/src/main/java/tomcat/request/session/Session.java
@@ -13,147 +13,126 @@ import org.apache.catalina.session.StandardSession;
import tomcat.request.session.redis.SessionManager;
-/**
- * Tomcat clustering with Redis data-cache implementation.
- *
- * This class is uses to store and retrieve the HTTP request session objects.
- *
- * @author Ranjith Manickam
- * @since 2.0
- */
+/** author: Ranjith Manickam @ 12 Jul' 2018 */
public class Session extends StandardSession {
- private static final long serialVersionUID = -6056744304016869278L;
+ private static final long serialVersionUID = -6056744304016869278L;
- protected Boolean dirty;
+ protected Boolean dirty;
+ protected Map changedAttributes;
- protected Map changedAttributes;
+ protected static Boolean manualDirtyTrackingSupportEnabled = false;
+ protected static String manualDirtyTrackingAttributeKey = "__changed__";
- protected static Boolean manualDirtyTrackingSupportEnabled = false;
-
- protected static String manualDirtyTrackingAttributeKey = "__changed__";
-
- public Session(Manager manager) {
- super(manager);
- resetDirtyTracking();
- }
-
- public void resetDirtyTracking() {
- this.changedAttributes = new HashMap<>();
- this.dirty = false;
- }
-
- public static void setManualDirtyTrackingSupportEnabled(boolean enabled) {
- manualDirtyTrackingSupportEnabled = enabled;
- }
-
- public static void setManualDirtyTrackingAttributeKey(String key) {
- manualDirtyTrackingAttributeKey = key;
- }
-
- public Boolean isDirty() {
- return this.dirty || !this.changedAttributes.isEmpty();
- }
-
- public Map getChangedAttributes() {
- return this.changedAttributes;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void setId(String id) {
- this.id = id;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void setAttribute(String key, Object value) {
- if (manualDirtyTrackingSupportEnabled && manualDirtyTrackingAttributeKey.equals(key)) {
- this.dirty = true;
- return;
+ public Session(Manager manager) {
+ super(manager);
+ resetDirtyTracking();
}
- Object oldValue = getAttribute(key);
- super.setAttribute(key, value);
-
- if ((value != null || oldValue != null)
- && (value == null && oldValue != null || oldValue == null && value != null
- || !value.getClass().isInstance(oldValue) || !value.equals(oldValue))) {
- if (this.manager instanceof SessionManager && ((SessionManager) this.manager)
- .getSaveOnChange()) {
- ((SessionManager) this.manager).save(this, true);
- } else {
- this.changedAttributes.put(key, value);
- }
+ /** To reset dirty tracking. */
+ public void resetDirtyTracking() {
+ this.changedAttributes = new HashMap<>();
+ this.dirty = false;
}
- }
- /**
- * {@inheritDoc}
- */
- @Override
- public Object getAttribute(String name) {
- return super.getAttribute(name);
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public Enumeration getAttributeNames() {
- return super.getAttributeNames();
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void removeAttribute(String name) {
- super.removeAttribute(name);
- if (this.manager instanceof SessionManager && ((SessionManager) this.manager)
- .getSaveOnChange()) {
- ((SessionManager) this.manager).save(this, true);
- } else {
- this.dirty = true;
+ /** To set manual dirty tracking support enabled. */
+ public static void setManualDirtyTrackingSupportEnabled(boolean enabled) {
+ manualDirtyTrackingSupportEnabled = enabled;
}
- }
- /**
- * {@inheritDoc}
- */
- @Override
- public void setPrincipal(Principal principal) {
- super.setPrincipal(principal);
- this.dirty = true;
- }
+ /** To set manual dirty tracking attribute key. */
+ public static void setManualDirtyTrackingAttributeKey(String key) {
+ manualDirtyTrackingAttributeKey = key;
+ }
- /**
- * {@inheritDoc}
- */
- @Override
- public void writeObjectData(ObjectOutputStream out) throws IOException {
- super.writeObjectData(out);
- out.writeLong(this.getCreationTime());
- }
+ /** Returns dirty check. */
+ public Boolean isDirty() {
+ return this.dirty || !this.changedAttributes.isEmpty();
+ }
- /**
- * {@inheritDoc}
- */
- @Override
- public void readObjectData(ObjectInputStream in) throws IOException, ClassNotFoundException {
- super.readObjectData(in);
- this.setCreationTime(in.readLong());
- }
+ /** To get changed attributes. */
+ public Map getChangedAttributes() {
+ return this.changedAttributes;
+ }
- /**
- * {@inheritDoc}
- */
- @Override
- public void invalidate() {
- super.invalidate();
- }
-}
\ No newline at end of file
+ /** {@inheritDoc} */
+ @Override
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void setAttribute(String key, Object value) {
+ if (manualDirtyTrackingSupportEnabled && manualDirtyTrackingAttributeKey.equals(key)) {
+ this.dirty = true;
+ return;
+ }
+
+ Object oldValue = getAttribute(key);
+ super.setAttribute(key, value);
+
+ if ((value != null || oldValue != null)
+ && (value == null && oldValue != null || oldValue == null && value != null
+ || !value.getClass().isInstance(oldValue) || !value.equals(oldValue))) {
+ if (this.manager instanceof SessionManager && ((SessionManager) this.manager)
+ .getSaveOnChange()) {
+ ((SessionManager) this.manager).save(this, true);
+ } else {
+ this.changedAttributes.put(key, value);
+ }
+ }
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public Object getAttribute(String name) {
+ return super.getAttribute(name);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public Enumeration getAttributeNames() {
+ return super.getAttributeNames();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void removeAttribute(String name) {
+ super.removeAttribute(name);
+ if (this.manager instanceof SessionManager && ((SessionManager) this.manager)
+ .getSaveOnChange()) {
+ ((SessionManager) this.manager).save(this, true);
+ } else {
+ this.dirty = true;
+ }
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void setPrincipal(Principal principal) {
+ super.setPrincipal(principal);
+ this.dirty = true;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void writeObjectData(ObjectOutputStream out) throws IOException {
+ super.writeObjectData(out);
+ out.writeLong(this.getCreationTime());
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void readObjectData(ObjectInputStream in) throws IOException, ClassNotFoundException {
+ super.readObjectData(in);
+ this.setCreationTime(in.readLong());
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void invalidate() {
+ super.invalidate();
+ }
+
+}
diff --git a/src/main/java/tomcat/request/session/SessionConstants.java b/src/main/java/tomcat/request/session/SessionConstants.java
index 0cc3550..44f2b2d 100644
--- a/src/main/java/tomcat/request/session/SessionConstants.java
+++ b/src/main/java/tomcat/request/session/SessionConstants.java
@@ -1,18 +1,22 @@
package tomcat.request.session;
-/**
- * Tomcat clustering with Redis data-cache implementation.
- *
- * Session constants.
- *
- * @author Ranjith Manickam
- * @since 2.0
- */
+/** author: Ranjith Manickam @ 12 Jul' 2018 */
public interface SessionConstants {
+ byte[] NULL_SESSION = "null".getBytes();
+ String CATALINA_BASE = "catalina.base";
+ String CONF = "conf";
- byte[] NULL_SESSION = "null".getBytes();
+ enum SessionPolicy {
+ DEFAULT, SAVE_ON_CHANGE, ALWAYS_SAVE_AFTER_REQUEST;
- String CATALINA_BASE = "catalina.base";
+ public static SessionPolicy fromName(String name) {
+ for (SessionPolicy policy : SessionPolicy.values()) {
+ if (policy.name().equalsIgnoreCase(name)) {
+ return policy;
+ }
+ }
+ throw new IllegalArgumentException("Invalid session policy [" + name + "]");
+ }
+ }
- String CONF = "conf";
-}
\ No newline at end of file
+}
diff --git a/src/main/java/tomcat/request/session/SessionContext.java b/src/main/java/tomcat/request/session/SessionContext.java
index 08c4ac8..263615b 100644
--- a/src/main/java/tomcat/request/session/SessionContext.java
+++ b/src/main/java/tomcat/request/session/SessionContext.java
@@ -1,85 +1,57 @@
package tomcat.request.session;
-/**
- * Tomcat clustering with Redis data-cache implementation.
- *
- * Session context uses to manage current session data.
- *
- * @author Ranjith Manickam
- * @since 2.0
- */
+/** author: Ranjith Manickam @ 12 Jul' 2018 */
public class SessionContext {
- private String id;
+ private String id;
+ private Session session;
+ private boolean persisted;
+ private SessionMetadata metadata;
- private Session session;
+ /** To get session id. */
+ public String getId() {
+ return id;
+ }
- private boolean persisted;
+ /** To set session id. */
+ public void setId(String id) {
+ this.id = id;
+ }
- private SessionMetadata metadata;
+ /** To get session. */
+ public Session getSession() {
+ return session;
+ }
- /**
- * To get session id
- */
- public String getId() {
- return id;
- }
+ /** To set session. */
+ public void setSession(Session session) {
+ this.session = session;
+ }
- /**
- * To set session id
- */
- public void setId(String id) {
- this.id = id;
- }
+ /** To check session is persisted. */
+ public boolean isPersisted() {
+ return persisted;
+ }
- /**
- * To get session
- */
- public Session getSession() {
- return session;
- }
+ /** To set session persisted. */
+ public void setPersisted(boolean persisted) {
+ this.persisted = persisted;
+ }
- /**
- * To set session
- */
- public void setSession(Session session) {
- this.session = session;
- }
+ /** To get session meta-data. */
+ public SessionMetadata getMetadata() {
+ return metadata;
+ }
- /**
- * To check session is persisted
- */
- public boolean isPersisted() {
- return persisted;
- }
+ /** To set session meta-data. */
+ public void setMetadata(SessionMetadata metadata) {
+ this.metadata = metadata;
+ }
- /**
- * To set session persisted
- */
- public void setPersisted(boolean persisted) {
- this.persisted = persisted;
- }
+ /** {@inheritDoc} */
+ @Override
+ public String toString() {
+ return "SessionContext [id=" + id + "]";
+ }
- /**
- * To get session meta-data
- */
- public SessionMetadata getMetadata() {
- return metadata;
- }
-
- /**
- * To set session meta-data
- */
- public void setMetadata(SessionMetadata metadata) {
- this.metadata = metadata;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public String toString() {
- return "SessionContext [id=" + id + "]";
- }
-
-}
\ No newline at end of file
+}
diff --git a/src/main/java/tomcat/request/session/SessionMetadata.java b/src/main/java/tomcat/request/session/SessionMetadata.java
index 2b654aa..989cf08 100644
--- a/src/main/java/tomcat/request/session/SessionMetadata.java
+++ b/src/main/java/tomcat/request/session/SessionMetadata.java
@@ -5,60 +5,44 @@ import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
-/**
- * Tomcat clustering with Redis data-cache implementation.
- *
- * This class is uses to store and retrieve the HTTP request session object meta-data.
- *
- * @author Ranjith Manickam
- * @since 2.0
- */
+/** author: Ranjith Manickam @ 12 Jul' 2018 */
public class SessionMetadata implements Serializable {
- private static final long serialVersionUID = 124438185184833546L;
+ private static final long serialVersionUID = 124438185184833546L;
- private byte[] attributesHash;
+ private byte[] attributesHash;
- public SessionMetadata() {
- this.attributesHash = new byte[0];
- }
+ public SessionMetadata() {
+ this.attributesHash = new byte[0];
+ }
- /**
- * To get session meta-data hash
- */
- public byte[] getAttributesHash() {
- return this.attributesHash;
- }
+ /** To get session meta-data hash. */
+ public byte[] getAttributesHash() {
+ return this.attributesHash;
+ }
- /**
- * To set session meta-data hash
- */
- public void setAttributesHash(byte[] attributesHash) {
- this.attributesHash = attributesHash;
- }
+ /** To set session meta-data hash. */
+ public void setAttributesHash(byte[] attributesHash) {
+ this.attributesHash = attributesHash;
+ }
- /**
- * To copy session meta-data
- */
- public void copyFieldsFrom(SessionMetadata metadata) {
- this.setAttributesHash(metadata.getAttributesHash());
- }
+ /** To copy session meta-data. */
+ public void copyFieldsFrom(SessionMetadata metadata) {
+ this.setAttributesHash(metadata.getAttributesHash());
+ }
- /**
- * To write session meta-data to output stream
- */
- private void writeObject(ObjectOutputStream out) throws IOException {
- out.writeInt(this.attributesHash.length);
- out.write(this.attributesHash);
- }
+ /** To write session meta-data to output stream. */
+ private void writeObject(ObjectOutputStream out) throws IOException {
+ out.writeInt(this.attributesHash.length);
+ out.write(this.attributesHash);
+ }
- /**
- * To read session meta-data from input stream
- */
- private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
- int hashLength = in.readInt();
- byte[] attributesHash = new byte[hashLength];
- in.read(attributesHash, 0, hashLength);
- this.attributesHash = attributesHash;
- }
-}
\ No newline at end of file
+ /** To read session meta-data from input stream. */
+ private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
+ int hashLength = in.readInt();
+ byte[] attributesHash = new byte[hashLength];
+ in.read(attributesHash, 0, hashLength);
+ this.attributesHash = attributesHash;
+ }
+
+}
diff --git a/src/main/java/tomcat/request/session/data/cache/DataCache.java b/src/main/java/tomcat/request/session/data/cache/DataCache.java
index 2988184..be3b045 100644
--- a/src/main/java/tomcat/request/session/data/cache/DataCache.java
+++ b/src/main/java/tomcat/request/session/data/cache/DataCache.java
@@ -1,40 +1,49 @@
package tomcat.request.session.data.cache;
-/**
- * Tomcat clustering with Redis data-cache implementation.
- *
- * API for Data cache.
- *
- * @author Ranjith Manickam
- * @since 2.0
- */
+/** author: Ranjith Manickam @ 12 Jul' 2018 */
public interface DataCache {
- /**
- * To set value in data-cache
- */
- byte[] set(String key, byte[] value);
+ /**
+ * Set value in data-cache.
+ *
+ * @param key - key with which the specified value is to be associated.
+ * @param value - value to be associated with the specified key.
+ * @return - Returns the value.
+ */
+ byte[] set(String key, byte[] value);
- /**
- * To set value if key not exists in data-cache
- *
- * Returns If key exists = 0 else 1
- */
- Long setnx(String key, byte[] value);
+ /**
+ * Set value if key not exists in data-cache.
+ *
+ * @param key - key with which the specified value is to be associated.
+ * @param value - value to be associated with the specified key.
+ * @return - Returns '0' if key already exists else '1'.
+ */
+ Long setnx(String key, byte[] value);
- /**
- * To expire the value based on key in data-cache
- */
- Long expire(String key, int seconds);
+ /**
+ * Set expiry in data-cache.
+ *
+ * @param key - key with which the specified value is to be associated.
+ * @param seconds - expiration time in seconds.
+ * @return - Returns the expiration time in seconds.
+ */
+ Long expire(String key, int seconds);
- /**
- * To get the value based on key from data-cache
- */
- byte[] get(String key);
+ /**
+ * Get value from data-cache.
+ *
+ * @param key - key with which the specified value is to be associated.
+ * @return - Returns the value.
+ */
+ byte[] get(String key);
- /**
- * To delete the value based on key from data-cache
- */
- Long delete(String key);
+ /**
+ * Delete value from data-cache.
+ *
+ * @param key - key with which the specified value is to be associated.
+ * @return - Returns the number of keys that were removed.
+ */
+ Long delete(String key);
-}
\ No newline at end of file
+}
diff --git a/src/main/java/tomcat/request/session/data/cache/impl/RedisCacheUtil.java b/src/main/java/tomcat/request/session/data/cache/impl/RedisCacheUtil.java
deleted file mode 100644
index 1afe6b2..0000000
--- a/src/main/java/tomcat/request/session/data/cache/impl/RedisCacheUtil.java
+++ /dev/null
@@ -1,147 +0,0 @@
-package tomcat.request.session.data.cache.impl;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-
-import redis.clients.jedis.Jedis;
-import redis.clients.jedis.JedisPool;
-import redis.clients.jedis.JedisPoolConfig;
-import redis.clients.jedis.exceptions.JedisConnectionException;
-import tomcat.request.session.data.cache.DataCache;
-
-/**
- * Tomcat clustering with Redis data-cache implementation.
- *
- * Redis stand-alone mode data-cache implementation.
- *
- * @author Ranjith Manickam
- * @since 2.0
- */
-class RedisCacheUtil implements DataCache {
-
- private JedisPool pool;
-
- private static final int NUM_RETRIES = 3;
-
- private Log log = LogFactory.getLog(RedisCacheUtil.class);
-
- RedisCacheUtil(String host, int port, String password, int database, int timeout,
- JedisPoolConfig poolConfig) {
- pool = new JedisPool(poolConfig, host, port, timeout, password, database);
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public byte[] set(String key, byte[] value) {
- int tries = 0;
- boolean sucess = false;
- String retVal = null;
- do {
- tries++;
- try (Jedis jedis = pool.getResource()) {
- retVal = jedis.set(key.getBytes(), value);
- sucess = true;
- } catch (JedisConnectionException ex) {
- log.error(RedisConstants.CONN_FAILED_RETRY_MSG + tries);
- if (tries == NUM_RETRIES) {
- throw ex;
- }
- }
- } while (!sucess && tries <= NUM_RETRIES);
- return (retVal != null) ? retVal.getBytes() : null;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public Long setnx(String key, byte[] value) {
- int tries = 0;
- boolean sucess = false;
- Long retVal = null;
- do {
- tries++;
- try (Jedis jedis = pool.getResource()) {
- retVal = jedis.setnx(key.getBytes(), value);
- sucess = true;
- } catch (JedisConnectionException ex) {
- log.error(RedisConstants.CONN_FAILED_RETRY_MSG + tries);
- if (tries == NUM_RETRIES) {
- throw ex;
- }
- }
- } while (!sucess && tries <= NUM_RETRIES);
- return retVal;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public Long expire(String key, int seconds) {
- int tries = 0;
- boolean sucess = false;
- Long retVal = null;
- do {
- tries++;
- try (Jedis jedis = pool.getResource()) {
- retVal = jedis.expire(key, seconds);
- sucess = true;
- } catch (JedisConnectionException ex) {
- log.error(RedisConstants.CONN_FAILED_RETRY_MSG + tries);
- if (tries == NUM_RETRIES) {
- throw ex;
- }
- }
- } while (!sucess && tries <= NUM_RETRIES);
- return retVal;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public byte[] get(String key) {
- int tries = 0;
- boolean sucess = false;
- byte[] retVal = null;
- do {
- tries++;
- try (Jedis jedis = pool.getResource()) {
- retVal = jedis.get(key.getBytes());
- sucess = true;
- } catch (JedisConnectionException ex) {
- log.error(RedisConstants.CONN_FAILED_RETRY_MSG + tries);
- if (tries == NUM_RETRIES) {
- throw ex;
- }
- }
- } while (!sucess && tries <= NUM_RETRIES);
- return retVal;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public Long delete(String key) {
- int tries = 0;
- boolean sucess = false;
- Long retVal = null;
- do {
- tries++;
- try (Jedis jedis = pool.getResource()) {
- retVal = jedis.del(key);
- sucess = true;
- } catch (JedisConnectionException ex) {
- log.error(RedisConstants.CONN_FAILED_RETRY_MSG + tries);
- if (tries == NUM_RETRIES) {
- throw ex;
- }
- }
- } while (!sucess && tries <= NUM_RETRIES);
- return retVal;
- }
-}
\ No newline at end of file
diff --git a/src/main/java/tomcat/request/session/data/cache/impl/RedisClusterCacheUtil.java b/src/main/java/tomcat/request/session/data/cache/impl/RedisClusterCacheUtil.java
deleted file mode 100644
index 328c3f3..0000000
--- a/src/main/java/tomcat/request/session/data/cache/impl/RedisClusterCacheUtil.java
+++ /dev/null
@@ -1,169 +0,0 @@
-package tomcat.request.session.data.cache.impl;
-
-import java.util.Set;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-
-import redis.clients.jedis.HostAndPort;
-import redis.clients.jedis.JedisCluster;
-import redis.clients.jedis.JedisPoolConfig;
-import redis.clients.jedis.Protocol;
-import redis.clients.jedis.exceptions.JedisClusterMaxRedirectionsException;
-import redis.clients.jedis.exceptions.JedisConnectionException;
-import tomcat.request.session.data.cache.DataCache;
-
-/**
- * Tomcat clustering with Redis data-cache implementation.
- *
- * Redis multiple node cluster data-cache implementation.
- *
- * @author Ranjith Manickam
- * @since 2.0
- */
-class RedisClusterCacheUtil implements DataCache {
-
- private JedisCluster cluster;
-
- private static final int NUM_RETRIES = 30;
- private static final int DEFAULT_MAX_REDIRECTIONS = 5;
-
- private Log log = LogFactory.getLog(RedisClusterCacheUtil.class);
-
- RedisClusterCacheUtil(Set nodes, String password, int timeout,
- JedisPoolConfig poolConfig) {
- cluster = new JedisCluster(nodes, timeout, Protocol.DEFAULT_TIMEOUT, DEFAULT_MAX_REDIRECTIONS,
- password, poolConfig);
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public byte[] set(String key, byte[] value) {
- int tries = 0;
- boolean sucess = false;
- String retVal = null;
- do {
- tries++;
- try {
- retVal = cluster.set(key.getBytes(), value);
- sucess = true;
- } catch (JedisClusterMaxRedirectionsException | JedisConnectionException ex) {
- log.error(RedisConstants.CONN_FAILED_RETRY_MSG + tries);
- if (tries == NUM_RETRIES) {
- throw ex;
- }
- waitforFailover();
- }
- } while (!sucess && tries <= NUM_RETRIES);
- return (retVal != null) ? retVal.getBytes() : null;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public Long setnx(String key, byte[] value) {
- int tries = 0;
- boolean sucess = false;
- Long retVal = null;
- do {
- tries++;
- try {
- retVal = cluster.setnx(key.getBytes(), value);
- sucess = true;
- } catch (JedisClusterMaxRedirectionsException | JedisConnectionException ex) {
- log.error(RedisConstants.CONN_FAILED_RETRY_MSG + tries);
- if (tries == NUM_RETRIES) {
- throw ex;
- }
- waitforFailover();
- }
- } while (!sucess && tries <= NUM_RETRIES);
- return retVal;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public Long expire(String key, int seconds) {
- int tries = 0;
- boolean sucess = false;
- Long retVal = null;
- do {
- tries++;
- try {
- retVal = cluster.expire(key, seconds);
- sucess = true;
- } catch (JedisClusterMaxRedirectionsException | JedisConnectionException ex) {
- log.error(RedisConstants.CONN_FAILED_RETRY_MSG + tries);
- if (tries == NUM_RETRIES) {
- throw ex;
- }
- waitforFailover();
- }
- } while (!sucess && tries <= NUM_RETRIES);
- return retVal;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public byte[] get(String key) {
- int tries = 0;
- boolean sucess = false;
- byte[] retVal = null;
- do {
- tries++;
- try {
- retVal = cluster.get(key.getBytes());
- sucess = true;
- } catch (JedisClusterMaxRedirectionsException | JedisConnectionException ex) {
- log.error(RedisConstants.CONN_FAILED_RETRY_MSG + tries);
- if (tries == NUM_RETRIES) {
- throw ex;
- }
- waitforFailover();
- }
- } while (!sucess && tries <= NUM_RETRIES);
- return retVal;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public Long delete(String key) {
- int tries = 0;
- boolean sucess = false;
- Long retVal = null;
- do {
- tries++;
- try {
- retVal = cluster.del(key);
- sucess = true;
- } catch (JedisClusterMaxRedirectionsException | JedisConnectionException ex) {
- log.error(RedisConstants.CONN_FAILED_RETRY_MSG + tries);
- if (tries == NUM_RETRIES) {
- throw ex;
- }
- waitforFailover();
- }
- } while (!sucess && tries <= NUM_RETRIES);
- return retVal;
- }
-
- /**
- * To wait for handling redis fail-over
- */
- private void waitforFailover() {
- try {
- Thread.sleep(4000);
- } catch (InterruptedException ex) {
- Thread.currentThread().interrupt();
- }
- }
-}
diff --git a/src/main/java/tomcat/request/session/data/cache/impl/RedisConstants.java b/src/main/java/tomcat/request/session/data/cache/impl/RedisConstants.java
deleted file mode 100644
index 3745a8a..0000000
--- a/src/main/java/tomcat/request/session/data/cache/impl/RedisConstants.java
+++ /dev/null
@@ -1,45 +0,0 @@
-package tomcat.request.session.data.cache.impl;
-
-/**
- * Tomcat clustering with Redis data-cache implementation.
- *
- * Redis data-cache constants.
- *
- * @author Ranjith Manickam
- * @since 2.0
- */
-interface RedisConstants {
-
- // redis properties file name
- String PROPERTIES_FILE = "redis-data-cache.properties";
-
- // redis properties
- String HOSTS = "redis.hosts";
- String CLUSTER_ENABLED = "redis.cluster.enabled";
-
- String MAX_ACTIVE = "redis.max.active";
- String TEST_ONBORROW = "redis.test.onBorrow";
- String TEST_ONRETURN = "redis.test.onReturn";
- String MAX_IDLE = "redis.max.idle";
- String MIN_IDLE = "redis.min.idle";
- String TEST_WHILEIDLE = "redis.test.whileIdle";
- String TEST_NUMPEREVICTION = "redis.test.numPerEviction";
- String TIME_BETWEENEVICTION = "redis.time.betweenEviction";
-
- String PASSWORD = "redis.password";
- String DATABASE = "redis.database";
- String TIMEOUT = "redis.timeout";
-
- // redis property default values
- String DEFAULT_MAX_ACTIVE_VALUE = "10";
- String DEFAULT_TEST_ONBORROW_VALUE = "true";
- String DEFAULT_TEST_ONRETURN_VALUE = "true";
- String DEFAULT_MAX_IDLE_VALUE = "5";
- String DEFAULT_MIN_IDLE_VALUE = "1";
- String DEFAULT_TEST_WHILEIDLE_VALUE = "true";
- String DEFAULT_TEST_NUMPEREVICTION_VALUE = "10";
- String DEFAULT_TIME_BETWEENEVICTION_VALUE = "60000";
- String DEFAULT_CLUSTER_ENABLED = "false";
-
- String CONN_FAILED_RETRY_MSG = "Jedis connection failed, retrying...";
-}
\ No newline at end of file
diff --git a/src/main/java/tomcat/request/session/data/cache/impl/RedisDataCache.java b/src/main/java/tomcat/request/session/data/cache/impl/RedisDataCache.java
deleted file mode 100644
index db1e25a..0000000
--- a/src/main/java/tomcat/request/session/data/cache/impl/RedisDataCache.java
+++ /dev/null
@@ -1,226 +0,0 @@
-package tomcat.request.session.data.cache.impl;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.Serializable;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Properties;
-import java.util.Set;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-
-import redis.clients.jedis.HostAndPort;
-import redis.clients.jedis.JedisPoolConfig;
-import redis.clients.jedis.Protocol;
-import tomcat.request.session.SessionConstants;
-import tomcat.request.session.data.cache.DataCache;
-
-/**
- * Tomcat clustering with Redis data-cache implementation.
- *
- * Redis data-cache implementation to store/retrieve session objects.
- *
- * @author Ranjith Manickam
- * @since 2.0
- */
-public class RedisDataCache implements DataCache {
-
- private static DataCache dataCache;
-
- private Log log = LogFactory.getLog(RedisDataCache.class);
-
- public RedisDataCache() {
- initialize();
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public byte[] set(String key, byte[] value) {
- return dataCache.set(key, value);
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public Long setnx(String key, byte[] value) {
- return dataCache.setnx(key, value);
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public Long expire(String key, int seconds) {
- return dataCache.expire(key, seconds);
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public byte[] get(String key) {
- return (key != null) ? dataCache.get(key) : null;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public Long delete(String key) {
- return dataCache.delete(key);
- }
-
- /**
- * To parse data-cache key
- */
- public static String parseDataCacheKey(String key) {
- return key.replaceAll("\\s", "_");
- }
-
- /**
- * To initialize the data-cache
- */
- @SuppressWarnings("unchecked")
- private void initialize() {
- if (dataCache != null) {
- return;
- }
- Properties properties = loadProperties();
-
- boolean clusterEnabled = Boolean.valueOf(properties
- .getProperty(RedisConstants.CLUSTER_ENABLED, RedisConstants.DEFAULT_CLUSTER_ENABLED));
-
- String hosts = properties.getProperty(RedisConstants.HOSTS,
- Protocol.DEFAULT_HOST.concat(":").concat(String.valueOf(Protocol.DEFAULT_PORT)));
- Collection extends Serializable> nodes = getJedisNodes(hosts, clusterEnabled);
-
- String password = properties.getProperty(RedisConstants.PASSWORD);
- password = (password != null && !password.isEmpty()) ? password : null;
-
- int database = Integer.parseInt(
- properties.getProperty(RedisConstants.DATABASE, String.valueOf(Protocol.DEFAULT_DATABASE)));
-
- int timeout = Integer.parseInt(
- properties.getProperty(RedisConstants.TIMEOUT, String.valueOf(Protocol.DEFAULT_TIMEOUT)));
- timeout = (timeout < Protocol.DEFAULT_TIMEOUT) ? Protocol.DEFAULT_TIMEOUT : timeout;
-
- if (clusterEnabled) {
- dataCache = new RedisClusterCacheUtil((Set) nodes, password, timeout,
- getPoolConfig(properties));
- } else {
- dataCache = new RedisCacheUtil(((List) nodes).get(0),
- Integer.parseInt(((List) nodes).get(1)), password, database, timeout,
- getPoolConfig(properties));
- }
- }
-
- /**
- * To get jedis pool configuration
- */
- private JedisPoolConfig getPoolConfig(Properties properties) {
- JedisPoolConfig poolConfig = new JedisPoolConfig();
- int maxActive = Integer.parseInt(
- properties.getProperty(RedisConstants.MAX_ACTIVE, RedisConstants.DEFAULT_MAX_ACTIVE_VALUE));
- poolConfig.setMaxTotal(maxActive);
-
- boolean testOnBorrow = Boolean.parseBoolean(properties
- .getProperty(RedisConstants.TEST_ONBORROW, RedisConstants.DEFAULT_TEST_ONBORROW_VALUE));
- poolConfig.setTestOnBorrow(testOnBorrow);
-
- boolean testOnReturn = Boolean.parseBoolean(properties
- .getProperty(RedisConstants.TEST_ONRETURN, RedisConstants.DEFAULT_TEST_ONRETURN_VALUE));
- poolConfig.setTestOnReturn(testOnReturn);
-
- int maxIdle = Integer.parseInt(
- properties.getProperty(RedisConstants.MAX_ACTIVE, RedisConstants.DEFAULT_MAX_ACTIVE_VALUE));
- poolConfig.setMaxIdle(maxIdle);
-
- int minIdle = Integer.parseInt(
- properties.getProperty(RedisConstants.MIN_IDLE, RedisConstants.DEFAULT_MIN_IDLE_VALUE));
- poolConfig.setMinIdle(minIdle);
-
- boolean testWhileIdle = Boolean.parseBoolean(properties
- .getProperty(RedisConstants.TEST_WHILEIDLE, RedisConstants.DEFAULT_TEST_WHILEIDLE_VALUE));
- poolConfig.setTestWhileIdle(testWhileIdle);
-
- int testNumPerEviction = Integer.parseInt(properties
- .getProperty(RedisConstants.TEST_NUMPEREVICTION,
- RedisConstants.DEFAULT_TEST_NUMPEREVICTION_VALUE));
- poolConfig.setNumTestsPerEvictionRun(testNumPerEviction);
-
- long timeBetweenEviction = Long.parseLong(properties
- .getProperty(RedisConstants.TIME_BETWEENEVICTION,
- RedisConstants.DEFAULT_TIME_BETWEENEVICTION_VALUE));
- poolConfig.setTimeBetweenEvictionRunsMillis(timeBetweenEviction);
- return poolConfig;
- }
-
- /**
- * To get jedis nodes
- */
- private Collection extends Serializable> getJedisNodes(String hosts, boolean clusterEnabled) {
- hosts = hosts.replaceAll("\\s", "");
- String[] hostPorts = hosts.split(",");
-
- List node = null;
- Set nodes = null;
-
- for (String hostPort : hostPorts) {
- String[] hostPortArr = hostPort.split(":");
-
- if (clusterEnabled) {
- nodes = (nodes == null) ? new HashSet() : nodes;
- nodes.add(new HostAndPort(hostPortArr[0], Integer.valueOf(hostPortArr[1])));
- } else {
- int port = Integer.valueOf(hostPortArr[1]);
- if (!hostPortArr[0].isEmpty() && port > 0) {
- node = (node == null) ? new ArrayList() : node;
- node.add(hostPortArr[0]);
- node.add(String.valueOf(port));
- break;
- }
- }
- }
- return clusterEnabled ? nodes : node;
- }
-
- /**
- * To load data-cache properties
- */
- private Properties loadProperties() {
- Properties properties = new Properties();
- try {
- String filePath = System.getProperty(SessionConstants.CATALINA_BASE).concat(File.separator)
- .concat(SessionConstants.CONF).concat(File.separator)
- .concat(RedisConstants.PROPERTIES_FILE);
-
- InputStream resourceStream = null;
- try {
- resourceStream = (filePath != null && !filePath.isEmpty() && new File(filePath).exists())
- ? new FileInputStream(filePath) : null;
-
- if (resourceStream == null) {
- ClassLoader loader = Thread.currentThread().getContextClassLoader();
- resourceStream = loader.getResourceAsStream(RedisConstants.PROPERTIES_FILE);
- }
- properties.load(resourceStream);
- } finally {
- if (resourceStream != null) {
- resourceStream.close();
- }
- }
- } catch (IOException ex) {
- log.error("Error while loading task scheduler properties", ex);
- }
- return properties;
- }
-}
\ No newline at end of file
diff --git a/src/main/java/tomcat/request/session/data/cache/impl/redis/AbstractRedisUtil.java b/src/main/java/tomcat/request/session/data/cache/impl/redis/AbstractRedisUtil.java
new file mode 100644
index 0000000..03d7f35
--- /dev/null
+++ b/src/main/java/tomcat/request/session/data/cache/impl/redis/AbstractRedisUtil.java
@@ -0,0 +1,132 @@
+package tomcat.request.session.data.cache.impl.redis;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import redis.clients.jedis.Jedis;
+import redis.clients.jedis.exceptions.JedisConnectionException;
+import redis.clients.util.Pool;
+import tomcat.request.session.data.cache.DataCache;
+
+/** author: Ranjith Manickam @ 12 Jul' 2018 */
+public abstract class AbstractRedisUtil implements DataCache {
+
+ private static final int NUM_RETRIES = 3;
+ private static final Log LOGGER = LogFactory.getLog(RedisUtil.class);
+
+ private final Pool pool;
+ private final long failiureWaitTime;
+
+ AbstractRedisUtil(Pool pool, long failiureWaitTime) {
+ this.pool = pool;
+ this.failiureWaitTime = failiureWaitTime;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public byte[] set(String key, byte[] value) {
+ int tries = 0;
+ boolean retry = true;
+ String retVal = null;
+ do {
+ tries++;
+ try (Jedis jedis = this.pool.getResource()) {
+ retVal = jedis.set(key.getBytes(), value);
+ retry = false;
+ } catch (JedisConnectionException ex) {
+ handleException(tries, ex);
+ }
+ } while (retry && tries <= NUM_RETRIES);
+ return (retVal != null) ? retVal.getBytes() : null;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public Long setnx(String key, byte[] value) {
+ int tries = 0;
+ boolean retry = true;
+ Long retVal = null;
+ do {
+ tries++;
+ try (Jedis jedis = this.pool.getResource()) {
+ retVal = jedis.setnx(key.getBytes(), value);
+ retry = false;
+ } catch (JedisConnectionException ex) {
+ handleException(tries, ex);
+ }
+ } while (retry && tries <= NUM_RETRIES);
+ return retVal;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public Long expire(String key, int seconds) {
+ int tries = 0;
+ boolean retry = true;
+ Long retVal = null;
+ do {
+ tries++;
+ try (Jedis jedis = this.pool.getResource()) {
+ retVal = jedis.expire(key, seconds);
+ retry = false;
+ } catch (JedisConnectionException ex) {
+ handleException(tries, ex);
+ }
+ } while (retry && tries <= NUM_RETRIES);
+ return retVal;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public byte[] get(String key) {
+ int tries = 0;
+ boolean retry = true;
+ byte[] retVal = null;
+ do {
+ tries++;
+ try (Jedis jedis = this.pool.getResource()) {
+ retVal = jedis.get(key.getBytes());
+ retry = false;
+ } catch (JedisConnectionException ex) {
+ handleException(tries, ex);
+ }
+ } while (retry && tries <= NUM_RETRIES);
+ return retVal;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public Long delete(String key) {
+ int tries = 0;
+ boolean retry = true;
+ Long retVal = null;
+ do {
+ tries++;
+ try (Jedis jedis = this.pool.getResource()) {
+ retVal = jedis.del(key);
+ retry = false;
+ } catch (JedisConnectionException ex) {
+ handleException(tries, ex);
+ }
+ } while (retry && tries <= NUM_RETRIES);
+ return retVal;
+ }
+
+ /**
+ * To handle jedis exception.
+ *
+ * @param tries - exception occurred in tries.
+ * @param ex - jedis exception.
+ */
+ void handleException(int tries, RuntimeException ex) {
+ LOGGER.error(RedisConstants.CONN_FAILED_RETRY_MSG + tries);
+ if (tries == NUM_RETRIES) {
+ throw ex;
+ }
+ try {
+ Thread.sleep(this.failiureWaitTime);
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ }
+ }
+
+}
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
new file mode 100644
index 0000000..e83dd3b
--- /dev/null
+++ b/src/main/java/tomcat/request/session/data/cache/impl/redis/RedisCache.java
@@ -0,0 +1,206 @@
+package tomcat.request.session.data.cache.impl.redis;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import redis.clients.jedis.HostAndPort;
+import redis.clients.jedis.JedisPoolConfig;
+import redis.clients.jedis.Protocol;
+import tomcat.request.session.SessionConstants;
+import tomcat.request.session.data.cache.DataCache;
+import tomcat.request.session.data.cache.impl.redis.RedisConstants.RedisConfigType;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+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 */
+public class RedisCache implements DataCache {
+
+ private static DataCache dataCache;
+
+ private static final Log LOGGER = LogFactory.getLog(RedisCache.class);
+
+ public RedisCache() {
+ initialize();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public byte[] set(String key, byte[] value) {
+ return dataCache.set(key, value);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public Long setnx(String key, byte[] value) {
+ return dataCache.setnx(key, value);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public Long expire(String key, int seconds) {
+ return dataCache.expire(key, seconds);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public byte[] get(String key) {
+ return dataCache.get(key);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public Long delete(String key) {
+ return dataCache.delete(key);
+ }
+
+ /** To initialize the redis data cache. */
+ private void initialize() {
+ if (dataCache != null) {
+ return;
+ }
+ Properties properties = getProperties();
+
+ RedisConfigType configType;
+ if (Boolean.valueOf(properties.getProperty(RedisConstants.CLUSTER_ENABLED))) {
+ configType = RedisConfigType.CLUSTER;
+ } else if (Boolean.valueOf(properties.getProperty(RedisConstants.SENTINEL_ENABLED))) {
+ configType = RedisConfigType.SENTINEL;
+ } else {
+ configType = RedisConfigType.DEFAULT;
+ }
+
+ String hosts = properties.getProperty(RedisConstants.HOSTS, Protocol.DEFAULT_HOST.concat(":").concat(String.valueOf(Protocol.DEFAULT_PORT)));
+ Collection> nodes = getJedisNodes(hosts, configType);
+
+ String password = properties.getProperty(RedisConstants.PASSWORD);
+ password = (password != null && !password.isEmpty()) ? password : null;
+
+ int database = Integer.parseInt(properties.getProperty(RedisConstants.DATABASE, String.valueOf(Protocol.DEFAULT_DATABASE)));
+
+ int timeout = Integer.parseInt(properties.getProperty(RedisConstants.TIMEOUT, String.valueOf(Protocol.DEFAULT_TIMEOUT)));
+ timeout = (timeout < Protocol.DEFAULT_TIMEOUT) ? Protocol.DEFAULT_TIMEOUT : timeout;
+
+ JedisPoolConfig poolConfig = getPoolConfig(properties);
+ switch (configType) {
+ case CLUSTER:
+ dataCache = new RedisClusterUtil((Set) nodes, password, timeout, poolConfig);
+ break;
+ case SENTINEL:
+ String masterName = String.valueOf(properties.getProperty(RedisConstants.SENTINEL_MASTER, RedisConstants.DEFAULT_SENTINEL_MASTER));
+ dataCache = new RedisSentinelUtil((Set) nodes, masterName, password, database, timeout, poolConfig);
+ break;
+ default:
+ dataCache = new RedisUtil(((List) nodes).get(0), Integer.parseInt(((List) nodes).get(1)), password, database, timeout, poolConfig);
+ break;
+ }
+ }
+
+ /**
+ * To get redis pool config.
+ *
+ * @param properties - Redis data cache properties.
+ * @return - Returns the redis pool config.
+ */
+ private JedisPoolConfig getPoolConfig(Properties properties) {
+ JedisPoolConfig poolConfig = new JedisPoolConfig();
+ int maxActive = Integer.parseInt(properties.getProperty(RedisConstants.MAX_ACTIVE, RedisConstants.DEFAULT_MAX_ACTIVE_VALUE));
+ poolConfig.setMaxTotal(maxActive);
+
+ boolean testOnBorrow = Boolean.parseBoolean(properties.getProperty(RedisConstants.TEST_ONBORROW, RedisConstants.DEFAULT_TEST_ONBORROW_VALUE));
+ poolConfig.setTestOnBorrow(testOnBorrow);
+
+ boolean testOnReturn = Boolean.parseBoolean(properties.getProperty(RedisConstants.TEST_ONRETURN, RedisConstants.DEFAULT_TEST_ONRETURN_VALUE));
+ poolConfig.setTestOnReturn(testOnReturn);
+
+ int maxIdle = Integer.parseInt(properties.getProperty(RedisConstants.MAX_ACTIVE, RedisConstants.DEFAULT_MAX_ACTIVE_VALUE));
+ poolConfig.setMaxIdle(maxIdle);
+
+ int minIdle = Integer.parseInt(properties.getProperty(RedisConstants.MIN_IDLE, RedisConstants.DEFAULT_MIN_IDLE_VALUE));
+ poolConfig.setMinIdle(minIdle);
+
+ boolean testWhileIdle = Boolean.parseBoolean(properties.getProperty(RedisConstants.TEST_WHILEIDLE, RedisConstants.DEFAULT_TEST_WHILEIDLE_VALUE));
+ poolConfig.setTestWhileIdle(testWhileIdle);
+
+ int testNumPerEviction = Integer.parseInt(properties.getProperty(RedisConstants.TEST_NUMPEREVICTION, RedisConstants.DEFAULT_TEST_NUMPEREVICTION_VALUE));
+ poolConfig.setNumTestsPerEvictionRun(testNumPerEviction);
+
+ long timeBetweenEviction = Long.parseLong(properties.getProperty(RedisConstants.TIME_BETWEENEVICTION, RedisConstants.DEFAULT_TIME_BETWEENEVICTION_VALUE));
+ poolConfig.setTimeBetweenEvictionRunsMillis(timeBetweenEviction);
+ return poolConfig;
+ }
+
+ /**
+ * To get redis data cache nodes.
+ *
+ * @param hosts - redis server hosts.
+ * @param configType - redis data config type.
+ * @return - Returns the redis nodes.
+ */
+ private Collection> getJedisNodes(String hosts, RedisConfigType configType) {
+ hosts = hosts.replaceAll("\\s", "");
+ String[] hostPorts = hosts.split(",");
+
+ Set