diff --git a/.gitignore b/.gitignore
index 982a41f6..faea3c33 100644
--- a/.gitignore
+++ b/.gitignore
@@ -6,3 +6,4 @@ example-app/.gradle/*
.rspec
*.iml
.idea/*
+gradle*
\ No newline at end of file
diff --git a/build.gradle b/build.gradle
index 2bd0db6a..e095fdb1 100644
--- a/build.gradle
+++ b/build.gradle
@@ -1,11 +1,13 @@
apply plugin: 'java'
-apply plugin: 'maven'
-apply plugin: 'signing'
group = 'com.orangefunction'
-version = '2.0.0'
+version = '2.1.1'
repositories {
+ mavenLocal()
+ maven {
+ url "https://maven.aliyun.com/nexus/content/groups/public"
+ }
mavenCentral()
}
@@ -15,10 +17,9 @@ compileJava {
}
dependencies {
- compile group: 'org.apache.tomcat', name: 'tomcat-catalina', version: '7.0.27'
+ compile group: 'org.apache.tomcat', name: 'tomcat-catalina', version: '8.5.31'
compile group: 'redis.clients', name: 'jedis', version: '2.5.2'
compile group: 'org.apache.commons', name: 'commons-pool2', version: '2.2'
- //compile group: 'commons-codec', name: 'commons-codec', version: '1.9'
testCompile group: 'junit', name: 'junit', version: '4.+'
testCompile 'org.hamcrest:hamcrest-core:1.3'
@@ -27,73 +28,3 @@ dependencies {
testCompile group: 'org.apache.tomcat', name: 'tomcat-coyote', version: '7.0.27'
}
-task javadocJar(type: Jar, dependsOn: javadoc) {
- classifier = 'javadoc'
- from 'build/docs/javadoc'
-}
-
-task sourcesJar(type: Jar) {
- from sourceSets.main.allSource
- classifier = 'sources'
-}
-
-artifacts {
- archives jar
-
- archives javadocJar
- archives sourcesJar
-}
-
-signing {
- sign configurations.archives
-}
-
-uploadArchives {
- repositories {
- mavenDeployer {
- beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) }
-
- repository(url: "https://oss.sonatype.org/service/local/staging/deploy/maven2/") {
- authentication(userName: sonatypeUsername, password: sonatypePassword)
- }
- //repository(url: "https://oss.sonatype.org/content/repositories/snapshots") {
- // authentication(userName: sonatypeUsername, password: sonatypePassword)
- //}
-
- pom.project {
- name 'tomcat-redis-session-manager'
- packaging 'jar'
- description 'Tomcat Redis Session Manager is a Tomcat extension to store sessions in Redis'
- url 'https://github.com/jcoleman/tomcat-redis-session-manager'
-
- issueManagement {
- url 'https://github.com:jcoleman/tomcat-redis-session-manager/issues'
- system 'GitHub Issues'
- }
-
- scm {
- url 'https://github.com:jcoleman/tomcat-redis-session-manager'
- connection 'scm:git:git://github.com/jcoleman/tomcat-redis-session-manager.git'
- developerConnection 'scm:git:git@github.com:jcoleman/tomcat-redis-session-manager.git'
- }
-
- licenses {
- license {
- name 'MIT'
- url 'http://opensource.org/licenses/MIT'
- distribution 'repo'
- }
- }
-
- developers {
- developer {
- id 'jcoleman'
- name 'James Coleman'
- email 'jtc331@gmail.com'
- url 'https://github.com/jcoleman'
- }
- }
- }
- }
- }
-}
diff --git a/example-app/build.gradle b/example-app/build.gradle
index 6f6690cb..ee653bf7 100644
--- a/example-app/build.gradle
+++ b/example-app/build.gradle
@@ -4,6 +4,10 @@ apply plugin: 'war'
version = '0.1'
repositories {
+ mavenLocal()
+ maven {
+ url "https://maven.aliyun.com/nexus/content/groups/public"
+ }
mavenCentral()
}
diff --git a/src/main/java/com/orangefunction/tomcat/redissessions/JavaSerializer.java b/src/main/java/com/orangefunction/tomcat/redissessions/JavaSerializer.java
index 4cfedff4..4c816547 100644
--- a/src/main/java/com/orangefunction/tomcat/redissessions/JavaSerializer.java
+++ b/src/main/java/com/orangefunction/tomcat/redissessions/JavaSerializer.java
@@ -1,81 +1,89 @@
package com.orangefunction.tomcat.redissessions;
import org.apache.catalina.util.CustomObjectInputStream;
+import org.apache.juli.logging.Log;
+import org.apache.juli.logging.LogFactory;
-import javax.servlet.http.HttpSession;
-
-import java.util.Enumeration;
-import java.util.HashMap;
import java.io.*;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
+import java.util.Enumeration;
+import java.util.HashMap;
-import org.apache.juli.logging.Log;
-import org.apache.juli.logging.LogFactory;
-
+/**
+ *
Title: Godfather1103's Github
+ * Copyright: Copyright (c) 2020
+ * Company: https://github.com/godfather1103
+ *
+ * @author 作者: Jack Chu E-mail: chuchuanbao@gmail.com
+ * 创建时间:2020-07-01 17:20
+ * @version 1.0
+ * @since 1.0
+ */
public class JavaSerializer implements Serializer {
- private ClassLoader loader;
+ private ClassLoader loader;
- private final Log log = LogFactory.getLog(JavaSerializer.class);
+ private final Log log = LogFactory.getLog(JavaSerializer.class);
- @Override
- public void setClassLoader(ClassLoader loader) {
- this.loader = loader;
- }
-
- public byte[] attributesHashFrom(RedisSession session) throws IOException {
- HashMap attributes = new HashMap();
- for (Enumeration enumerator = session.getAttributeNames(); enumerator.hasMoreElements();) {
- String key = enumerator.nextElement();
- attributes.put(key, session.getAttribute(key));
+ @Override
+ public void setClassLoader(ClassLoader loader) {
+ this.loader = loader;
}
- byte[] serialized = null;
+ @Override
+ public byte[] attributesHashFrom(RedisSession session) throws IOException {
+ HashMap 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();
- }
+ byte[] serialized = null;
- MessageDigest digester = null;
- try {
- digester = MessageDigest.getInstance("MD5");
- } catch (NoSuchAlgorithmException e) {
- log.error("Unable to get MessageDigest instance for MD5");
+ try (
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ ObjectOutputStream oos = new ObjectOutputStream(new BufferedOutputStream(bos));
+ ) {
+ oos.writeUnshared(attributes);
+ oos.flush();
+ serialized = bos.toByteArray();
+ }
+
+ MessageDigest digester = null;
+ try {
+ digester = MessageDigest.getInstance("MD5");
+ } catch (NoSuchAlgorithmException e) {
+ log.error("Unable to get MessageDigest instance for MD5");
+ }
+ return digester.digest(serialized);
}
- return digester.digest(serialized);
- }
- @Override
- public byte[] serializeFrom(RedisSession session, SessionSerializationMetadata metadata) throws IOException {
- byte[] serialized = null;
+ @Override
+ public byte[] serializeFrom(RedisSession session, SessionSerializationMetadata 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();
- }
+ 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 serialized;
+ }
- @Override
- public void deserializeInto(byte[] data, RedisSession session, SessionSerializationMetadata metadata) throws IOException, ClassNotFoundException {
- try(
- BufferedInputStream bis = new BufferedInputStream(new ByteArrayInputStream(data));
- ObjectInputStream ois = new CustomObjectInputStream(bis, loader);
- ) {
- SessionSerializationMetadata serializedMetadata = (SessionSerializationMetadata)ois.readObject();
- metadata.copyFieldsFrom(serializedMetadata);
- session.readObjectData(ois);
+ @Override
+ public void deserializeInto(byte[] data, RedisSession session, SessionSerializationMetadata metadata) throws IOException, ClassNotFoundException {
+ try (
+ BufferedInputStream bis = new BufferedInputStream(new ByteArrayInputStream(data));
+ ObjectInputStream ois = new CustomObjectInputStream(bis, loader);
+ ) {
+ SessionSerializationMetadata serializedMetadata = (SessionSerializationMetadata) ois.readObject();
+ metadata.copyFieldsFrom(serializedMetadata);
+ session.readObjectData(ois);
+ }
}
- }
}
diff --git a/src/main/java/com/orangefunction/tomcat/redissessions/RedisSession.java b/src/main/java/com/orangefunction/tomcat/redissessions/RedisSession.java
index 0fa742d8..8ec6bbbf 100644
--- a/src/main/java/com/orangefunction/tomcat/redissessions/RedisSession.java
+++ b/src/main/java/com/orangefunction/tomcat/redissessions/RedisSession.java
@@ -1,14 +1,14 @@
package com.orangefunction.tomcat.redissessions;
-import java.security.Principal;
import org.apache.catalina.Manager;
import org.apache.catalina.session.StandardSession;
-import java.util.HashMap;
-import java.io.IOException;
-
import org.apache.juli.logging.Log;
import org.apache.juli.logging.LogFactory;
+import java.io.IOException;
+import java.security.Principal;
+import java.util.HashMap;
+
public class RedisSession extends StandardSession {
diff --git a/src/main/java/com/orangefunction/tomcat/redissessions/RedisSessionHandlerValve.java b/src/main/java/com/orangefunction/tomcat/redissessions/RedisSessionHandlerValve.java
index 13da6765..31be292a 100644
--- a/src/main/java/com/orangefunction/tomcat/redissessions/RedisSessionHandlerValve.java
+++ b/src/main/java/com/orangefunction/tomcat/redissessions/RedisSessionHandlerValve.java
@@ -1,16 +1,14 @@
package com.orangefunction.tomcat.redissessions;
-import org.apache.catalina.Session;
import org.apache.catalina.connector.Request;
import org.apache.catalina.connector.Response;
import org.apache.catalina.valves.ValveBase;
+import org.apache.juli.logging.Log;
+import org.apache.juli.logging.LogFactory;
import javax.servlet.ServletException;
import java.io.IOException;
-import org.apache.juli.logging.Log;
-import org.apache.juli.logging.LogFactory;
-
public class RedisSessionHandlerValve extends ValveBase {
private final Log log = LogFactory.getLog(RedisSessionManager.class);
diff --git a/src/main/java/com/orangefunction/tomcat/redissessions/RedisSessionManager.java b/src/main/java/com/orangefunction/tomcat/redissessions/RedisSessionManager.java
index 2b58a261..a297d98c 100644
--- a/src/main/java/com/orangefunction/tomcat/redissessions/RedisSessionManager.java
+++ b/src/main/java/com/orangefunction/tomcat/redissessions/RedisSessionManager.java
@@ -1,358 +1,403 @@
package com.orangefunction.tomcat.redissessions;
-import org.apache.catalina.Lifecycle;
-import org.apache.catalina.LifecycleException;
-import org.apache.catalina.LifecycleListener;
-import org.apache.catalina.util.LifecycleSupport;
-import org.apache.catalina.LifecycleState;
-import org.apache.catalina.Loader;
-import org.apache.catalina.Valve;
-import org.apache.catalina.Session;
+import org.apache.catalina.*;
import org.apache.catalina.session.ManagerBase;
-
-import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
-import org.apache.commons.pool2.impl.BaseObjectPoolConfig;
-
+import org.apache.juli.logging.Log;
+import org.apache.juli.logging.LogFactory;
+import org.apache.tomcat.util.ExceptionUtils;
+import redis.clients.jedis.*;
import redis.clients.util.Pool;
-import redis.clients.jedis.JedisPool;
-import redis.clients.jedis.JedisSentinelPool;
-import redis.clients.jedis.JedisPoolConfig;
-import redis.clients.jedis.Jedis;
-import redis.clients.jedis.Protocol;
+import java.beans.PropertyChangeSupport;
import java.io.IOException;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.Enumeration;
-import java.util.Set;
-import java.util.EnumSet;
-import java.util.HashSet;
-import java.util.Iterator;
-
-import org.apache.juli.logging.Log;
-import org.apache.juli.logging.LogFactory;
+import java.util.*;
public class RedisSessionManager extends ManagerBase implements Lifecycle {
- enum SessionPersistPolicy {
- DEFAULT,
- SAVE_ON_CHANGE,
- ALWAYS_SAVE_AFTER_REQUEST;
+ enum SessionPersistPolicy {
+ DEFAULT,
+ SAVE_ON_CHANGE,
+ ALWAYS_SAVE_AFTER_REQUEST;
+
+ static SessionPersistPolicy fromName(String name) {
+ for (SessionPersistPolicy policy : SessionPersistPolicy.values()) {
+ if (policy.name().equalsIgnoreCase(name)) {
+ return policy;
+ }
+ }
+ throw new IllegalArgumentException("Invalid session persist policy [" + name + "]. Must be one of " + Arrays.asList(SessionPersistPolicy.values()) + ".");
+ }
+ }
+
+ protected byte[] NULL_SESSION = "null".getBytes();
+
+ private final Log log = LogFactory.getLog(RedisSessionManager.class);
+
+ protected String host = "localhost";
+ protected int port = 6379;
+ protected int database = 0;
+ protected String password = null;
+ protected int timeout = Protocol.DEFAULT_TIMEOUT;
+ protected String sentinelMaster = null;
+ Set sentinelSet = null;
+
+ protected Pool connectionPool;
+ protected JedisPoolConfig connectionPoolConfig = new JedisPoolConfig();
+
+ protected RedisSessionHandlerValve handlerValve;
+ protected ThreadLocal currentSession = new ThreadLocal<>();
+ protected ThreadLocal currentSessionSerializationMetadata = new ThreadLocal<>();
+ protected ThreadLocal currentSessionId = new ThreadLocal<>();
+ protected ThreadLocal currentSessionIsPersisted = new ThreadLocal<>();
+ protected Serializer serializer;
+
+ protected static String name = "RedisSessionManager";
+
+ protected String serializationStrategyClass = "com.orangefunction.tomcat.redissessions.JavaSerializer";
+
+ protected EnumSet sessionPersistPoliciesSet = EnumSet.of(SessionPersistPolicy.DEFAULT);
+
+ protected String maxInactiveInterval;
+
+ public void setMaxInactiveInterval(String maxInactiveInterval) {
+ this.maxInactiveInterval = maxInactiveInterval;
+ }
+
+ /**
+ * The lifecycle event support for this component.
+ */
+
+ public String getHost() {
+ return host;
+ }
+
+ public void setHost(String host) {
+ this.host = host;
+ }
+
+ public int getPort() {
+ return port;
+ }
+
+ public void setPort(int port) {
+ this.port = port;
+ }
- static SessionPersistPolicy fromName(String name) {
- for (SessionPersistPolicy policy : SessionPersistPolicy.values()) {
- if (policy.name().equalsIgnoreCase(name)) {
- return policy;
+ public int getDatabase() {
+ return database;
+ }
+
+ public void setDatabase(int database) {
+ this.database = database;
+ }
+
+ public int getTimeout() {
+ return timeout;
+ }
+
+ public void setTimeout(int timeout) {
+ this.timeout = timeout;
+ }
+
+ public String getPassword() {
+ return password;
+ }
+
+ public void setPassword(String password) {
+ this.password = password;
+ }
+
+ public void setSerializationStrategyClass(String strategy) {
+ this.serializationStrategyClass = strategy;
+ }
+
+ public String getSessionPersistPolicies() {
+ StringBuilder policies = new StringBuilder();
+ for (Iterator iter = this.sessionPersistPoliciesSet.iterator(); iter.hasNext(); ) {
+ SessionPersistPolicy policy = iter.next();
+ policies.append(policy.name());
+ if (iter.hasNext()) {
+ policies.append(",");
+ }
}
- }
- throw new IllegalArgumentException("Invalid session persist policy [" + name + "]. Must be one of " + Arrays.asList(SessionPersistPolicy.values())+ ".");
+ return policies.toString();
}
- }
- protected byte[] NULL_SESSION = "null".getBytes();
+ public void setSessionPersistPolicies(String sessionPersistPolicies) {
+ String[] policyArray = sessionPersistPolicies.split(",");
+ EnumSet policySet = EnumSet.of(SessionPersistPolicy.DEFAULT);
+ for (String policyName : policyArray) {
+ SessionPersistPolicy policy = SessionPersistPolicy.fromName(policyName);
+ policySet.add(policy);
+ }
+ this.sessionPersistPoliciesSet = policySet;
+ }
- private final Log log = LogFactory.getLog(RedisSessionManager.class);
+ public boolean getSaveOnChange() {
+ return this.sessionPersistPoliciesSet.contains(SessionPersistPolicy.SAVE_ON_CHANGE);
+ }
- protected String host = "localhost";
- protected int port = 6379;
- protected int database = 0;
- protected String password = null;
- protected int timeout = Protocol.DEFAULT_TIMEOUT;
- protected String sentinelMaster = null;
- Set sentinelSet = null;
-
- protected Pool connectionPool;
- protected JedisPoolConfig connectionPoolConfig = new JedisPoolConfig();
+ public boolean getAlwaysSaveAfterRequest() {
+ return this.sessionPersistPoliciesSet.contains(SessionPersistPolicy.ALWAYS_SAVE_AFTER_REQUEST);
+ }
- protected RedisSessionHandlerValve handlerValve;
- protected ThreadLocal currentSession = new ThreadLocal<>();
- protected ThreadLocal currentSessionSerializationMetadata = new ThreadLocal<>();
- protected ThreadLocal currentSessionId = new ThreadLocal<>();
- protected ThreadLocal currentSessionIsPersisted = new ThreadLocal<>();
- protected Serializer serializer;
+ public String getSentinels() {
+ StringBuilder sentinels = new StringBuilder();
+ for (Iterator iter = this.sentinelSet.iterator(); iter.hasNext(); ) {
+ sentinels.append(iter.next());
+ if (iter.hasNext()) {
+ sentinels.append(",");
+ }
+ }
+ return sentinels.toString();
+ }
- protected static String name = "RedisSessionManager";
+ public void setSentinels(String sentinels) {
+ if (null == sentinels) {
+ sentinels = "";
+ }
- protected String serializationStrategyClass = "com.orangefunction.tomcat.redissessions.JavaSerializer";
+ String[] sentinelArray = sentinels.split(",");
+ this.sentinelSet = new HashSet(Arrays.asList(sentinelArray));
+ }
- protected EnumSet sessionPersistPoliciesSet = EnumSet.of(SessionPersistPolicy.DEFAULT);
+ public Set getSentinelSet() {
+ return this.sentinelSet;
+ }
- /**
- * The lifecycle event support for this component.
- */
- protected LifecycleSupport lifecycle = new LifecycleSupport(this);
+ public String getSentinelMaster() {
+ return this.sentinelMaster;
+ }
- public String getHost() {
- return host;
- }
+ public void setSentinelMaster(String master) {
+ this.sentinelMaster = master;
+ }
- public void setHost(String host) {
- this.host = host;
- }
+ @Override
+ public int getRejectedSessions() {
+ // Essentially do nothing.
+ return 0;
+ }
- public int getPort() {
- return port;
- }
+ public void setRejectedSessions(int i) {
+ // Do nothing.
+ }
- public void setPort(int port) {
- this.port = port;
- }
+ protected Jedis acquireConnection() {
+ Jedis jedis = connectionPool.getResource();
- public int getDatabase() {
- return database;
- }
+ if (getDatabase() != 0) {
+ jedis.select(getDatabase());
+ }
- public void setDatabase(int database) {
- this.database = database;
- }
+ return jedis;
+ }
- public int getTimeout() {
- return timeout;
- }
+ protected void returnConnection(Jedis jedis, Boolean error) {
+ if (error) {
+ connectionPool.returnBrokenResource(jedis);
+ } else {
+ connectionPool.returnResource(jedis);
+ }
+ }
- public void setTimeout(int timeout) {
- this.timeout = timeout;
- }
+ protected void returnConnection(Jedis jedis) {
+ returnConnection(jedis, false);
+ }
- public String getPassword() {
- return password;
- }
+ @Override
+ public void load() throws ClassNotFoundException, IOException {
- public void setPassword(String password) {
- this.password = password;
- }
+ }
- public void setSerializationStrategyClass(String strategy) {
- this.serializationStrategyClass = strategy;
- }
+ @Override
+ public void unload() throws IOException {
- public String getSessionPersistPolicies() {
- StringBuilder policies = new StringBuilder();
- for (Iterator iter = this.sessionPersistPoliciesSet.iterator(); iter.hasNext();) {
- SessionPersistPolicy policy = iter.next();
- policies.append(policy.name());
- if (iter.hasNext()) {
- policies.append(",");
- }
}
- return policies.toString();
- }
- public void setSessionPersistPolicies(String sessionPersistPolicies) {
- String[] policyArray = sessionPersistPolicies.split(",");
- EnumSet policySet = EnumSet.of(SessionPersistPolicy.DEFAULT);
- for (String policyName : policyArray) {
- SessionPersistPolicy policy = SessionPersistPolicy.fromName(policyName);
- policySet.add(policy);
+ protected final PropertyChangeSupport support =
+ new PropertyChangeSupport(this);
+
+ private LifecycleListener listeners[] = new LifecycleListener[0];
+
+ private final Object listenersLock = new Object(); // Lock object for changes to listeners
+
+ /**
+ * Add a lifecycle event listener to this component.
+ *
+ * @param listener The listener to add
+ */
+ @Override
+ public void addLifecycleListener(LifecycleListener listener) {
+ synchronized (listenersLock) {
+ LifecycleListener results[] =
+ new LifecycleListener[listeners.length + 1];
+ for (int i = 0; i < listeners.length; i++) {
+ results[i] = listeners[i];
+ }
+ results[listeners.length] = listener;
+ listeners = results;
+ }
+ }
+
+ /**
+ * Get the lifecycle listeners associated with this lifecycle. If this
+ * Lifecycle has no listeners registered, a zero-length array is returned.
+ */
+ @Override
+ public LifecycleListener[] findLifecycleListeners() {
+ return listeners;
+ }
+
+
+ /**
+ * Remove a lifecycle event listener from this component.
+ *
+ * @param listener The listener to remove
+ */
+ @Override
+ public void removeLifecycleListener(LifecycleListener listener) {
+ synchronized (listenersLock) {
+ int n = -1;
+ for (int i = 0; i < listeners.length; i++) {
+ if (listeners[i] == listener) {
+ n = i;
+ break;
+ }
+ }
+ if (n < 0) {
+ return;
+ }
+ LifecycleListener results[] =
+ new LifecycleListener[listeners.length - 1];
+ int j = 0;
+ for (int i = 0; i < listeners.length; i++) {
+ if (i != n) {
+ results[j++] = listeners[i];
+ }
+ }
+ listeners = results;
+ }
}
- this.sessionPersistPoliciesSet = policySet;
- }
-
- public boolean getSaveOnChange() {
- return this.sessionPersistPoliciesSet.contains(SessionPersistPolicy.SAVE_ON_CHANGE);
- }
-
- public boolean getAlwaysSaveAfterRequest() {
- return this.sessionPersistPoliciesSet.contains(SessionPersistPolicy.ALWAYS_SAVE_AFTER_REQUEST);
- }
-
- public String getSentinels() {
- StringBuilder sentinels = new StringBuilder();
- for (Iterator iter = this.sentinelSet.iterator(); iter.hasNext();) {
- sentinels.append(iter.next());
- if (iter.hasNext()) {
- sentinels.append(",");
- }
- }
- return sentinels.toString();
- }
-
- public void setSentinels(String sentinels) {
- if (null == sentinels) {
- sentinels = "";
- }
-
- String[] sentinelArray = sentinels.split(",");
- this.sentinelSet = new HashSet(Arrays.asList(sentinelArray));
- }
-
- public Set getSentinelSet() {
- return this.sentinelSet;
- }
-
- public String getSentinelMaster() {
- return this.sentinelMaster;
- }
-
- public void setSentinelMaster(String master) {
- this.sentinelMaster = master;
- }
-
- @Override
- public int getRejectedSessions() {
- // Essentially do nothing.
- return 0;
- }
-
- public void setRejectedSessions(int i) {
- // Do nothing.
- }
-
- protected Jedis acquireConnection() {
- Jedis jedis = connectionPool.getResource();
-
- if (getDatabase() != 0) {
- jedis.select(getDatabase());
- }
-
- return jedis;
- }
-
- protected void returnConnection(Jedis jedis, Boolean error) {
- if (error) {
- connectionPool.returnBrokenResource(jedis);
- } else {
- connectionPool.returnResource(jedis);
- }
- }
-
- protected void returnConnection(Jedis jedis) {
- returnConnection(jedis, false);
- }
-
- @Override
- public void load() throws ClassNotFoundException, IOException {
-
- }
-
- @Override
- public void unload() throws IOException {
-
- }
-
- /**
- * Add a lifecycle event listener to this component.
- *
- * @param listener The listener to add
- */
- @Override
- public void addLifecycleListener(LifecycleListener listener) {
- lifecycle.addLifecycleListener(listener);
- }
-
- /**
- * Get the lifecycle listeners associated with this lifecycle. If this
- * Lifecycle has no listeners registered, a zero-length array is returned.
- */
- @Override
- public LifecycleListener[] findLifecycleListeners() {
- return lifecycle.findLifecycleListeners();
- }
-
-
- /**
- * Remove a lifecycle event listener from this component.
- *
- * @param listener The listener to remove
- */
- @Override
- public void removeLifecycleListener(LifecycleListener listener) {
- lifecycle.removeLifecycleListener(listener);
- }
-
- /**
- * Start this component and implement the requirements
- * of {@link org.apache.catalina.util.LifecycleBase#startInternal()}.
- *
- * @exception LifecycleException if this component detects a fatal error
- * that prevents this component from being used
- */
- @Override
- protected synchronized void startInternal() throws LifecycleException {
- super.startInternal();
- setState(LifecycleState.STARTING);
-
- Boolean attachedToValve = false;
- for (Valve valve : getContainer().getPipeline().getValves()) {
- if (valve instanceof RedisSessionHandlerValve) {
- this.handlerValve = (RedisSessionHandlerValve) valve;
- this.handlerValve.setRedisSessionManager(this);
- log.info("Attached to RedisSessionHandlerValve");
- attachedToValve = true;
- break;
- }
- }
-
- if (!attachedToValve) {
- String error = "Unable to attach to session handling valve; sessions cannot be saved after the request without the valve starting properly.";
- log.fatal(error);
- throw new LifecycleException(error);
- }
-
- try {
- initializeSerializer();
- } catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) {
- log.fatal("Unable to load serializer", e);
- throw new LifecycleException(e);
- }
-
- log.info("Will expire sessions after " + getMaxInactiveInterval() + " seconds");
-
- initializeDatabaseConnection();
-
- setDistributable(true);
- }
-
-
- /**
- * Stop this component and implement the requirements
- * of {@link org.apache.catalina.util.LifecycleBase#stopInternal()}.
- *
- * @exception LifecycleException if this component detects a fatal error
- * that prevents this component from being used
- */
- @Override
- protected synchronized void stopInternal() throws LifecycleException {
- if (log.isDebugEnabled()) {
- log.debug("Stopping");
- }
-
- setState(LifecycleState.STOPPING);
-
- try {
- connectionPool.destroy();
- } catch(Exception e) {
- // Do nothing.
- }
-
- // Require a new random number generator if we are restarted
- super.stopInternal();
- }
-
- @Override
- public Session createSession(String requestedSessionId) {
- RedisSession session = null;
- String sessionId = null;
- String jvmRoute = getJvmRoute();
-
- Boolean error = true;
- Jedis jedis = null;
- try {
- jedis = acquireConnection();
-
- // Ensure generation of a unique session identifier.
- if (null != requestedSessionId) {
- sessionId = sessionIdWithJvmRoute(requestedSessionId, jvmRoute);
- if (jedis.setnx(sessionId.getBytes(), NULL_SESSION) == 0L) {
- sessionId = null;
- }
- } else {
- do {
- sessionId = sessionIdWithJvmRoute(generateSessionId(), jvmRoute);
- } while (jedis.setnx(sessionId.getBytes(), NULL_SESSION) == 0L); // 1 = key set; 0 = key already existed
- }
+ /**
+ * Start this component and implement the requirements
+ * of {@link org.apache.catalina.util.LifecycleBase#startInternal()}.
+ *
+ * @throws LifecycleException if this component detects a fatal error
+ * that prevents this component from being used
+ */
+ @Override
+ protected synchronized void startInternal() throws LifecycleException {
+ super.startInternal();
+
+ setState(LifecycleState.STARTING);
+
+ Boolean attachedToValve = false;
+ for (Valve valve : getContext().getPipeline().getValves()) {
+ if (valve instanceof RedisSessionHandlerValve) {
+ this.handlerValve = (RedisSessionHandlerValve) valve;
+ this.handlerValve.setRedisSessionManager(this);
+ log.info("Attached to RedisSessionHandlerValve");
+ attachedToValve = true;
+ break;
+ }
+ }
+
+ if (!attachedToValve) {
+ String error = "Unable to attach to session handling valve; sessions cannot be saved after the request without the valve starting properly.";
+ log.fatal(error);
+ throw new LifecycleException(error);
+ }
+
+ try {
+ initializeSerializer();
+ } catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) {
+ log.fatal("Unable to load serializer", e);
+ throw new LifecycleException(e);
+ }
+
+ log.info("Will expire sessions after " + getMaxInactiveInterval() + " seconds");
+
+ initializeDatabaseConnection();
+ getContext().setDistributable(true);
+ }
+
+
+ @Override
+ public void expireSession(String sessionId) {
+ try {
+ Session session = findSession(sessionId);
+ if (session != null) {
+ session.expire();
+ }
+ } catch (IOException e) {
+ log.error(e.getMessage(), e);
+ }
+ }
+
+ /**
+ * Stop this component and implement the requirements
+ * of {@link org.apache.catalina.util.LifecycleBase#stopInternal()}.
+ *
+ * @throws LifecycleException if this component detects a fatal error
+ * that prevents this component from being used
+ */
+ @Override
+ protected synchronized void stopInternal() throws LifecycleException {
+ if (log.isDebugEnabled()) {
+ log.debug("Stopping");
+ }
+
+ setState(LifecycleState.STOPPING);
+ // Expire all active sessions
+ Session sessions[] = findSessions();
+ for (int i = 0; i < sessions.length; i++) {
+ Session session = sessions[i];
+ try {
+ if (session.isValid()) {
+ session.expire();
+ }
+ } catch (Throwable t) {
+ ExceptionUtils.handleThrowable(t);
+ } finally {
+ // Measure against memory leaking if references to the session
+ // object are kept in a shared field somewhere
+ session.recycle();
+ }
+ }
+ try {
+ connectionPool.destroy();
+ } catch (Exception e) {
+ // Do nothing.
+ }
+ // Require a new random number generator if we are restarted
+ super.stopInternal();
+ }
+
+ @Override
+ public Session createSession(String requestedSessionId) {
+ RedisSession session = null;
+ String sessionId = null;
+ String jvmRoute = getJvmRoute();
+
+ Boolean error = true;
+ Jedis jedis = null;
+ try {
+ jedis = acquireConnection();
+
+ // Ensure generation of a unique session identifier.
+ if (null != requestedSessionId) {
+ sessionId = sessionIdWithJvmRoute(requestedSessionId, jvmRoute);
+ if (jedis.hsetnx(getClassName().getBytes(), sessionId.getBytes(), NULL_SESSION) == 0L) {
+ sessionId = null;
+ }
+ } else {
+ do {
+ sessionId = sessionIdWithJvmRoute(generateSessionId(), jvmRoute);
+ } while (jedis.hsetnx(getClassName().getBytes(), sessionId.getBytes(), NULL_SESSION) == 0L); // 1 = key set; 0 = key already existed
+ }
/* Even though the key is set in Redis, we are not going to flag
the current thread as having had the session persisted since
@@ -360,526 +405,555 @@ public Session createSession(String requestedSessionId) {
This ensures that the save(session) at the end of the request
will serialize the session into Redis with 'set' instead of 'setnx'. */
- error = false;
+ error = false;
+
+ if (null != sessionId) {
+ session = (RedisSession) super.createSession(sessionId);
+ session.setNew(true);
+ session.setValid(true);
+ session.setCreationTime(System.currentTimeMillis());
+ session.setMaxInactiveInterval(getMaxInactiveInterval());
+ session.setId(sessionId);
+ session.tellNew();
+ }
+
+ currentSession.set(session);
+ currentSessionId.set(sessionId);
+ currentSessionIsPersisted.set(false);
+ currentSessionSerializationMetadata.set(new SessionSerializationMetadata());
+
+ if (null != session) {
+ try {
+ error = saveInternal(jedis, session, true);
+ sessions.put(sessionId, session);
+ } catch (IOException ex) {
+ log.error("Error saving newly created session: " + ex.getMessage());
+ currentSession.set(null);
+ currentSessionId.set(null);
+ session = null;
+ }
+ }
+ } finally {
+ if (jedis != null) {
+ returnConnection(jedis, error);
+ }
+ }
- if (null != sessionId) {
- session = (RedisSession)createEmptySession();
- session.setNew(true);
- session.setValid(true);
- session.setCreationTime(System.currentTimeMillis());
- session.setMaxInactiveInterval(getMaxInactiveInterval());
- session.setId(sessionId);
- session.tellNew();
- }
+ return session;
+ }
- currentSession.set(session);
- currentSessionId.set(sessionId);
- currentSessionIsPersisted.set(false);
- currentSessionSerializationMetadata.set(new SessionSerializationMetadata());
+ private String sessionIdWithJvmRoute(String sessionId, String jvmRoute) {
+ if (jvmRoute != null) {
+ String jvmRoutePrefix = '.' + jvmRoute;
+ return sessionId.endsWith(jvmRoutePrefix) ? sessionId : sessionId + jvmRoutePrefix;
+ }
+ return sessionId;
+ }
- if (null != session) {
+ @Override
+ public Session createEmptySession() {
+ return new RedisSession(this);
+ }
+
+ @Override
+ public void add(Session session) {
+ super.add(session);
try {
- error = saveInternal(jedis, session, true);
+ save(session);
} catch (IOException ex) {
- log.error("Error saving newly created session: " + ex.getMessage());
- currentSession.set(null);
- currentSessionId.set(null);
- session = null;
- }
- }
- } finally {
- if (jedis != null) {
- returnConnection(jedis, error);
- }
- }
-
- return session;
- }
-
- private String sessionIdWithJvmRoute(String sessionId, String jvmRoute) {
- if (jvmRoute != null) {
- String jvmRoutePrefix = '.' + jvmRoute;
- return sessionId.endsWith(jvmRoutePrefix) ? sessionId : sessionId + jvmRoutePrefix;
- }
- return sessionId;
- }
-
- @Override
- public Session createEmptySession() {
- return new RedisSession(this);
- }
-
- @Override
- public void add(Session session) {
- try {
- save(session);
- } catch (IOException ex) {
- log.warn("Unable to add to session manager store: " + ex.getMessage());
- throw new RuntimeException("Unable to add to session manager store.", ex);
- }
- }
-
- @Override
- public Session findSession(String id) throws IOException {
- RedisSession session = null;
-
- if (null == id) {
- currentSessionIsPersisted.set(false);
- currentSession.set(null);
- currentSessionSerializationMetadata.set(null);
- currentSessionId.set(null);
- } else if (id.equals(currentSessionId.get())) {
- session = currentSession.get();
- } else {
- byte[] data = loadSessionDataFromRedis(id);
- if (data != null) {
- DeserializedSessionContainer container = sessionFromSerializedData(id, data);
- session = container.session;
- currentSession.set(session);
- currentSessionSerializationMetadata.set(container.metadata);
- currentSessionIsPersisted.set(true);
- currentSessionId.set(id);
- } else {
- currentSessionIsPersisted.set(false);
- currentSession.set(null);
- currentSessionSerializationMetadata.set(null);
- currentSessionId.set(null);
- }
- }
-
- return session;
- }
-
- public void clear() {
- Jedis jedis = null;
- Boolean error = true;
- try {
- jedis = acquireConnection();
- jedis.flushDB();
- error = false;
- } finally {
- if (jedis != null) {
- returnConnection(jedis, error);
- }
- }
- }
-
- public int getSize() throws IOException {
- Jedis jedis = null;
- Boolean error = true;
- try {
- jedis = acquireConnection();
- int size = jedis.dbSize().intValue();
- error = false;
- return size;
- } finally {
- if (jedis != null) {
- returnConnection(jedis, error);
- }
- }
- }
-
- public String[] keys() throws IOException {
- Jedis jedis = null;
- Boolean error = true;
- try {
- jedis = acquireConnection();
- Set keySet = jedis.keys("*");
- error = false;
- return keySet.toArray(new String[keySet.size()]);
- } finally {
- if (jedis != null) {
- returnConnection(jedis, error);
- }
- }
- }
-
- public byte[] loadSessionDataFromRedis(String id) throws IOException {
- Jedis jedis = null;
- Boolean error = true;
-
- try {
- log.trace("Attempting to load session " + id + " from Redis");
-
- jedis = acquireConnection();
- byte[] data = jedis.get(id.getBytes());
- error = false;
-
- if (data == null) {
- log.trace("Session " + id + " not found in Redis");
- }
-
- return data;
- } finally {
- if (jedis != null) {
- returnConnection(jedis, error);
- }
- }
- }
-
- public DeserializedSessionContainer sessionFromSerializedData(String id, byte[] data) throws IOException {
- log.trace("Deserializing session " + id + " from Redis");
-
- if (Arrays.equals(NULL_SESSION, data)) {
- log.error("Encountered serialized session " + id + " with data equal to NULL_SESSION. This is a bug.");
- throw new IOException("Serialized session data was equal to NULL_SESSION");
- }
-
- RedisSession session = null;
- SessionSerializationMetadata metadata = new SessionSerializationMetadata();
-
- try {
- session = (RedisSession)createEmptySession();
-
- serializer.deserializeInto(data, session, metadata);
-
- session.setId(id);
- session.setNew(false);
- session.setMaxInactiveInterval(getMaxInactiveInterval());
- session.access();
- session.setValid(true);
- session.resetDirtyTracking();
-
- if (log.isTraceEnabled()) {
- log.trace("Session Contents [" + id + "]:");
- Enumeration en = session.getAttributeNames();
- while(en.hasMoreElements()) {
- log.trace(" " + en.nextElement());
- }
- }
- } catch (ClassNotFoundException ex) {
- log.fatal("Unable to deserialize into session", ex);
- throw new IOException("Unable to deserialize into session", ex);
- }
-
- return new DeserializedSessionContainer(session, metadata);
- }
-
- public void save(Session session) throws IOException {
- save(session, false);
- }
-
- public void save(Session session, boolean forceSave) throws IOException {
- Jedis jedis = null;
- Boolean error = true;
-
- try {
- jedis = acquireConnection();
- error = saveInternal(jedis, session, forceSave);
- } catch (IOException e) {
- throw e;
- } finally {
- if (jedis != null) {
- returnConnection(jedis, error);
- }
- }
- }
+ log.warn("Unable to add to session manager store: " + ex.getMessage());
+ throw new RuntimeException("Unable to add to session manager store.", ex);
+ }
+ }
- protected boolean saveInternal(Jedis jedis, Session session, boolean forceSave) throws IOException {
- Boolean error = true;
+ @Override
+ public Session findSession(String id) throws IOException {
+ RedisSession session = null;
+
+ if (null == id) {
+ currentSessionIsPersisted.set(false);
+ currentSession.set(null);
+ currentSessionSerializationMetadata.set(null);
+ currentSessionId.set(null);
+ } else if (id.equals(currentSessionId.get())) {
+ session = currentSession.get();
+ } else {
+ byte[] data = loadSessionDataFromRedis(id);
+ if (data != null) {
+ DeserializedSessionContainer container = sessionFromSerializedData(id, data);
+ session = container.session;
+ currentSession.set(session);
+ currentSessionSerializationMetadata.set(container.metadata);
+ currentSessionIsPersisted.set(true);
+ currentSessionId.set(id);
+ } else {
+ currentSessionIsPersisted.set(false);
+ currentSession.set(null);
+ currentSessionSerializationMetadata.set(null);
+ currentSessionId.set(null);
+ }
+ }
- try {
- log.trace("Saving session " + session + " into Redis");
-
- RedisSession redisSession = (RedisSession)session;
+ return session;
+ }
- if (log.isTraceEnabled()) {
- log.trace("Session Contents [" + redisSession.getId() + "]:");
- Enumeration en = redisSession.getAttributeNames();
- while(en.hasMoreElements()) {
- log.trace(" " + en.nextElement());
+ public void clear() {
+ Jedis jedis = null;
+ Boolean error = true;
+ try {
+ jedis = acquireConnection();
+ jedis.flushDB();
+ error = false;
+ } finally {
+ if (jedis != null) {
+ returnConnection(jedis, error);
+ }
}
- }
+ }
+
+ public int getSize() throws IOException {
+ Jedis jedis = null;
+ Boolean error = true;
+ try {
+ jedis = acquireConnection();
+ int size = jedis.dbSize().intValue();
+ error = false;
+ return size;
+ } finally {
+ if (jedis != null) {
+ returnConnection(jedis, error);
+ }
+ }
+ }
- byte[] binaryId = redisSession.getId().getBytes();
+// @Override
+// public Session[] findSessions() {
+// Jedis jedis = null;
+// Boolean error = true;
+// List sessions = new ArrayList<>();
+// try {
+// log.trace("Attempting to load sessions from Redis");
+// jedis = acquireConnection();
+// Map datas = jedis.hgetAll(getClassName().getBytes());
+// Set keys = datas.keySet();
+// for (byte[] key : keys) {
+// byte[] data = datas.get(key);
+// if (data != null) {
+// String id = new String(key);
+// try {
+// DeserializedSessionContainer container = sessionFromSerializedData(id, data);
+// RedisSession session = container.session;
+// if (session != null) {
+// sessions.add(session);
+// }
+// } catch (IOException ex) {
+// log.fatal("Session " + id + " Unable to deserialize into session", ex);
+// }
+// }
+// }
+// error = false;
+// } finally {
+// if (jedis != null) {
+// returnConnection(jedis, error);
+// }
+// }
+// return sessions.toArray(new Session[0]);
+// }
+
+ public byte[] loadSessionDataFromRedis(String id) throws IOException {
+ Jedis jedis = null;
+ Boolean error = true;
- Boolean isCurrentSessionPersisted;
- SessionSerializationMetadata sessionSerializationMetadata = currentSessionSerializationMetadata.get();
- byte[] originalSessionAttributesHash = sessionSerializationMetadata.getSessionAttributesHash();
- byte[] sessionAttributesHash = null;
- if (
- forceSave
- || redisSession.isDirty()
- || null == (isCurrentSessionPersisted = this.currentSessionIsPersisted.get())
- || !isCurrentSessionPersisted
- || !Arrays.equals(originalSessionAttributesHash, (sessionAttributesHash = serializer.attributesHashFrom(redisSession)))
- ) {
+ try {
+ log.trace("Attempting to load session " + id + " from Redis");
- log.trace("Save was determined to be necessary");
+ jedis = acquireConnection();
+ byte[] data = jedis.hget(getClassName().getBytes(), id.getBytes());
+ error = false;
- if (null == sessionAttributesHash) {
- sessionAttributesHash = serializer.attributesHashFrom(redisSession);
+ if (data == null) {
+ log.trace("Session " + id + " not found in Redis");
+ }
+
+ return data;
+ } finally {
+ if (jedis != null) {
+ returnConnection(jedis, error);
+ }
}
+ }
- SessionSerializationMetadata updatedSerializationMetadata = new SessionSerializationMetadata();
- updatedSerializationMetadata.setSessionAttributesHash(sessionAttributesHash);
+ public int getMaxInactiveInterval() {
+ if (maxInactiveInterval == null || maxInactiveInterval.trim().length() == 0) {
+ return getContext().getSessionTimeout() * 60;
+ } else {
+ return Integer.valueOf(maxInactiveInterval) * 60;
+ }
+ }
- jedis.set(binaryId, serializer.serializeFrom(redisSession, updatedSerializationMetadata));
+ public DeserializedSessionContainer sessionFromSerializedData(String id, byte[] data) throws IOException {
+ log.trace("Deserializing session " + id + " from Redis");
- redisSession.resetDirtyTracking();
- currentSessionSerializationMetadata.set(updatedSerializationMetadata);
- currentSessionIsPersisted.set(true);
- } else {
- log.trace("Save was determined to be unnecessary");
- }
+ if (Arrays.equals(NULL_SESSION, data)) {
+ log.error("Encountered serialized session " + id + " with data equal to NULL_SESSION. This is a bug.");
+ throw new IOException("Serialized session data was equal to NULL_SESSION");
+ }
- log.trace("Setting expire timeout on session [" + redisSession.getId() + "] to " + getMaxInactiveInterval());
- jedis.expire(binaryId, getMaxInactiveInterval());
+ RedisSession session = null;
+ SessionSerializationMetadata metadata = new SessionSerializationMetadata();
- error = false;
+ try {
+ session = (RedisSession) createEmptySession();
+
+ serializer.deserializeInto(data, session, metadata);
+
+ session.setId(id);
+ session.setNew(false);
+ session.access();
+ session.setValid(true);
+ session.resetDirtyTracking();
+
+ if (log.isTraceEnabled()) {
+ log.trace("Session Contents [" + id + "]:");
+ Enumeration en = session.getAttributeNames();
+ while (en.hasMoreElements()) {
+ log.trace(" " + en.nextElement());
+ }
+ }
+ } catch (ClassNotFoundException ex) {
+ log.fatal("Unable to deserialize into session", ex);
+ throw new IOException("Unable to deserialize into session", ex);
+ }
- return error;
- } catch (IOException e) {
- log.error(e.getMessage());
-
- throw e;
- } finally {
- return error;
- }
- }
+ return new DeserializedSessionContainer(session, metadata);
+ }
- @Override
- public void remove(Session session) {
- remove(session, false);
- }
+ public void save(Session session) throws IOException {
+ save(session, false);
+ }
- @Override
- public void remove(Session session, boolean update) {
- Jedis jedis = null;
- Boolean error = true;
+ public void save(Session session, boolean forceSave) throws IOException {
+ Jedis jedis = null;
+ Boolean error = true;
- log.trace("Removing session ID : " + session.getId());
+ try {
+ jedis = acquireConnection();
+ error = saveInternal(jedis, session, forceSave);
+ } catch (IOException e) {
+ throw e;
+ } finally {
+ if (jedis != null) {
+ returnConnection(jedis, error);
+ }
+ }
+ }
+
+ protected boolean saveInternal(Jedis jedis, Session session, boolean forceSave) throws IOException {
+ Boolean error = true;
- try {
- jedis = acquireConnection();
- jedis.del(session.getId());
- error = false;
- } finally {
- if (jedis != null) {
- returnConnection(jedis, error);
- }
+ try {
+ log.trace("Saving session " + session + " into Redis");
+
+ RedisSession redisSession = (RedisSession) session;
+
+ if (log.isTraceEnabled()) {
+ log.trace("Session Contents [" + redisSession.getId() + "]:");
+ Enumeration en = redisSession.getAttributeNames();
+ while (en.hasMoreElements()) {
+ log.trace(" " + en.nextElement());
+ }
+ }
+
+ byte[] binaryId = redisSession.getId().getBytes();
+
+ Boolean isCurrentSessionPersisted;
+ SessionSerializationMetadata sessionSerializationMetadata = currentSessionSerializationMetadata.get();
+ byte[] originalSessionAttributesHash = sessionSerializationMetadata.getSessionAttributesHash();
+ byte[] sessionAttributesHash = null;
+ if (
+ forceSave
+ || redisSession.isDirty()
+ || null == (isCurrentSessionPersisted = this.currentSessionIsPersisted.get())
+ || !isCurrentSessionPersisted
+ || !Arrays.equals(originalSessionAttributesHash, (sessionAttributesHash = serializer.attributesHashFrom(redisSession)))
+ ) {
+
+ log.trace("Save was determined to be necessary");
+
+ if (null == sessionAttributesHash) {
+ sessionAttributesHash = serializer.attributesHashFrom(redisSession);
+ }
+
+ SessionSerializationMetadata updatedSerializationMetadata = new SessionSerializationMetadata();
+ updatedSerializationMetadata.setSessionAttributesHash(sessionAttributesHash);
+
+ jedis.hset(getClassName().getBytes(), binaryId, serializer.serializeFrom(redisSession, updatedSerializationMetadata));
+
+ redisSession.resetDirtyTracking();
+ currentSessionSerializationMetadata.set(updatedSerializationMetadata);
+ currentSessionIsPersisted.set(true);
+ } else {
+ log.trace("Save was determined to be unnecessary");
+ }
+ error = false;
+ return error;
+ } catch (IOException e) {
+ log.error(e.getMessage());
+
+ throw e;
+ } finally {
+ return error;
+ }
}
- }
-
- public void afterRequest() {
- RedisSession redisSession = currentSession.get();
- if (redisSession != null) {
- try {
- if (redisSession.isValid()) {
- log.trace("Request with session completed, saving session " + redisSession.getId());
- save(redisSession, getAlwaysSaveAfterRequest());
- } else {
- log.trace("HTTP Session has been invalidated, removing :" + redisSession.getId());
- remove(redisSession);
- }
- } catch (Exception e) {
- log.error("Error storing/removing session", e);
- } finally {
- currentSession.remove();
- currentSessionId.remove();
- currentSessionIsPersisted.remove();
- log.trace("Session removed from ThreadLocal :" + redisSession.getIdInternal());
- }
- }
- }
-
- @Override
- public void processExpires() {
- // We are going to use Redis's ability to expire keys for session expiration.
-
- // Do nothing.
- }
-
- private void initializeDatabaseConnection() throws LifecycleException {
- try {
- if (getSentinelMaster() != null) {
- Set sentinelSet = getSentinelSet();
- if (sentinelSet != null && sentinelSet.size() > 0) {
- connectionPool = new JedisSentinelPool(getSentinelMaster(), sentinelSet, this.connectionPoolConfig, getTimeout(), getPassword());
- } else {
- throw new LifecycleException("Error configuring Redis Sentinel connection pool: expected both `sentinelMaster` and `sentiels` to be configured");
+
+ @Override
+ public void remove(Session session) {
+ remove(session, false);
+ }
+
+ @Override
+ public void remove(Session session, boolean update) {
+ super.remove(session, update);
+ Jedis jedis = null;
+ Boolean error = true;
+
+ log.trace("Removing session ID : " + session.getId());
+ currentSessionSerializationMetadata.remove();
+ try {
+ jedis = acquireConnection();
+ jedis.hdel(getClassName(), session.getId());
+ error = false;
+ } finally {
+ if (jedis != null) {
+ returnConnection(jedis, error);
+ }
+ }
+ }
+
+ public void afterRequest() {
+ RedisSession redisSession = currentSession.get();
+ if (redisSession != null) {
+ try {
+ if (redisSession.isValid()) {
+ log.trace("Request with session completed, saving session " + redisSession.getId());
+ save(redisSession, getAlwaysSaveAfterRequest());
+ } else {
+ log.trace("HTTP Session has been invalidated, removing :" + redisSession.getId());
+ remove(redisSession);
+ }
+ } catch (Exception e) {
+ log.error("Error storing/removing session", e);
+ } finally {
+ currentSession.remove();
+ currentSessionId.remove();
+ currentSessionIsPersisted.remove();
+ log.trace("Session removed from ThreadLocal :" + redisSession.getIdInternal());
+ }
+ }
+ }
+
+ @Override
+ public void processExpires() {
+ // We are going to use Redis's ability to expire keys for session expiration.
+ super.processExpires();
+ // Do nothing.
+ }
+
+ private void initializeDatabaseConnection() throws LifecycleException {
+ try {
+ if (getSentinelMaster() != null) {
+ Set sentinelSet = getSentinelSet();
+ if (sentinelSet != null && sentinelSet.size() > 0) {
+ connectionPool = new JedisSentinelPool(getSentinelMaster(), sentinelSet, this.connectionPoolConfig, getTimeout(), getPassword());
+ } else {
+ throw new LifecycleException("Error configuring Redis Sentinel connection pool: expected both `sentinelMaster` and `sentiels` to be configured");
+ }
+ } else {
+ connectionPool = new JedisPool(this.connectionPoolConfig, getHost(), getPort(), getTimeout(), getPassword());
+ }
+ } catch (Exception e) {
+ log.error("Error connecting to Redis", e);
+ throw new LifecycleException("Error connecting to Redis", e);
+ }
+ }
+
+ private void initializeSerializer() throws ClassNotFoundException, IllegalAccessException, InstantiationException {
+ log.info("Attempting to use serializer :" + serializationStrategyClass);
+ serializer = (Serializer) Class.forName(serializationStrategyClass).newInstance();
+
+ Loader loader = null;
+
+ if (getContext() != null) {
+ loader = getContext().getLoader();
+ }
+
+ ClassLoader classLoader = null;
+
+ if (loader != null) {
+ classLoader = loader.getClassLoader();
}
- } else {
- connectionPool = new JedisPool(this.connectionPoolConfig, getHost(), getPort(), getTimeout(), getPassword());
- }
- } catch (Exception e) {
- e.printStackTrace();
- throw new LifecycleException("Error connecting to Redis", e);
+ serializer.setClassLoader(classLoader);
}
- }
- private void initializeSerializer() throws ClassNotFoundException, IllegalAccessException, InstantiationException {
- log.info("Attempting to use serializer :" + serializationStrategyClass);
- serializer = (Serializer) Class.forName(serializationStrategyClass).newInstance();
- Loader loader = null;
+ // Connection Pool Config Accessors
- if (getContainer() != null) {
- loader = getContainer().getLoader();
+ // - from org.apache.commons.pool2.impl.GenericObjectPoolConfig
+
+ public int getConnectionPoolMaxTotal() {
+ return this.connectionPoolConfig.getMaxTotal();
}
- ClassLoader classLoader = null;
+ public void setConnectionPoolMaxTotal(int connectionPoolMaxTotal) {
+ this.connectionPoolConfig.setMaxTotal(connectionPoolMaxTotal);
+ }
- if (loader != null) {
- classLoader = loader.getClassLoader();
+ public int getConnectionPoolMaxIdle() {
+ return this.connectionPoolConfig.getMaxIdle();
}
- serializer.setClassLoader(classLoader);
- }
+ public void setConnectionPoolMaxIdle(int connectionPoolMaxIdle) {
+ this.connectionPoolConfig.setMaxIdle(connectionPoolMaxIdle);
+ }
- // Connection Pool Config Accessors
+ public int getConnectionPoolMinIdle() {
+ return this.connectionPoolConfig.getMinIdle();
+ }
- // - from org.apache.commons.pool2.impl.GenericObjectPoolConfig
+ public void setConnectionPoolMinIdle(int connectionPoolMinIdle) {
+ this.connectionPoolConfig.setMinIdle(connectionPoolMinIdle);
+ }
- public int getConnectionPoolMaxTotal() {
- return this.connectionPoolConfig.getMaxTotal();
- }
- public void setConnectionPoolMaxTotal(int connectionPoolMaxTotal) {
- this.connectionPoolConfig.setMaxTotal(connectionPoolMaxTotal);
- }
+ // - from org.apache.commons.pool2.impl.BaseObjectPoolConfig
- public int getConnectionPoolMaxIdle() {
- return this.connectionPoolConfig.getMaxIdle();
- }
+ public boolean getLifo() {
+ return this.connectionPoolConfig.getLifo();
+ }
- public void setConnectionPoolMaxIdle(int connectionPoolMaxIdle) {
- this.connectionPoolConfig.setMaxIdle(connectionPoolMaxIdle);
- }
+ public void setLifo(boolean lifo) {
+ this.connectionPoolConfig.setLifo(lifo);
+ }
- public int getConnectionPoolMinIdle() {
- return this.connectionPoolConfig.getMinIdle();
- }
+ public long getMaxWaitMillis() {
+ return this.connectionPoolConfig.getMaxWaitMillis();
+ }
- public void setConnectionPoolMinIdle(int connectionPoolMinIdle) {
- this.connectionPoolConfig.setMinIdle(connectionPoolMinIdle);
- }
+ public void setMaxWaitMillis(long maxWaitMillis) {
+ this.connectionPoolConfig.setMaxWaitMillis(maxWaitMillis);
+ }
+ public long getMinEvictableIdleTimeMillis() {
+ return this.connectionPoolConfig.getMinEvictableIdleTimeMillis();
+ }
- // - from org.apache.commons.pool2.impl.BaseObjectPoolConfig
+ public void setMinEvictableIdleTimeMillis(long minEvictableIdleTimeMillis) {
+ this.connectionPoolConfig.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
+ }
- public boolean getLifo() {
- return this.connectionPoolConfig.getLifo();
- }
- public void setLifo(boolean lifo) {
- this.connectionPoolConfig.setLifo(lifo);
- }
- public long getMaxWaitMillis() {
- return this.connectionPoolConfig.getMaxWaitMillis();
- }
+ public long getSoftMinEvictableIdleTimeMillis() {
+ return this.connectionPoolConfig.getSoftMinEvictableIdleTimeMillis();
+ }
- public void setMaxWaitMillis(long maxWaitMillis) {
- this.connectionPoolConfig.setMaxWaitMillis(maxWaitMillis);
- }
+ public void setSoftMinEvictableIdleTimeMillis(long softMinEvictableIdleTimeMillis) {
+ this.connectionPoolConfig.setSoftMinEvictableIdleTimeMillis(softMinEvictableIdleTimeMillis);
+ }
- public long getMinEvictableIdleTimeMillis() {
- return this.connectionPoolConfig.getMinEvictableIdleTimeMillis();
- }
+ public int getNumTestsPerEvictionRun() {
+ return this.connectionPoolConfig.getNumTestsPerEvictionRun();
+ }
- public void setMinEvictableIdleTimeMillis(long minEvictableIdleTimeMillis) {
- this.connectionPoolConfig.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
- }
+ public void setNumTestsPerEvictionRun(int numTestsPerEvictionRun) {
+ this.connectionPoolConfig.setNumTestsPerEvictionRun(numTestsPerEvictionRun);
+ }
- public long getSoftMinEvictableIdleTimeMillis() {
- return this.connectionPoolConfig.getSoftMinEvictableIdleTimeMillis();
- }
+ public boolean getTestOnCreate() {
+ return this.connectionPoolConfig.getTestOnCreate();
+ }
- public void setSoftMinEvictableIdleTimeMillis(long softMinEvictableIdleTimeMillis) {
- this.connectionPoolConfig.setSoftMinEvictableIdleTimeMillis(softMinEvictableIdleTimeMillis);
- }
+ public void setTestOnCreate(boolean testOnCreate) {
+ this.connectionPoolConfig.setTestOnCreate(testOnCreate);
+ }
- public int getNumTestsPerEvictionRun() {
- return this.connectionPoolConfig.getNumTestsPerEvictionRun();
- }
+ public boolean getTestOnBorrow() {
+ return this.connectionPoolConfig.getTestOnBorrow();
+ }
- public void setNumTestsPerEvictionRun(int numTestsPerEvictionRun) {
- this.connectionPoolConfig.setNumTestsPerEvictionRun(numTestsPerEvictionRun);
- }
+ public void setTestOnBorrow(boolean testOnBorrow) {
+ this.connectionPoolConfig.setTestOnBorrow(testOnBorrow);
+ }
- public boolean getTestOnCreate() {
- return this.connectionPoolConfig.getTestOnCreate();
- }
+ public boolean getTestOnReturn() {
+ return this.connectionPoolConfig.getTestOnReturn();
+ }
- public void setTestOnCreate(boolean testOnCreate) {
- this.connectionPoolConfig.setTestOnCreate(testOnCreate);
- }
+ public void setTestOnReturn(boolean testOnReturn) {
+ this.connectionPoolConfig.setTestOnReturn(testOnReturn);
+ }
- public boolean getTestOnBorrow() {
- return this.connectionPoolConfig.getTestOnBorrow();
- }
+ public boolean getTestWhileIdle() {
+ return this.connectionPoolConfig.getTestWhileIdle();
+ }
+
+ public void setTestWhileIdle(boolean testWhileIdle) {
+ this.connectionPoolConfig.setTestWhileIdle(testWhileIdle);
+ }
+
+ public long getTimeBetweenEvictionRunsMillis() {
+ return this.connectionPoolConfig.getTimeBetweenEvictionRunsMillis();
+ }
+
+ public void setTimeBetweenEvictionRunsMillis(long timeBetweenEvictionRunsMillis) {
+ this.connectionPoolConfig.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
+ }
+
+ public String getEvictionPolicyClassName() {
+ return this.connectionPoolConfig.getEvictionPolicyClassName();
+ }
+
+ public void setEvictionPolicyClassName(String evictionPolicyClassName) {
+ this.connectionPoolConfig.setEvictionPolicyClassName(evictionPolicyClassName);
+ }
+
+ public boolean getBlockWhenExhausted() {
+ return this.connectionPoolConfig.getBlockWhenExhausted();
+ }
+
+ public void setBlockWhenExhausted(boolean blockWhenExhausted) {
+ this.connectionPoolConfig.setBlockWhenExhausted(blockWhenExhausted);
+ }
- public void setTestOnBorrow(boolean testOnBorrow) {
- this.connectionPoolConfig.setTestOnBorrow(testOnBorrow);
- }
+ public boolean getJmxEnabled() {
+ return this.connectionPoolConfig.getJmxEnabled();
+ }
+
+ public void setJmxEnabled(boolean jmxEnabled) {
+ this.connectionPoolConfig.setJmxEnabled(jmxEnabled);
+ }
- public boolean getTestOnReturn() {
- return this.connectionPoolConfig.getTestOnReturn();
- }
+ public String getJmxNameBase() {
+ return this.connectionPoolConfig.getJmxNameBase();
+ }
- public void setTestOnReturn(boolean testOnReturn) {
- this.connectionPoolConfig.setTestOnReturn(testOnReturn);
- }
+ public void setJmxNameBase(String jmxNameBase) {
+ this.connectionPoolConfig.setJmxNameBase(jmxNameBase);
+ }
- public boolean getTestWhileIdle() {
- return this.connectionPoolConfig.getTestWhileIdle();
- }
+ public String getJmxNamePrefix() {
+ return this.connectionPoolConfig.getJmxNamePrefix();
+ }
- public void setTestWhileIdle(boolean testWhileIdle) {
- this.connectionPoolConfig.setTestWhileIdle(testWhileIdle);
- }
-
- public long getTimeBetweenEvictionRunsMillis() {
- return this.connectionPoolConfig.getTimeBetweenEvictionRunsMillis();
- }
-
- public void setTimeBetweenEvictionRunsMillis(long timeBetweenEvictionRunsMillis) {
- this.connectionPoolConfig.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
- }
-
- public String getEvictionPolicyClassName() {
- return this.connectionPoolConfig.getEvictionPolicyClassName();
- }
-
- public void setEvictionPolicyClassName(String evictionPolicyClassName) {
- this.connectionPoolConfig.setEvictionPolicyClassName(evictionPolicyClassName);
- }
-
- public boolean getBlockWhenExhausted() {
- return this.connectionPoolConfig.getBlockWhenExhausted();
- }
-
- public void setBlockWhenExhausted(boolean blockWhenExhausted) {
- this.connectionPoolConfig.setBlockWhenExhausted(blockWhenExhausted);
- }
-
- public boolean getJmxEnabled() {
- return this.connectionPoolConfig.getJmxEnabled();
- }
-
- public void setJmxEnabled(boolean jmxEnabled) {
- this.connectionPoolConfig.setJmxEnabled(jmxEnabled);
- }
- public String getJmxNameBase() {
- return this.connectionPoolConfig.getJmxNameBase();
- }
- public void setJmxNameBase(String jmxNameBase) {
- this.connectionPoolConfig.setJmxNameBase(jmxNameBase);
- }
-
- public String getJmxNamePrefix() {
- return this.connectionPoolConfig.getJmxNamePrefix();
- }
-
- public void setJmxNamePrefix(String jmxNamePrefix) {
- this.connectionPoolConfig.setJmxNamePrefix(jmxNamePrefix);
- }
+ public void setJmxNamePrefix(String jmxNamePrefix) {
+ this.connectionPoolConfig.setJmxNamePrefix(jmxNamePrefix);
+ }
}
class DeserializedSessionContainer {
- public final RedisSession session;
- public final SessionSerializationMetadata metadata;
- public DeserializedSessionContainer(RedisSession session, SessionSerializationMetadata metadata) {
- this.session = session;
- this.metadata = metadata;
- }
+ public final RedisSession session;
+ public final SessionSerializationMetadata metadata;
+
+ public DeserializedSessionContainer(RedisSession session, SessionSerializationMetadata metadata) {
+ this.session = session;
+ this.metadata = metadata;
+ }
}
diff --git a/src/main/java/com/orangefunction/tomcat/redissessions/Serializer.java b/src/main/java/com/orangefunction/tomcat/redissessions/Serializer.java
index b6d1161a..d9da63a7 100644
--- a/src/main/java/com/orangefunction/tomcat/redissessions/Serializer.java
+++ b/src/main/java/com/orangefunction/tomcat/redissessions/Serializer.java
@@ -1,12 +1,23 @@
package com.orangefunction.tomcat.redissessions;
-import javax.servlet.http.HttpSession;
import java.io.IOException;
+/**
+ * Title: Godfather1103's Github
+ * Copyright: Copyright (c) 2020
+ * Company: https://github.com/godfather1103
+ *
+ * @author 作者: Jack Chu E-mail: chuchuanbao@gmail.com
+ * 创建时间:2020-07-01 17:20
+ * @version 1.0
+ * @since 1.0
+ */
public interface Serializer {
- void setClassLoader(ClassLoader loader);
+ void setClassLoader(ClassLoader loader);
- byte[] attributesHashFrom(RedisSession session) throws IOException;
- byte[] serializeFrom(RedisSession session, SessionSerializationMetadata metadata) throws IOException;
- void deserializeInto(byte[] data, RedisSession session, SessionSerializationMetadata metadata) throws IOException, ClassNotFoundException;
+ byte[] attributesHashFrom(RedisSession session) throws IOException;
+
+ byte[] serializeFrom(RedisSession session, SessionSerializationMetadata metadata) throws IOException;
+
+ void deserializeInto(byte[] data, RedisSession session, SessionSerializationMetadata metadata) throws IOException, ClassNotFoundException;
}
diff --git a/src/main/java/com/orangefunction/tomcat/redissessions/SessionSerializationMetadata.java b/src/main/java/com/orangefunction/tomcat/redissessions/SessionSerializationMetadata.java
index 7d3d9276..e88c966b 100644
--- a/src/main/java/com/orangefunction/tomcat/redissessions/SessionSerializationMetadata.java
+++ b/src/main/java/com/orangefunction/tomcat/redissessions/SessionSerializationMetadata.java
@@ -1,6 +1,8 @@
package com.orangefunction.tomcat.redissessions;
-import java.io.*;
+import java.io.IOException;
+import java.io.ObjectStreamException;
+import java.io.Serializable;
public class SessionSerializationMetadata implements Serializable {