package com.liuxinglanyue.session.redis.share;
import org.apache.catalina.session.StandardSession;
import org.apache.juli.logging.Log;
import org.apache.juli.logging.LogFactory;
import redis.clients.jedis.PipelineBlock;
import redis.clients.jedis.Protocol;
//imp tomcat StandardSession
public class RedisSession extends StandardSession {
private static final long serialVersionUID = 1L;
protected transient Log log = LogFactory.getLog(RedisSession.class);
protected transient RedisManager _manager;
protected transient PipelineBlock _expirePipeline = new RedisPipelineBlock(this) {
@Override
public void execute() {
_redisSession._manager.jedisHset(RedisManager.TOMCAT_SESSION_PREFIX + _redisSession.id, "__[creationTime]__",
String.valueOf(System.currentTimeMillis()).getBytes());
_redisSession._manager.jedisExpire(RedisManager.TOMCAT_SESSION_PREFIX + _redisSession.id, _redisSession.maxInactiveInterval);
}
};
public RedisSession(RedisManager manager) {
super(manager);
this._manager = manager;
}
/**
* Update the accessed time information for this session. This method should
* be called by the context when a request comes in for a particular
* session, even if the application does not reference it.
*/
@Override
public void access() {
if (_manager.debug) {
log.info("id=" + this.id);
}
super.access();
if (!_manager.isStarted()) {
return;
}
try {
if (_manager.jedisExpire(RedisManager.TOMCAT_SESSION_PREFIX + this.id, this.maxInactiveInterval) == 0) {
_manager.jedisPipelined(RedisManager.TOMCAT_SESSION_PREFIX + this.id, _expirePipeline);
}
} catch (Exception ex) {
log.error("error:", ex);
}
}
@Override
public Object getAttribute(String name) {
Object value = super.getAttribute(name);
if (name.startsWith("javax.zkoss.zk.ui.Session") || !_manager.isStarted()) {
return value;
}
try {
if (_manager.stickySession) {
if (value == null) {
byte[] bytesValue = _manager.jedisHget(RedisManager.TOMCAT_SESSION_PREFIX + this.id, name);
if (bytesValue == null) {
return null;
}
if (_manager.debug) {
log.info("id=" + this.id + ",name=" + name + ",strValue=" + new String(bytesValue, Protocol.CHARSET));
}
value = KryoSerializer.read(bytesValue);
super.setAttribute(name, value, false); // 属性添加到本地的attributes中.
return value;
} else {
return value;
}
} else { // 不是stickySessionEnabled,那么每次都要从redis里获取属性值.
byte[] bytesValue = _manager.jedisHget(RedisManager.TOMCAT_SESSION_PREFIX + this.id, name);
if (bytesValue == null) {
return value;
}
if (_manager.debug) {
log.info("id=" + this.id + ",name=" + name + ",strValue=" + new String(bytesValue, Protocol.CHARSET));
}
return KryoSerializer.read(bytesValue);
}
} catch (Exception ex) {
log.error("error:name=" + name + ";value=" + value, ex);
return value;
}
}
@Override
public void setAttribute(String name, Object value) {
super.setAttribute(name, value);
if (value == null || name.startsWith("javax.zkoss.zk.ui.Session") || !_manager.isStarted()) {
return;
}
try {
byte[] bytesValue = KryoSerializer.write(value);
if (_manager.debug) {
log.info("id=" + this.id + ",name=" + name + ",strValue=" + new String(bytesValue, Protocol.CHARSET));
}
_manager.jedisHset(RedisManager.TOMCAT_SESSION_PREFIX + this.id, name, bytesValue);
} catch (Exception ex) {
log.error("error:name=" + name + ";value=" + value, ex);
}
}
@Override
protected void removeAttributeInternal(String name, boolean notify) {
if (_manager.debug) {
log.info("id=" + this.id + ",name=" + name + ",notify=" + notify);
}
super.removeAttributeInternal(name, notify);
if (!_manager.isStarted()) {
return;
}
try {
_manager.jedisHdel(RedisManager.TOMCAT_SESSION_PREFIX + this.id, name);
} catch (Exception ex) {
log.error("error:", ex);
}
}
@Override
public void expire(boolean notify) {
if (_manager.debug) {
log.info("id=" + this.id + ",notify=" + notify);
}
super.expire(notify); // 在expire里就会清空当前session的所有属性
if (!_manager.isStarted()) {
return;
}
try {
_manager.jedisDel(RedisManager.TOMCAT_SESSION_PREFIX + this.id);
} catch (Exception ex) {
log.error("error:", ex);
}
}
void setCachedId(String id) {
this.id = id;
}
private static abstract class RedisPipelineBlock extends PipelineBlock {
RedisSession _redisSession;
RedisPipelineBlock(RedisSession redisSession) {
super();
_redisSession = redisSession;
}
}
}