package hirondelle.fish.test.doubles;
import java.io.FileNotFoundException;
import java.util.*;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpSessionBindingEvent;
import javax.servlet.http.HttpSessionContext;
import javax.servlet.http.HttpSessionBindingListener;
import hirondelle.web4j.util.Util;
import java.util.logging.*;
public class FakeSession implements HttpSession {
public static synchronized HttpSession joinOrCreate(String aRequestedSessionId, boolean aCreateNew){
HttpSession result = tryToJoinExistingSession(aRequestedSessionId);
if( result == null && aCreateNew ) {
result = createNewSession();
}
if( result != null ) {
fLogger.fine("Join/Create Session. Id: " + result.getId());
}
else {
fLogger.fine("No session was joined.");
}
return result;
}
public long getCreationTime() {
vomitIfInvalidated();
return fCreationTime;
}
public String getId() {
return fSessionId;
}
public long getLastAccessedTime() {
vomitIfInvalidated();
return fLastAccessTime;
}
public ServletContext getServletContext() {
return fServletContext;
}
public void setMaxInactiveInterval(int aInterval) {
fMaxInactiveInterval = aInterval;
}
public int getMaxInactiveInterval() {
return fMaxInactiveInterval;
}
public Enumeration getAttributeNames() {
vomitIfInvalidated();
Hashtable<String, Object> hashTable = new Hashtable<String, Object>(fAttributes);
return hashTable.keys();
}
public Object getAttribute(String aName) {
vomitIfInvalidated();
return fAttributes.get(aName);
}
public void setAttribute(String aName, Object aObject) {
vomitIfInvalidated();
Object existingObject = fAttributes.put(aName, aObject);
if( aObject instanceof HttpSessionBindingListener) {
HttpSessionBindingListener listener = (HttpSessionBindingListener)aObject;
Object value = (existingObject != null ? existingObject : aObject);
listener.valueBound(new HttpSessionBindingEvent(this, aName, value));
}
}
public void removeAttribute(String aName) {
vomitIfInvalidated();
Object existingObject = fAttributes.remove(aName);
if( existingObject instanceof HttpSessionBindingListener) {
HttpSessionBindingListener listener = (HttpSessionBindingListener)existingObject;
listener.valueUnbound(new HttpSessionBindingEvent(this, aName, existingObject));
}
}
public void invalidate() {
vomitIfInvalidated();
List<String> attrs = Collections.list(getAttributeNames());
for(String name: attrs){
removeAttribute(name);
}
fAttributes.clear();
fHasBeenInvalidated = true;
}
public boolean isNew() {
vomitIfInvalidated();
return fIsPropsective;
}
public void putValue(String aName, Object aValue) { }
public void removeValue(String aName) { }
public Object getValue(String aName) { return null; }
public HttpSessionContext getSessionContext() { return null; }
public String[] getValueNames() { return null; }
private static Map<String, FakeSession> fSessions = new LinkedHashMap<String, FakeSession>();
private static int fSessionIdGenerator;
private static synchronized String getNextSessionId(){
fSessionIdGenerator++;
return new Integer(fSessionIdGenerator).toString();
}
private static synchronized HttpSession tryToJoinExistingSession(String aSessionId){
HttpSession result = null;
FakeSession existingSession = fSessions.get(aSessionId);
if ( existingSession != null ) {
existingSession.updateTimes();
if( existingSession.hasTimedOut() ) {
existingSession.invalidate();
}
else {
existingSession.fIsPropsective = false;
result = existingSession;
}
}
return result;
}
private static synchronized HttpSession createNewSession(){
String id = getNextSessionId();
FakeSession result = new FakeSession(id);
fSessions.put(id, result);
return result;
}
private ServletContext fServletContext;
private long fCreationTime;
private String fSessionId;
private boolean fIsPropsective = true;
private long fLastAccessTime;
private long fCurrentAccessTime;
private int fMaxInactiveInterval = 60*30; private Map<String, Object> fAttributes = new LinkedHashMap<String, Object>();
private boolean fHasBeenInvalidated = false;
private static final Logger fLogger = Util.getLogger(FakeSession.class);
private FakeSession(String aSessionId){
fCreationTime = System.currentTimeMillis();
fLastAccessTime = fCreationTime;
fSessionId = aSessionId;
try {
fServletContext = new FakeServletContext();
}
catch(FileNotFoundException ex){
throw new IllegalArgumentException("Cannot construct FakeServletContext.");
}
}
private void vomitIfInvalidated() {
if (fHasBeenInvalidated) throw new IllegalStateException("Session has been invalidated.");
}
private void updateTimes(){
fLastAccessTime = fCurrentAccessTime; fCurrentAccessTime = System.currentTimeMillis();
}
private boolean hasTimedOut(){
return (fCurrentAccessTime - fLastAccessTime) > fMaxInactiveInterval * 1000;
}
}