package com.jqmobile.core.server.session;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import javax.servlet.http.HttpServletRequest;
import org.apache.struts2.ServletActionContext;
import com.jqmobile.core.http.HttpUtils;
import com.jqmobile.core.http.SessionExceedTimeException;
import com.jqmobile.core.http2.HttpException;
import com.jqmobile.core.utils.timer.TimerTask;
public abstract class Session extends TimerTask<Void, Boolean> implements ISession{
private static final int DefaultMaxInactiveInterval = 30*60000;
private static final String SESSION_ID=HttpUtils.REQUEST_SESSION;
private final static Map<String, Session> map = Collections.synchronizedMap(new HashMap<String, Session>());
public static Session getSession(){
String sessionId = getSessionId();
if(null == sessionId){
throw new SessionExceedTimeException("servlet session中找不到Session id, 请确认session已激活 或 struts框架使用正确");
}
Session session = map.get(sessionId);
if(null == session){
throw new SessionExceedTimeException(sessionId);
}
session.f5LastAccessedTime();
return session;
}
public static void vali(String sessionId, HttpServletRequest request) throws HttpException{
Session session = map.get(sessionId);
if(null == session){
throw new HttpException(HttpException.SESSION_TIMEOUT);
}else{
session.f5LastAccessedTime();
}
sessionid.set(session.getId());
session.servlet = request;
}
private final static ThreadLocal<String> sessionid = new ThreadLocal<String>();
private static String getSessionId() {
String str = sessionid.get();
if(null == str){
try{
HttpServletRequest request = ServletActionContext.getRequest();
str = (String) request.getSession().getAttribute(SESSION_ID);
}catch(Throwable e){
e.printStackTrace();
}
}
return str;
}
/**
* 激活Session(持有Session)
* @param request
*/
public static void activate(HttpServletRequest request){
Session session=null;
Object obj = null;
if(null != request)
obj = request.getSession().getAttribute(SESSION_ID);
if(null != obj && obj instanceof String){
session = map.get(obj);
if(null != session){
synchronized (session.lock) {
while(null != session.servlet){
try {
System.err.println("session lock,servlet request : "+session.servlet);
System.err.println("this servlet request is : "+request);
session.lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
session.f5LastAccessedTime();
}
}
if(null == session){
session = new BaseSessionImpl();
map.put(session.getId(), session);
session.execute();
if(null != request){
request.getSession().setAttribute(SESSION_ID, session.getId());
request.getSession().setMaxInactiveInterval(session.getMaxInactiveInterval());
}
}
sessionid.set(session.getId());
session.servlet = request;
}
/**
* 释放Session
*/
public static void release(){
Session session = null;
try{
session = getSession();
}catch(Throwable e){
}
if(null != session){
session.release_();
sessionid.remove();
}
}
private void release_() {
this.isNew = false;
this.servlet = null;
this.f5LastAccessedTime();
synchronized (this.lock) {
this.lock.notify();
}
}
public int getTimeOut(){
return maxInactiveInterval;
}
//================================================
private long lastAccessedTime=System.currentTimeMillis();
private int maxInactiveInterval=DefaultMaxInactiveInterval;
private boolean isNew = true;
private String userId;
private HttpServletRequest servlet;
private final Object lock = new Object();
private Session(){
}
/**
* 刷新最后一次访问时间
*/
private void f5LastAccessedTime(){
this.lastAccessedTime = System.currentTimeMillis();
}
/**
* 销毁
* (non-Javadoc)
* @see com.jqmobile.core.server.session.ISession#invalidate()
*/
@Override
public void invalidate() {
//销毁
release_();
map.remove(getId());
onCancelled();
}
public void setUserId(String userId){
this.userId = userId;
}
static class BaseSessionImpl extends Session{
private final long creationTime = System.currentTimeMillis();
private final String id = UUID.randomUUID().toString();
private final Map<String, Object> map = new HashMap<String, Object>();
@Override
public long getCreationTime() {
return creationTime;
}
@Override
public String getId() {
return id;
}
@Override
public long getLastAccessedTime() {
return super.lastAccessedTime;
}
@Override
public HttpServletRequest getHttpServletRequest() {
return super.servlet;
}
@Override
public void setMaxInactiveInterval(int interval) {
super.maxInactiveInterval = interval;
if(null != super.servlet){
super.servlet.getSession().setMaxInactiveInterval(getMaxInactiveInterval());
}
}
@Override
public int getMaxInactiveInterval() {
return super.maxInactiveInterval;
}
@Override
public Object getAttribute(String name) {
return map.get(name);
}
@Override
public void setAttribute(String name, Object value) {
map.put(name, value);
}
@Override
public void removeAttribute(String name) {
map.remove(name);
}
@Override
public boolean isNew() {
return super.isNew;
}
@Override
public String getUserId() {
return super.userId;
}
//
@Override
protected Boolean doInBackground(Void... params) throws Throwable {
return (System.currentTimeMillis()-getLastAccessedTime())>getMaxInactiveInterval();
}
@Override
protected void onPostExecute(Boolean result) {
if(result){
invalidate();
//System.out.println("invalidate session id : "+getId());
}
}
@Override
protected long period() {
return getMaxInactiveInterval()/3;
}
@Override
protected void onException(Throwable e) {
e.printStackTrace();
}
}
//========================================test
public static void main(String[] args) {
for(int i=0; i<1000; i++){
Session.activate(null);
System.out.println(Session.getSession().getId());
Session.release();
}
int i=0;
int mapCount=0;
while(true){
try {
Thread.sleep(1000);
System.out.println("============================= count:\t"+i++);
// if(0 == AsyncTask.getThreadCount()){
// conn.close();
//// testTime();
// return;
// }
int j=0;
int c = Session.map.size();
for(Session s : Session.map.values()){
if(c != mapCount){
System.out.println(c);
mapCount = c;
}
if(0==j++%3){
sessionid.set(s.getId());
getSession();
release();
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}