diff --git a/src/main/java/tomcat/request/session/SerializationUtil.java b/src/main/java/tomcat/request/session/SerializationUtil.java index 25f7f15..48c2557 100644 --- a/src/main/java/tomcat/request/session/SerializationUtil.java +++ b/src/main/java/tomcat/request/session/SerializationUtil.java @@ -11,14 +11,11 @@ import java.security.MessageDigest; import java.util.Enumeration; import java.util.HashMap; import java.util.Map; - import org.apache.catalina.util.CustomObjectInputStream; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; /** * Tomcat clustering with Redis data-cache implementation. - * + * * Session serialization utility. * * @author Ranjith Manickam @@ -26,87 +23,69 @@ import org.apache.commons.logging.LogFactory; */ public class SerializationUtil { - private ClassLoader loader; + private ClassLoader loader; - private Log log = LogFactory.getLog(SerializationUtil.class); + /** + * To set class loader + */ + public void setClassLoader(ClassLoader loader) { + this.loader = loader; + } - /** - * To set class loader - * - * @param 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<>(); - /** - * To get session attributes hash code - * - * @param session - * @return - * @throws IOException - */ - public byte[] getSessionAttributesHashCode(Session session) throws IOException { - byte[] serialized = null; - Map attributes = new HashMap(); + for (Enumeration enumerator = session.getAttributeNames(); + enumerator.hasMoreElements(); ) { + String key = enumerator.nextElement(); + attributes.put(key, session.getAttribute(key)); + } - 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(); + } - 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 = null; - try { - digester = MessageDigest.getInstance("MD5"); - } catch (Exception ex) { - log.error("Unable to get MessageDigest instance for MD5", ex); - } - 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(); + } + return serialized; + } - /** - * To serialize session object - * - * @param session - * @param metadata - * @return - * @throws IOException - */ - public byte[] serializeSessionData(Session session, SessionMetadata metadata) throws IOException { - byte[] serialized = null; - 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; - } - - /** - * To de-serialize session object - * - * @param data - * @param session - * @param metadata - * @throws IOException - * @throws ClassNotFoundException - */ - 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); - } - } + /** + * 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 65b2870..55f71b2 100644 --- a/src/main/java/tomcat/request/session/Session.java +++ b/src/main/java/tomcat/request/session/Session.java @@ -15,7 +15,7 @@ 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 @@ -23,117 +23,137 @@ import tomcat.request.session.redis.SessionManager; */ 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 Boolean manualDirtyTrackingSupportEnabled = false; - protected static String manualDirtyTrackingAttributeKey = "__changed__"; + protected static String manualDirtyTrackingAttributeKey = "__changed__"; - public Session(Manager manager) { - super(manager); - resetDirtyTracking(); - } + public Session(Manager manager) { + super(manager); + resetDirtyTracking(); + } - public void resetDirtyTracking() { - this.changedAttributes = new HashMap<>(); - this.dirty = false; - } + public void resetDirtyTracking() { + this.changedAttributes = new HashMap<>(); + this.dirty = false; + } - public static void setManualDirtyTrackingSupportEnabled(boolean enabled) { - manualDirtyTrackingSupportEnabled = enabled; - } + public static void setManualDirtyTrackingSupportEnabled(boolean enabled) { + manualDirtyTrackingSupportEnabled = enabled; + } - public static void setManualDirtyTrackingAttributeKey(String key) { - manualDirtyTrackingAttributeKey = key; - } + public static void setManualDirtyTrackingAttributeKey(String key) { + manualDirtyTrackingAttributeKey = key; + } - public Boolean isDirty() { - return this.dirty || !this.changedAttributes.isEmpty(); - } + public Boolean isDirty() { + return this.dirty || !this.changedAttributes.isEmpty(); + } - public Map getChangedAttributes() { - return this.changedAttributes; - } + public Map getChangedAttributes() { + return this.changedAttributes; + } - /** {@inheritDoc} */ - @Override - public void setId(String id) { - this.id = id; - } + /** + * {@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; - } + /** + * {@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); + 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); - } - } - } + 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 Object getAttribute(String name) { + return super.getAttribute(name); + } - /** {@inheritDoc} */ - @Override - public Enumeration getAttributeNames() { - return super.getAttributeNames(); - } + /** + * {@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 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 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 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 readObjectData(ObjectInputStream in) throws IOException, ClassNotFoundException { + super.readObjectData(in); + this.setCreationTime(in.readLong()); + } - /** {@inheritDoc} */ - @Override - public void invalidate() { - super.invalidate(); - } + /** + * {@inheritDoc} + */ + @Override + public void invalidate() { + super.invalidate(); + } } \ No newline at end of file diff --git a/src/main/java/tomcat/request/session/SessionConstants.java b/src/main/java/tomcat/request/session/SessionConstants.java index 2568009..0cc3550 100644 --- a/src/main/java/tomcat/request/session/SessionConstants.java +++ b/src/main/java/tomcat/request/session/SessionConstants.java @@ -2,17 +2,17 @@ package tomcat.request.session; /** * Tomcat clustering with Redis data-cache implementation. - * + * * Session constants. - * + * * @author Ranjith Manickam * @since 2.0 */ -public class SessionConstants { +public interface SessionConstants { - public static final byte[] NULL_SESSION = "null".getBytes(); + byte[] NULL_SESSION = "null".getBytes(); - public static final String CATALINA_BASE = "catalina.base"; + String CATALINA_BASE = "catalina.base"; - public static final String CONF = "conf"; + 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 f333b0b..08c4ac8 100644 --- a/src/main/java/tomcat/request/session/SessionContext.java +++ b/src/main/java/tomcat/request/session/SessionContext.java @@ -2,98 +2,84 @@ 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 */ public class SessionContext { - private String id; + private String id; - private Session session; + private Session session; - private boolean persisted; + private boolean persisted; - private SessionMetadata metadata; + private SessionMetadata metadata; - /** - * To get session id - * - * @return - */ - public String getId() { - return id; - } + /** + * To get session id + */ + public String getId() { + return id; + } - /** - * To set session id - * - * @param id - */ - public void setId(String id) { - this.id = id; - } + /** + * To set session id + */ + public void setId(String id) { + this.id = id; + } - /** - * To get session - * - * @return - */ - public Session getSession() { - return session; - } + /** + * To get session + */ + public Session getSession() { + return session; + } - /** - * To set session - * - * @param session - */ - public void setSession(Session session) { - this.session = session; - } + /** + * To set session + */ + public void setSession(Session session) { + this.session = session; + } - /** - * To check session is persisted - * - * @return - */ - public boolean isPersisted() { - return persisted; - } + /** + * To check session is persisted + */ + public boolean isPersisted() { + return persisted; + } - /** - * To set session persisted - * - * @param persisted - */ - public void setPersisted(boolean persisted) { - this.persisted = persisted; - } + /** + * To set session persisted + */ + public void setPersisted(boolean persisted) { + this.persisted = persisted; + } - /** - * To get session meta-data - * - * @return - */ - public SessionMetadata getMetadata() { - return metadata; - } + /** + * To get session meta-data + */ + public SessionMetadata getMetadata() { + return metadata; + } - /** - * To set session meta-data - * - * @param metadata - */ - public void setMetadata(SessionMetadata metadata) { - this.metadata = metadata; - } + /** + * To set session meta-data + */ + public void setMetadata(SessionMetadata metadata) { + this.metadata = metadata; + } - /** {@inheritDoc} */ - @Override - public String toString() { - return "SessionContext [id=" + id + "]"; - } + /** + * {@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 a44f4c3..2b654aa 100644 --- a/src/main/java/tomcat/request/session/SessionMetadata.java +++ b/src/main/java/tomcat/request/session/SessionMetadata.java @@ -7,72 +7,58 @@ 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. + * + * This class is uses to store and retrieve the HTTP request session object meta-data. * * @author Ranjith Manickam * @since 2.0 */ 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 - * - * @return - */ - public byte[] getAttributesHash() { - return this.attributesHash; - } + /** + * To get session meta-data hash + */ + public byte[] getAttributesHash() { + return this.attributesHash; + } - /** - * To set session meta-data hash - * - * @param attributesHash - */ - 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 - * - * @param metadata - */ - 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 - * - * @param out - * @throws IOException - */ - 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 - * - * @param in - * @throws IOException - * @throws ClassNotFoundException - */ - 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; - } + /** + * 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 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 e304ebe..2988184 100644 --- a/src/main/java/tomcat/request/session/data/cache/DataCache.java +++ b/src/main/java/tomcat/request/session/data/cache/DataCache.java @@ -2,7 +2,7 @@ package tomcat.request.session.data.cache; /** * Tomcat clustering with Redis data-cache implementation. - * + * * API for Data cache. * * @author Ranjith Manickam @@ -10,49 +10,31 @@ package tomcat.request.session.data.cache; */ public interface DataCache { - /** - * To set value in data-cache - * - * @param key - * @param value - * @return - */ - byte[] set(String key, byte[] value); + /** + * To set value in data-cache + */ + byte[] set(String key, byte[] value); - /** - * To set value if key not exists in data-cache - * - * Returns If key exists = 0 else 1 - * - * @param key - * @param value - * @return - */ - Long setnx(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); - /** - * To expire the value based on key in data-cache - * - * @param key - * @param seconds - * @return - */ - Long expire(String key, int seconds); + /** + * To expire the value based on key in data-cache + */ + Long expire(String key, int seconds); - /** - * To get the value based on key from data-cache - * - * @param key - * @return - */ - byte[] get(String key); + /** + * To get the value based on key from data-cache + */ + byte[] get(String key); - /** - * To delete the value based on key from data-cache - * - * @param key - * @return - */ - Long delete(String key); + /** + * To delete the value based on key from data-cache + */ + 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 new file mode 100644 index 0000000..92b92f0 --- /dev/null +++ b/src/main/java/tomcat/request/session/data/cache/impl/RedisCacheUtil.java @@ -0,0 +1,157 @@ +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); + jedis.close(); + 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); + jedis.close(); + 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); + jedis.close(); + 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()); + jedis.close(); + 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); + jedis.close(); + 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 new file mode 100644 index 0000000..328c3f3 --- /dev/null +++ b/src/main/java/tomcat/request/session/data/cache/impl/RedisClusterCacheUtil.java @@ -0,0 +1,169 @@ +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 index 84aec5a..3745a8a 100644 --- a/src/main/java/tomcat/request/session/data/cache/impl/RedisConstants.java +++ b/src/main/java/tomcat/request/session/data/cache/impl/RedisConstants.java @@ -2,44 +2,44 @@ 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 - final String PROPERTIES_FILE = "redis-data-cache.properties"; + // redis properties file name + String PROPERTIES_FILE = "redis-data-cache.properties"; - // redis properties - final String HOSTS = "redis.hosts"; - final String CLUSTER_ENABLED = "redis.cluster.enabled"; + // redis properties + String HOSTS = "redis.hosts"; + String CLUSTER_ENABLED = "redis.cluster.enabled"; - final String MAX_ACTIVE = "redis.max.active"; - final String TEST_ONBORROW = "redis.test.onBorrow"; - final String TEST_ONRETURN = "redis.test.onReturn"; - final String MAX_IDLE = "redis.max.idle"; - final String MIN_IDLE = "redis.min.idle"; - final String TEST_WHILEIDLE = "redis.test.whileIdle"; - final String TEST_NUMPEREVICTION = "redis.test.numPerEviction"; - final String TIME_BETWEENEVICTION = "redis.time.betweenEviction"; + 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"; - final String PASSWORD = "redis.password"; - final String DATABASE = "redis.database"; - final String TIMEOUT = "redis.timeout"; + String PASSWORD = "redis.password"; + String DATABASE = "redis.database"; + String TIMEOUT = "redis.timeout"; - // redis property default values - final String DEFAULT_MAX_ACTIVE_VALUE = "10"; - final String DEFAULT_TEST_ONBORROW_VALUE = "true"; - final String DEFAULT_TEST_ONRETURN_VALUE = "true"; - final String DEFAULT_MAX_IDLE_VALUE = "5"; - final String DEFAULT_MIN_IDLE_VALUE = "1"; - final String DEFAULT_TEST_WHILEIDLE_VALUE = "true"; - final String DEFAULT_TEST_NUMPEREVICTION_VALUE = "10"; - final String DEFAULT_TIME_BETWEENEVICTION_VALUE = "60000"; - final String DEFAULT_CLUSTER_ENABLED = "false"; + // 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"; - final String CONN_FAILED_RETRY_MSG = "Jedis connection failed, retrying..."; + 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 index ad08616..db1e25a 100644 --- a/src/main/java/tomcat/request/session/data/cache/impl/RedisDataCache.java +++ b/src/main/java/tomcat/request/session/data/cache/impl/RedisDataCache.java @@ -16,478 +16,211 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import redis.clients.jedis.HostAndPort; -import redis.clients.jedis.Jedis; -import redis.clients.jedis.JedisCluster; -import redis.clients.jedis.JedisPool; 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.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 static DataCache dataCache; - private Log log = LogFactory.getLog(RedisDataCache.class); + private Log log = LogFactory.getLog(RedisDataCache.class); - public RedisDataCache() { - initialize(); - } + public RedisDataCache() { + initialize(); + } - /** {@inheritDoc} */ - @Override - public byte[] set(String key, byte[] value) { - return dataCache.set(key, value); - } + /** + * {@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 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 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 byte[] get(String key) { + return (key != null) ? dataCache.get(key) : null; + } - /** {@inheritDoc} */ - @Override - public Long delete(String key) { - return dataCache.delete(key); - } + /** + * {@inheritDoc} + */ + @Override + public Long delete(String key) { + return dataCache.delete(key); + } - /** - * To parse data-cache key - * - * @param key - * @return - */ - public static String parseDataCacheKey(String key) { - return key.replaceAll("\\s", "_"); - } + /** + * To parse data-cache key + */ + public static String parseDataCacheKey(String key) { + return key.replaceAll("\\s", "_"); + } - /** - * To initialize the data-cache - * - * @param properties - * @param filePath - */ - @SuppressWarnings("unchecked") - private void initialize() { - if (dataCache != null) { - return; - } - Properties properties = loadProperties(); + /** + * 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)); + 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 nodes = getJedisNodes(hosts, clusterEnabled); + String hosts = properties.getProperty(RedisConstants.HOSTS, + Protocol.DEFAULT_HOST.concat(":").concat(String.valueOf(Protocol.DEFAULT_PORT))); + Collection nodes = getJedisNodes(hosts, clusterEnabled); - String password = properties.getProperty(RedisConstants.PASSWORD); - password = (password != null && !password.isEmpty()) ? password : null; + 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 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; + 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)); - } - } + 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 - * - * @param properties - * @return - */ - 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); + /** + * 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 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); + 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 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); + 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); + 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); + 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; - } + long timeBetweenEviction = Long.parseLong(properties + .getProperty(RedisConstants.TIME_BETWEENEVICTION, + RedisConstants.DEFAULT_TIME_BETWEENEVICTION_VALUE)); + poolConfig.setTimeBetweenEvictionRunsMillis(timeBetweenEviction); + return poolConfig; + } - /** - * To get jedis nodes - * - * @param hosts - * @param clusterEnabled - * @return - */ - private Collection getJedisNodes(String hosts, boolean clusterEnabled) { - hosts = hosts.replaceAll("\\s", ""); - String[] hostPorts = hosts.split(","); + /** + * To get jedis nodes + */ + private Collection getJedisNodes(String hosts, boolean clusterEnabled) { + hosts = hosts.replaceAll("\\s", ""); + String[] hostPorts = hosts.split(","); - List node = null; - Set nodes = null; + List node = null; + Set nodes = null; - for (String hostPort : hostPorts) { - String[] hostPortArr = hostPort.split(":"); + 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; - } + 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 - * - * @param filePath - * @return - */ - 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); + /** + * 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; + 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 { - resourceStream.close(); - } - } catch (IOException ex) { - log.error("Error while loading task scheduler properties", ex); - } - return properties; - } - - /** - * Tomcat clustering with Redis data-cache implementation. - * - * Redis stand-alone mode data-cache implementation. - * - * @author Ranjith Manickam - * @since 2.0 - */ - private class RedisCacheUtil implements DataCache { - - private JedisPool pool; - - private static final int NUM_RETRIES = 3; - - private Log log = LogFactory.getLog(RedisCacheUtil.class); - - public 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); - jedis.close(); - 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); - jedis.close(); - 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); - jedis.close(); - 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()); - jedis.close(); - 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); - jedis.close(); - 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; - } - } - - /** - * Tomcat clustering with Redis data-cache implementation. - * - * Redis multiple node cluster data-cache implementation. - * - * @author Ranjith Manickam - * @since 2.0 - */ - private 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); - - public 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(); - } - } - } + 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/redis/SessionHandlerValve.java b/src/main/java/tomcat/request/session/redis/SessionHandlerValve.java index 3b9ee7a..dc4df2a 100644 --- a/src/main/java/tomcat/request/session/redis/SessionHandlerValve.java +++ b/src/main/java/tomcat/request/session/redis/SessionHandlerValve.java @@ -10,33 +10,33 @@ import org.apache.catalina.valves.ValveBase; /** * Tomcat clustering with Redis data-cache implementation. - * - * Valve that implements per-request session persistence. It is intended to be - * used with non-sticky load-balancers. + * + * Valve that implements per-request session persistence. It is intended to be used with non-sticky + * load-balancers. * * @author Ranjith Manickam * @since 2.0 */ public class SessionHandlerValve extends ValveBase { - private SessionManager manager; + private SessionManager manager; - /** - * To set session manager - * - * @param manager - */ - public void setSessionManager(SessionManager manager) { - this.manager = manager; - } + /** + * To set session manager + */ + public void setSessionManager(SessionManager manager) { + this.manager = manager; + } - /** {@inheritDoc} */ - @Override - public void invoke(Request request, Response response) throws IOException, ServletException { - try { - getNext().invoke(request, response); - } finally { - manager.afterRequest(request); - } - } + /** + * {@inheritDoc} + */ + @Override + public void invoke(Request request, Response response) throws IOException, ServletException { + try { + getNext().invoke(request, response); + } finally { + manager.afterRequest(request); + } + } } \ No newline at end of file diff --git a/src/main/java/tomcat/request/session/redis/SessionManager.java b/src/main/java/tomcat/request/session/redis/SessionManager.java index df8efda..60ca4d3 100644 --- a/src/main/java/tomcat/request/session/redis/SessionManager.java +++ b/src/main/java/tomcat/request/session/redis/SessionManager.java @@ -27,381 +27,385 @@ import tomcat.request.session.data.cache.impl.RedisDataCache; /** * Tomcat clustering with Redis data-cache implementation. - * - * Manager that implements per-request session persistence. It is intended to be - * used with non-sticky load-balancers. + * + * Manager that implements per-request session persistence. It is intended to be used with + * non-sticky load-balancers. * * @author Ranjith Manickam * @since 2.0 */ public class SessionManager extends ManagerBase implements Lifecycle { - private DataCache dataCache; + private DataCache dataCache; - protected SerializationUtil serializer; + protected SerializationUtil serializer; - protected ThreadLocal sessionContext = new ThreadLocal<>(); + protected ThreadLocal sessionContext = new ThreadLocal<>(); - protected SessionHandlerValve handlerValve; + protected SessionHandlerValve handlerValve; - protected Set sessionPolicy = EnumSet.of(SessionPolicy.DEFAULT); + protected Set sessionPolicy = EnumSet.of(SessionPolicy.DEFAULT); - private Log log = LogFactory.getLog(SessionManager.class); + private Log log = LogFactory.getLog(SessionManager.class); - enum SessionPolicy { - DEFAULT, SAVE_ON_CHANGE, ALWAYS_SAVE_AFTER_REQUEST; + enum SessionPolicy { + DEFAULT, SAVE_ON_CHANGE, ALWAYS_SAVE_AFTER_REQUEST; - static SessionPolicy fromName(String name) { - for (SessionPolicy policy : SessionPolicy.values()) { - if (policy.name().equalsIgnoreCase(name)) { - return policy; - } - } - throw new IllegalArgumentException("Invalid session policy [" + name + "]"); - } - } + static SessionPolicy fromName(String name) { + for (SessionPolicy policy : SessionPolicy.values()) { + if (policy.name().equalsIgnoreCase(name)) { + return policy; + } + } + throw new IllegalArgumentException("Invalid session policy [" + name + "]"); + } + } - /** - * To get session persist policies - * - * @return - */ - public String getSessionPersistPolicies() { - String policyStr = null; - for (SessionPolicy policy : this.sessionPolicy) { - policyStr = (policyStr == null) ? policy.name() : policyStr.concat(",").concat(policy.name()); - } - return policyStr; - } + /** + * To get session persist policies + */ + public String getSessionPersistPolicies() { + String policyStr = null; + for (SessionPolicy policy : this.sessionPolicy) { + policyStr = (policyStr == null) ? policy.name() : policyStr.concat(",").concat(policy.name()); + } + return policyStr; + } - /** - * To set session persist policies - * - * @param policyStr - */ - public void setSessionPersistPolicies(String policyStr) { - Set policySet = EnumSet.of(SessionPolicy.DEFAULT); - String[] policyArray = policyStr.split(","); + /** + * To set session persist policies + */ + public void setSessionPersistPolicies(String policyStr) { + Set policySet = EnumSet.of(SessionPolicy.DEFAULT); + String[] policyArray = policyStr.split(","); - for (String policy : policyArray) { - policySet.add(SessionPolicy.fromName(policy)); - } - this.sessionPolicy = policySet; - } + for (String policy : policyArray) { + policySet.add(SessionPolicy.fromName(policy)); + } + this.sessionPolicy = policySet; + } - /** - * @return - */ - public boolean getSaveOnChange() { - return this.sessionPolicy.contains(SessionPolicy.SAVE_ON_CHANGE); - } + public boolean getSaveOnChange() { + return this.sessionPolicy.contains(SessionPolicy.SAVE_ON_CHANGE); + } - /** - * @return - */ - public boolean getAlwaysSaveAfterRequest() { - return this.sessionPolicy.contains(SessionPolicy.ALWAYS_SAVE_AFTER_REQUEST); - } + public boolean getAlwaysSaveAfterRequest() { + return this.sessionPolicy.contains(SessionPolicy.ALWAYS_SAVE_AFTER_REQUEST); + } - /** {@inheritDoc} */ - @Override - public void addLifecycleListener(LifecycleListener listener) { - super.addLifecycleListener(listener); - } + /** + * {@inheritDoc} + */ + @Override + public void addLifecycleListener(LifecycleListener listener) { + super.addLifecycleListener(listener); + } - /** {@inheritDoc} */ - @Override - public LifecycleListener[] findLifecycleListeners() { - return super.findLifecycleListeners(); - } + /** + * {@inheritDoc} + */ + @Override + public LifecycleListener[] findLifecycleListeners() { + return super.findLifecycleListeners(); + } - /** {@inheritDoc} */ - @Override - public void removeLifecycleListener(LifecycleListener listener) { - super.removeLifecycleListener(listener); - } + /** + * {@inheritDoc} + */ + @Override + public void removeLifecycleListener(LifecycleListener listener) { + super.removeLifecycleListener(listener); + } - /** {@inheritDoc} */ - @Override - protected synchronized void startInternal() throws LifecycleException { - super.startInternal(); - super.setState(LifecycleState.STARTING); + /** + * {@inheritDoc} + */ + @Override + protected synchronized void startInternal() throws LifecycleException { + super.startInternal(); + super.setState(LifecycleState.STARTING); - boolean initializedValve = false; - Context context = getContextIns(); - for (Valve valve : context.getPipeline().getValves()) { - if (valve instanceof SessionHandlerValve) { - this.handlerValve = (SessionHandlerValve) valve; - this.handlerValve.setSessionManager(this); - initializedValve = true; - break; - } - } + boolean initializedValve = false; + Context context = getContextIns(); + for (Valve valve : context.getPipeline().getValves()) { + if (valve instanceof SessionHandlerValve) { + this.handlerValve = (SessionHandlerValve) valve; + this.handlerValve.setSessionManager(this); + initializedValve = true; + break; + } + } - if (!initializedValve) - throw new LifecycleException("Session handling valve is not initialized.."); + if (!initializedValve) { + throw new LifecycleException("Session handling valve is not initialized.."); + } - initialize(); + initialize(); - log.info("The sessions will expire after " + (getSessionTimeout(null)) + " seconds."); - context.setDistributable(true); - } + log.info("The sessions will expire after " + (getSessionTimeout(null)) + " seconds."); + context.setDistributable(true); + } - /** {@inheritDoc} */ - @Override - protected synchronized void stopInternal() throws LifecycleException { - super.setState(LifecycleState.STOPPING); - super.stopInternal(); - } + /** + * {@inheritDoc} + */ + @Override + protected synchronized void stopInternal() throws LifecycleException { + super.setState(LifecycleState.STOPPING); + super.stopInternal(); + } - /** {@inheritDoc} */ - @Override - public Session createSession(String sessionId) { - if (sessionId != null) { - sessionId = (this.dataCache.setnx(sessionId, SessionConstants.NULL_SESSION) == 0L) ? null : sessionId; - } else { - do { - sessionId = generateSessionId(); - } while (this.dataCache.setnx(sessionId, SessionConstants.NULL_SESSION) == 0L); - } + /** + * {@inheritDoc} + */ + @Override + public Session createSession(String sessionId) { + if (sessionId != null) { + sessionId = + (this.dataCache.setnx(sessionId, SessionConstants.NULL_SESSION) == 0L) ? null : sessionId; + } else { + do { + sessionId = generateSessionId(); + } while (this.dataCache.setnx(sessionId, SessionConstants.NULL_SESSION) == 0L); + } - Session session = (sessionId != null) ? (Session) createEmptySession() : null; - if (session != null) { - session.setId(sessionId); - session.setNew(true); - session.setValid(true); - session.setCreationTime(System.currentTimeMillis()); - session.setMaxInactiveInterval(getSessionTimeout(session)); - session.tellNew(); - } - setValues(sessionId, session, false, new SessionMetadata()); + Session session = (sessionId != null) ? createEmptySession() : null; + if (session != null) { + session.setId(sessionId); + session.setNew(true); + session.setValid(true); + session.setCreationTime(System.currentTimeMillis()); + session.setMaxInactiveInterval(getSessionTimeout(session)); + session.tellNew(); + } + setValues(sessionId, session, false, new SessionMetadata()); - if (session != null) { - try { - save(session, true); - } catch (Exception ex) { - log.error("Error occured while creating session..", ex); - setValues(null, null); - session = null; - } - } - return session; - } + if (session != null) { + try { + save(session, true); + } catch (Exception ex) { + log.error("Error occurred while creating session..", ex); + setValues(null, null); + session = null; + } + } + return session; + } - /** {@inheritDoc} */ - @Override - public Session createEmptySession() { - return new Session(this); - } + /** + * {@inheritDoc} + */ + @Override + public Session createEmptySession() { + return new Session(this); + } - /** {@inheritDoc} */ - @Override - public void add(org.apache.catalina.Session session) { - save(session, false); - } + /** + * {@inheritDoc} + */ + @Override + public void add(org.apache.catalina.Session session) { + save(session, false); + } - /** {@inheritDoc} */ - @Override - public Session findSession(String sessionId) throws IOException { - Session session = null; - if (sessionId != null && this.sessionContext.get() != null && sessionId.equals(this.sessionContext.get().getId())) { - session = this.sessionContext.get().getSession(); - } else { - byte[] data = this.dataCache.get(sessionId); + /** + * {@inheritDoc} + */ + @Override + public Session findSession(String sessionId) throws IOException { + Session session = null; + if (sessionId != null && this.sessionContext.get() != null && sessionId + .equals(this.sessionContext.get().getId())) { + session = this.sessionContext.get().getSession(); + } else { + byte[] data = this.dataCache.get(sessionId); - boolean isPersisted = false; - SessionMetadata metadata = null; - if (data == null) { - session = null; - metadata = null; - sessionId = null; - isPersisted = false; - } else { - if (Arrays.equals(SessionConstants.NULL_SESSION, data)) { - throw new IOException("NULL session data"); - } - try { - metadata = new SessionMetadata(); - Session newSession = (Session) createEmptySession(); - this.serializer.deserializeSessionData(data, newSession, metadata); + boolean isPersisted = false; + SessionMetadata metadata = null; + if (data == null) { + session = null; + metadata = null; + sessionId = null; + isPersisted = false; + } else { + if (Arrays.equals(SessionConstants.NULL_SESSION, data)) { + throw new IOException("NULL session data"); + } + try { + metadata = new SessionMetadata(); + Session newSession = createEmptySession(); + this.serializer.deserializeSessionData(data, newSession, metadata); - newSession.setId(sessionId); - newSession.access(); - newSession.setNew(false); - newSession.setValid(true); - newSession.resetDirtyTracking(); - newSession.setMaxInactiveInterval(getSessionTimeout(newSession)); + newSession.setId(sessionId); + newSession.access(); + newSession.setNew(false); + newSession.setValid(true); + newSession.resetDirtyTracking(); + newSession.setMaxInactiveInterval(getSessionTimeout(newSession)); - session = newSession; - isPersisted = true; - } catch (Exception ex) { - log.error("Error occured while de-serializing the session object..", ex); - } - } - setValues(sessionId, session, isPersisted, metadata); - } - return session; - } + session = newSession; + isPersisted = true; + } catch (Exception ex) { + log.error("Error occurred while de-serializing the session object..", ex); + } + } + setValues(sessionId, session, isPersisted, metadata); + } + return session; + } - /** {@inheritDoc} */ - @Override - public void remove(org.apache.catalina.Session session) { - remove(session, false); - } + /** + * {@inheritDoc} + */ + @Override + public void remove(org.apache.catalina.Session session) { + remove(session, false); + } - /** {@inheritDoc} */ - @Override - public void remove(org.apache.catalina.Session session, boolean update) { - this.dataCache.expire(session.getId(), 10); - } + /** + * {@inheritDoc} + */ + @Override + public void remove(org.apache.catalina.Session session, boolean update) { + this.dataCache.expire(session.getId(), 10); + } - /** {@inheritDoc} */ - @Override - public void load() throws ClassNotFoundException, IOException { - // Auto-generated method stub - } + /** + * {@inheritDoc} + */ + @Override + public void load() throws ClassNotFoundException, IOException { + // Auto-generated method stub + } - /** {@inheritDoc} */ - @Override - public void unload() throws IOException { - // Auto-generated method stub - } + /** + * {@inheritDoc} + */ + @Override + public void unload() throws IOException { + // Auto-generated method stub + } - /** - * To initialize the session manager - */ - private void initialize() { - try { - this.dataCache = new RedisDataCache(); + /** + * To initialize the session manager + */ + private void initialize() { + try { + this.dataCache = new RedisDataCache(); - this.serializer = new SerializationUtil(); - Context context = getContextIns(); - ClassLoader loader = (context != null && context.getLoader() != null) ? context.getLoader().getClassLoader() : null; - this.serializer.setClassLoader(loader); - } catch (Exception ex) { - log.error("Error occured while initializing the session manager..", ex); - throw ex; - } - } + this.serializer = new SerializationUtil(); + Context context = getContextIns(); + ClassLoader loader = + (context != null && context.getLoader() != null) ? context.getLoader().getClassLoader() + : null; + this.serializer.setClassLoader(loader); + } catch (Exception ex) { + log.error("Error occurred while initializing the session manager..", ex); + throw ex; + } + } - /** - * To save session object to data-cache - * - * @param session - * @param forceSave - */ - public void save(org.apache.catalina.Session session, boolean forceSave) { - try { - Boolean isPersisted; - Session newSession = (Session) session; - byte[] hash = (this.sessionContext.get() != null && this.sessionContext.get().getMetadata() != null) - ? this.sessionContext.get().getMetadata().getAttributesHash() : null; - byte[] currentHash = serializer.getSessionAttributesHashCode(newSession); + /** + * To save session object to data-cache + */ + public void save(org.apache.catalina.Session session, boolean forceSave) { + try { + Boolean isPersisted; + Session newSession = (Session) session; + byte[] hash = + (this.sessionContext.get() != null && this.sessionContext.get().getMetadata() != null) + ? this.sessionContext.get().getMetadata().getAttributesHash() : null; + byte[] currentHash = serializer.getSessionAttributesHashCode(newSession); - if (forceSave || newSession.isDirty() - || (isPersisted = (this.sessionContext.get() != null) ? this.sessionContext.get().isPersisted() : null) == null - || !isPersisted || !Arrays.equals(hash, currentHash)) { + if (forceSave || newSession.isDirty() + || (isPersisted = + (this.sessionContext.get() != null) ? this.sessionContext.get().isPersisted() : null) + == null + || !isPersisted || !Arrays.equals(hash, currentHash)) { - SessionMetadata metadata = new SessionMetadata(); - metadata.setAttributesHash(currentHash); + SessionMetadata metadata = new SessionMetadata(); + metadata.setAttributesHash(currentHash); - this.dataCache.set(newSession.getId(), serializer.serializeSessionData(newSession, metadata)); - newSession.resetDirtyTracking(); - setValues(true, metadata); - } + this.dataCache + .set(newSession.getId(), serializer.serializeSessionData(newSession, metadata)); + newSession.resetDirtyTracking(); + setValues(true, metadata); + } - int timeout = getSessionTimeout(newSession); - this.dataCache.expire(newSession.getId(), timeout); - log.trace("Session [" + newSession.getId() + "] expire in [" + timeout + "] seconds."); + int timeout = getSessionTimeout(newSession); + this.dataCache.expire(newSession.getId(), timeout); + log.trace("Session [" + newSession.getId() + "] expire in [" + timeout + "] seconds."); - } catch (IOException ex) { - log.error("Error occured while saving the session object in data cache..", ex); - } - } + } catch (IOException ex) { + log.error("Error occurred while saving the session object in data cache..", ex); + } + } - /** - * To process post request process - * - * @param request - */ - public void afterRequest(Request request) { - Session session = null; - try { - session = (this.sessionContext.get() != null) ? this.sessionContext.get().getSession() : null; - if (session != null) { - if (session.isValid()) - save(session, getAlwaysSaveAfterRequest()); - else - remove(session); - log.trace("Session object " + (session.isValid() ? "saved: " : "removed: ") + session.getId()); - } - } catch (Exception ex) { - log.error("Error occured while processing post request process..", ex); - } finally { - this.sessionContext.remove(); - log.trace("Session removed from ThreadLocal:" + ((session != null) ? session.getIdInternal() : "")); - } - } + /** + * To process post request process + */ + public void afterRequest(Request request) { + Session session = null; + try { + session = (this.sessionContext.get() != null) ? this.sessionContext.get().getSession() : null; + if (session != null) { + if (session.isValid()) { + save(session, getAlwaysSaveAfterRequest()); + } else { + remove(session); + } + log.trace( + "Session object " + (session.isValid() ? "saved: " : "removed: ") + session.getId()); + } + } catch (Exception ex) { + log.error("Error occurred while processing post request process..", ex); + } finally { + this.sessionContext.remove(); + log.trace( + "Session removed from ThreadLocal:" + ((session != null) ? session.getIdInternal() : "")); + } + } - /** - * @return - */ - private int getSessionTimeout(Session session) { - int timeout = getContextIns().getSessionTimeout() * 60; - int sessionTimeout = (session == null) ? 0 : session.getMaxInactiveInterval(); - return (sessionTimeout < timeout) ? ((timeout < 1800) ? 1800 : timeout) : sessionTimeout; - } + private int getSessionTimeout(Session session) { + int timeout = getContextIns().getSessionTimeout() * 60; + int sessionTimeout = (session == null) ? 0 : session.getMaxInactiveInterval(); + return (sessionTimeout < timeout) ? ((timeout < 1800) ? 1800 : timeout) : sessionTimeout; + } - /** - * @param sessionId - * @param session - */ - private void setValues(String sessionId, Session session) { - if (this.sessionContext.get() == null) { - this.sessionContext.set(new SessionContext()); - } - this.sessionContext.get().setId(sessionId); - this.sessionContext.get().setSession(session); - } + private void setValues(String sessionId, Session session) { + if (this.sessionContext.get() == null) { + this.sessionContext.set(new SessionContext()); + } + this.sessionContext.get().setId(sessionId); + this.sessionContext.get().setSession(session); + } - /** - * @param isPersisted - * @param metadata - */ - private void setValues(boolean isPersisted, SessionMetadata metadata) { - if (this.sessionContext.get() == null) { - this.sessionContext.set(new SessionContext()); - } - this.sessionContext.get().setMetadata(metadata); - this.sessionContext.get().setPersisted(isPersisted); - } + private void setValues(boolean isPersisted, SessionMetadata metadata) { + if (this.sessionContext.get() == null) { + this.sessionContext.set(new SessionContext()); + } + this.sessionContext.get().setMetadata(metadata); + this.sessionContext.get().setPersisted(isPersisted); + } - /** - * @param sessionId - * @param session - * @param isPersisted - * @param metadata - */ - private void setValues(String sessionId, Session session, boolean isPersisted, SessionMetadata metadata) { - setValues(sessionId, session); - setValues(isPersisted, metadata); - } + private void setValues(String sessionId, Session session, boolean isPersisted, + SessionMetadata metadata) { + setValues(sessionId, session); + setValues(isPersisted, metadata); + } - /** - * @return - */ - private Context getContextIns() { - try { - Method method = this.getClass().getSuperclass().getDeclaredMethod("getContext"); - return (Context) method.invoke(this); - } catch (Exception ex) { - try { - Method method = this.getClass().getSuperclass().getDeclaredMethod("getContainer"); - return (Context) method.invoke(this); - } catch (Exception ex2) { - log.error("Error in getContext", ex2); - } - } - return null; - } + private Context getContextIns() { + try { + Method method = this.getClass().getSuperclass().getDeclaredMethod("getContext"); + return (Context) method.invoke(this); + } catch (Exception ex) { + try { + Method method = this.getClass().getSuperclass().getDeclaredMethod("getContainer"); + return (Context) method.invoke(this); + } catch (Exception ex2) { + log.error("Error in getContext", ex2); + } + } + throw new RuntimeException("Error occurred while creating container instance"); + } }