package com.naritech.nicole.gump;
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.Context;
import org.apache.catalina.LifecycleState;
import org.apache.catalina.Loader;
import org.apache.catalina.Valve;
import org.apache.catalina.Session;
import org.apache.catalina.session.ManagerBase;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.apache.commons.pool2.impl.BaseObjectPoolConfig;
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.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;
public class RedisSessionManager extends ManagerBase implements Lifecycle {
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<String> sentinelSet = null;
protected Pool<Jedis> connectionPool;
protected JedisPoolConfig connectionPoolConfig = new JedisPoolConfig();
protected RedisSessionHandlerValve handlerValve;
protected ThreadLocal<RedisSession> currentSession = new ThreadLocal<>();
protected ThreadLocal<SessionSerializationMetadata> currentSessionSerializationMetadata = new ThreadLocal<>();
protected ThreadLocal<String> currentSessionId = new ThreadLocal<>();
protected ThreadLocal<Boolean> currentSessionIsPersisted = new ThreadLocal<>();
protected Serializer serializer;
protected static String name = "RedisSessionManager";
protected String serializationStrategyClass = "com.naritech.nicole.gump.JavaSerializer";
protected EnumSet<SessionPersistPolicy> sessionPersistPoliciesSet = EnumSet.of(SessionPersistPolicy.DEFAULT);
/**
* The lifecycle event support for this component.
*/
protected LifecycleSupport lifecycle = new LifecycleSupport(this);
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;
}
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<SessionPersistPolicy> 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<SessionPersistPolicy> policySet = EnumSet.of(SessionPersistPolicy.DEFAULT);
for (String policyName : policyArray) {
SessionPersistPolicy policy = SessionPersistPolicy.fromName(policyName);
policySet.add(policy);
}
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<String> 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<String>(Arrays.asList(sentinelArray));
}
public Set<String> 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;
//nicole.gump modified for tomcat8.5
//for (Valve valve : getContainer().getPipeline().getValves()) {
for (Valve valve : getContext().getPipeline().getValves()) {
if (valve instanceof RedisSessionHandlerValve) {
this.handlerValve = (RedisSessionHandlerValve) valve;
this.handlerValve.setRedisSessionMan