Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support Reids Cluster & JDK 8 #104

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,5 @@ example-app/.gradle/*
.rspec
*.iml
.idea/*
/bin/
/.gradle/
18 changes: 16 additions & 2 deletions README.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,19 @@ Architecture

Note: this architecture differs from the Apache PersistentManager implementation which implements persistent sticky sessions. Because that implementation expects all requests from a specific session to be routed to the same server, the timing persistence of sessions is non-deterministic since it is primarily for failover capabilities.


Support Reids Cluster & JDK 8
------------

<Valve className="com.orangefunction.tomcat.redissessions.RedisSessionHandlerValve" />
<Manager className="com.orangefunction.tomcat.redissessions.RedisSessionManager"
database="0" <!-- optional: defaults to "0" -->
maxInactiveInterval="60" <!-- optional: defaults to "60" (in seconds) -->
sessionPersistPolicies="PERSIST_POLICY_1,PERSIST_POLICY_2,.." <!-- optional -->
clusters="host-1:port,host-2:port,.." />



Usage
-----

Expand All @@ -69,14 +82,15 @@ Add the following into your Tomcat context.xml (or the context block of the serv
sessionPersistPolicies="PERSIST_POLICY_1,PERSIST_POLICY_2,.." <!-- optional -->
sentinelMaster="SentinelMasterName" <!-- optional -->
sentinels="sentinel-host-1:port,sentinel-host-2:port,.." <!-- optional --> />
clusters="host-1:port,host-2:port,.." <!-- optional --> />

The Valve must be declared before the Manager.

Copy the following files into the `TOMCAT_BASE/lib` directory:

* tomcat-redis-session-manager-VERSION.jar
* jedis-2.5.2.jar
* commons-pool2-2.2.jar
* jedis-2.9.0.jar
* commons-pool2-2.4.2.jar

Reboot the server, and sessions should now be stored in Redis.

Expand Down
20 changes: 10 additions & 10 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ apply plugin: 'maven'
apply plugin: 'signing'

group = 'com.orangefunction'
version = '2.0.0'
version = '2.0.2'

repositories {
mavenCentral()
Expand All @@ -16,8 +16,8 @@ compileJava {

dependencies {
compile group: 'org.apache.tomcat', name: 'tomcat-catalina', version: '7.0.27'
compile group: 'redis.clients', name: 'jedis', version: '2.5.2'
compile group: 'org.apache.commons', name: 'commons-pool2', version: '2.2'
compile group: 'redis.clients', name: 'jedis', version: '2.9.0'
compile group: 'org.apache.commons', name: 'commons-pool2', version: '2.4.2'
//compile group: 'commons-codec', name: 'commons-codec', version: '1.9'

testCompile group: 'junit', name: 'junit', version: '4.+'
Expand All @@ -40,22 +40,22 @@ task sourcesJar(type: Jar) {
artifacts {
archives jar

archives javadocJar
archives javadocJar
archives sourcesJar
}

signing {
sign configurations.archives
}
//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/service/local/staging/deploy/maven2/") {
// authentication(userName: sonatypeUsername, password: sonatypePassword)
// }
//repository(url: "https://oss.sonatype.org/content/repositories/snapshots") {
// authentication(userName: sonatypeUsername, password: sonatypePassword)
//}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

import org.apache.catalina.util.CustomObjectInputStream;

import javax.servlet.http.HttpSession;

import java.util.Enumeration;
import java.util.HashMap;
Expand Down
207 changes: 102 additions & 105 deletions src/main/java/com/orangefunction/tomcat/redissessions/RedisSession.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,112 +9,109 @@
import org.apache.juli.logging.Log;
import org.apache.juli.logging.LogFactory;


public class RedisSession extends StandardSession {

private final Log log = LogFactory.getLog(RedisSession.class);

protected static Boolean manualDirtyTrackingSupportEnabled = false;

public static void setManualDirtyTrackingSupportEnabled(Boolean enabled) {
manualDirtyTrackingSupportEnabled = enabled;
}

protected static String manualDirtyTrackingAttributeKey = "__changed__";

public static void setManualDirtyTrackingAttributeKey(String key) {
manualDirtyTrackingAttributeKey = key;
}


protected HashMap<String, Object> changedAttributes;
protected Boolean dirty;

public RedisSession(Manager manager) {
super(manager);
resetDirtyTracking();
}

public Boolean isDirty() {
return dirty || !changedAttributes.isEmpty();
}

public HashMap<String, Object> getChangedAttributes() {
return changedAttributes;
}

public void resetDirtyTracking() {
changedAttributes = new HashMap<>();
dirty = false;
}

@Override
public void setAttribute(String key, Object value) {
if (manualDirtyTrackingSupportEnabled && manualDirtyTrackingAttributeKey.equals(key)) {
dirty = true;
return;
}

Object oldValue = getAttribute(key);
super.setAttribute(key, value);

if ( (value != null || oldValue != null)
&& ( value == null && oldValue != null
|| oldValue == null && value != null
|| !value.getClass().isInstance(oldValue)
|| !value.equals(oldValue) ) ) {
if (this.manager instanceof RedisSessionManager
&& ((RedisSessionManager)this.manager).getSaveOnChange()) {
try {
((RedisSessionManager)this.manager).save(this, true);
} catch (IOException ex) {
log.error("Error saving session on setAttribute (triggered by saveOnChange=true): " + ex.getMessage());
}
} else {
changedAttributes.put(key, value);
}
}
}

@Override
public void removeAttribute(String name) {
super.removeAttribute(name);
if (this.manager instanceof RedisSessionManager
&& ((RedisSessionManager)this.manager).getSaveOnChange()) {
try {
((RedisSessionManager)this.manager).save(this, true);
} catch (IOException ex) {
log.error("Error saving session on setAttribute (triggered by saveOnChange=true): " + ex.getMessage());
}
} else {
dirty = true;
}
}

@Override
public void setId(String id) {
// Specifically do not call super(): it's implementation does unexpected things
// like calling manager.remove(session.id) and manager.add(session).

this.id = id;
}

@Override
public void setPrincipal(Principal principal) {
dirty = true;
super.setPrincipal(principal);
}

@Override
public void writeObjectData(java.io.ObjectOutputStream out) throws IOException {
super.writeObjectData(out);
out.writeLong(this.getCreationTime());
}

@Override
public void readObjectData(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException {
super.readObjectData(in);
this.setCreationTime(in.readLong());
}
private static final long serialVersionUID = 1L;

private final Log log = LogFactory.getLog(RedisSession.class);

protected static Boolean manualDirtyTrackingSupportEnabled = false;

public static void setManualDirtyTrackingSupportEnabled(Boolean enabled) {
manualDirtyTrackingSupportEnabled = enabled;
}

protected static String manualDirtyTrackingAttributeKey = "__changed__";

public static void setManualDirtyTrackingAttributeKey(String key) {
manualDirtyTrackingAttributeKey = key;
}

protected HashMap<String, Object> changedAttributes;
protected Boolean dirty;

public RedisSession(Manager manager) {
super(manager);
resetDirtyTracking();
}

public Boolean isDirty() {
return dirty || !changedAttributes.isEmpty();
}

public HashMap<String, Object> getChangedAttributes() {
return changedAttributes;
}

public void resetDirtyTracking() {
changedAttributes = new HashMap<>();
dirty = false;
}

@Override
public void setAttribute(String key, Object value) {
if (manualDirtyTrackingSupportEnabled && manualDirtyTrackingAttributeKey.equals(key)) {
dirty = true;
return;
}

Object oldValue = getAttribute(key);
super.setAttribute(key, value);

if ((value != null || oldValue != null)
&& (value == null && oldValue != null || oldValue == null && value != null
|| !value.getClass().isInstance(oldValue) || !value.equals(oldValue))) {
if (this.manager instanceof RedisSessionManager && ((RedisSessionManager) this.manager).getSaveOnChange()) {
try {
((RedisSessionManager) this.manager).save(this, true);
} catch (IOException ex) {
log.error("Error saving session on setAttribute (triggered by saveOnChange=true): "
+ ex.getMessage());
}
} else {
changedAttributes.put(key, value);
}
}
}

@Override
public void removeAttribute(String name) {
super.removeAttribute(name);
if (this.manager instanceof RedisSessionManager && ((RedisSessionManager) this.manager).getSaveOnChange()) {
try {
((RedisSessionManager) this.manager).save(this, true);
} catch (IOException ex) {
log.error("Error saving session on setAttribute (triggered by saveOnChange=true): " + ex.getMessage());
}
} else {
dirty = true;
}
}

@Override
public void setId(String id) {
// Specifically do not call super(): it's implementation does unexpected things
// like calling manager.remove(session.id) and manager.add(session).

this.id = id;
}

@Override
public void setPrincipal(Principal principal) {
dirty = true;
super.setPrincipal(principal);
}

@Override
public void writeObjectData(java.io.ObjectOutputStream out) throws IOException {
super.writeObjectData(out);
out.writeLong(this.getCreationTime());
}

@Override
public void readObjectData(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException {
super.readObjectData(in);
this.setCreationTime(in.readLong());
}

}
Original file line number Diff line number Diff line change
@@ -1,19 +1,15 @@
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 java.io.IOException;

import javax.servlet.ServletException;
import java.io.IOException;

import org.apache.juli.logging.Log;
import org.apache.juli.logging.LogFactory;
import org.apache.catalina.connector.Request;
import org.apache.catalina.connector.Response;
import org.apache.catalina.valves.ValveBase;


public class RedisSessionHandlerValve extends ValveBase {
private final Log log = LogFactory.getLog(RedisSessionManager.class);
private RedisSessionManager manager;

public void setRedisSessionManager(RedisSessionManager manager) {
Expand Down
Loading