Issue #2646 - Better handle concurrent calls to change session id and invalidate within a context (#2670)
* Issue #2646 handle concurrent invalidate/changeid calls Signed-off-by: Jan Bartel <janb@webtide.com>
This commit is contained in:
parent
54319589a4
commit
4e672c6b27
|
@ -151,8 +151,9 @@ public abstract class AbstractSessionCache extends ContainerLifeCycle implements
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove the session with this identity from the store
|
* Remove the session with this identity from the store
|
||||||
|
*
|
||||||
* @param id the id
|
* @param id the id
|
||||||
* @return true if removed false otherwise
|
* @return Session that was removed or null
|
||||||
*/
|
*/
|
||||||
public abstract Session doDelete (String id);
|
public abstract Session doDelete (String id);
|
||||||
|
|
||||||
|
@ -727,12 +728,8 @@ public abstract class AbstractSessionCache extends ContainerLifeCycle implements
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @see org.eclipse.jetty.server.session.SessionCache#renewSessionId(java.lang.String, java.lang.String)
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public Session renewSessionId (String oldId, String newId)
|
public Session renewSessionId (String oldId, String newId, String oldExtendedId, String newExtendedId)
|
||||||
throws Exception
|
throws Exception
|
||||||
{
|
{
|
||||||
if (StringUtil.isBlank(oldId))
|
if (StringUtil.isBlank(oldId))
|
||||||
|
@ -741,17 +738,40 @@ public abstract class AbstractSessionCache extends ContainerLifeCycle implements
|
||||||
throw new IllegalArgumentException ("New session id is null");
|
throw new IllegalArgumentException ("New session id is null");
|
||||||
|
|
||||||
Session session = get(oldId);
|
Session session = get(oldId);
|
||||||
|
renewSessionId(session, newId, newExtendedId);
|
||||||
|
|
||||||
|
return session;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Swap the id on a session.
|
||||||
|
*
|
||||||
|
* @param session the session for which to do the swap
|
||||||
|
* @param newId the new id
|
||||||
|
* @param newExtendedId the full id plus node id
|
||||||
|
*
|
||||||
|
* @throws Exception if there was a failure saving the change
|
||||||
|
*/
|
||||||
|
protected void renewSessionId (Session session, String newId, String newExtendedId)
|
||||||
|
throws Exception
|
||||||
|
{
|
||||||
if (session == null)
|
if (session == null)
|
||||||
return null;
|
return;
|
||||||
|
|
||||||
try (Lock lock = session.lock())
|
try (Lock lock = session.lock())
|
||||||
{
|
{
|
||||||
|
String oldId = session.getId();
|
||||||
session.checkValidForWrite(); //can't change id on invalid session
|
session.checkValidForWrite(); //can't change id on invalid session
|
||||||
session.getSessionData().setId(newId);
|
session.getSessionData().setId(newId);
|
||||||
session.getSessionData().setLastSaved(0); //pretend that the session has never been saved before to get a full save
|
session.getSessionData().setLastSaved(0); //pretend that the session has never been saved before to get a full save
|
||||||
session.getSessionData().setDirty(true); //ensure we will try to write the session out
|
session.getSessionData().setDirty(true); //ensure we will try to write the session out
|
||||||
|
session.setExtendedId(newExtendedId); //remember the new extended id
|
||||||
|
session.setIdChanged(true); //session id changed
|
||||||
|
|
||||||
doPutIfAbsent(newId, session); //put the new id into our map
|
doPutIfAbsent(newId, session); //put the new id into our map
|
||||||
doDelete (oldId); //take old out of map
|
doDelete (oldId); //take old out of map
|
||||||
|
|
||||||
if (_sessionDataStore != null)
|
if (_sessionDataStore != null)
|
||||||
{
|
{
|
||||||
_sessionDataStore.delete(oldId); //delete the session data with the old id
|
_sessionDataStore.delete(oldId); //delete the session data with the old id
|
||||||
|
@ -759,7 +779,6 @@ public abstract class AbstractSessionCache extends ContainerLifeCycle implements
|
||||||
}
|
}
|
||||||
if (LOG.isDebugEnabled())
|
if (LOG.isDebugEnabled())
|
||||||
LOG.debug ("Session id {} swapped for new id {}", oldId, newId);
|
LOG.debug ("Session id {} swapped for new id {}", oldId, newId);
|
||||||
return session;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,6 +25,7 @@ import java.util.Enumeration;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.concurrent.locks.Condition;
|
||||||
|
|
||||||
import javax.servlet.ServletContext;
|
import javax.servlet.ServletContext;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
@ -41,20 +42,17 @@ import org.eclipse.jetty.util.thread.Locker;
|
||||||
import org.eclipse.jetty.util.thread.Locker.Lock;
|
import org.eclipse.jetty.util.thread.Locker.Lock;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Session
|
* Session
|
||||||
*
|
*
|
||||||
* A heavy-weight Session object representing a HttpSession. Session objects
|
* A heavy-weight Session object representing a HttpSession. Session objects
|
||||||
* relating to a context are kept in a {@link SessionCache}. The purpose of
|
* relating to a context are kept in a {@link SessionCache}. The purpose of the
|
||||||
* the SessionCache is to keep the working set of Session objects in memory
|
* SessionCache is to keep the working set of Session objects in memory so that
|
||||||
* so that they may be accessed quickly, and facilitate the sharing of a
|
* they may be accessed quickly, and facilitate the sharing of a Session object
|
||||||
* Session object amongst multiple simultaneous requests referring to the
|
* amongst multiple simultaneous requests referring to the same session id.
|
||||||
* same session id.
|
|
||||||
*
|
*
|
||||||
* The {@link SessionHandler} coordinates
|
* The {@link SessionHandler} coordinates the lifecycle of Session objects with
|
||||||
* the lifecycle of Session objects with the help of the SessionCache.
|
* the help of the SessionCache.
|
||||||
*
|
*
|
||||||
* @see SessionHandler
|
* @see SessionHandler
|
||||||
* @see org.eclipse.jetty.server.SessionIdManager
|
* @see org.eclipse.jetty.server.SessionIdManager
|
||||||
|
@ -63,44 +61,54 @@ public class Session implements SessionHandler.SessionIf
|
||||||
{
|
{
|
||||||
private final static Logger LOG = Log.getLogger("org.eclipse.jetty.server.session");
|
private final static Logger LOG = Log.getLogger("org.eclipse.jetty.server.session");
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public final static String SESSION_CREATED_SECURE="org.eclipse.jetty.security.sessionCreatedSecure";
|
public final static String SESSION_CREATED_SECURE = "org.eclipse.jetty.security.sessionCreatedSecure";
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* State
|
* State
|
||||||
*
|
*
|
||||||
* Validity states of a session
|
* Validity states of a session
|
||||||
*/
|
*/
|
||||||
public enum State {VALID, INVALID, INVALIDATING};
|
public enum State
|
||||||
|
{
|
||||||
|
VALID, INVALID, INVALIDATING, CHANGING
|
||||||
|
};
|
||||||
|
|
||||||
|
public enum IdState
|
||||||
|
{
|
||||||
|
SET, CHANGING
|
||||||
|
};
|
||||||
|
|
||||||
|
protected final SessionData _sessionData; // the actual data associated with
|
||||||
|
// a session
|
||||||
|
|
||||||
|
protected final SessionHandler _handler; // the manager of the session
|
||||||
|
|
||||||
|
protected String _extendedId; // the _id plus the worker name
|
||||||
protected final SessionData _sessionData; //the actual data associated with a session
|
|
||||||
protected final SessionHandler _handler; //the manager of the session
|
|
||||||
protected String _extendedId; //the _id plus the worker name
|
|
||||||
protected long _requests;
|
protected long _requests;
|
||||||
|
|
||||||
protected boolean _idChanged;
|
protected boolean _idChanged;
|
||||||
|
|
||||||
protected boolean _newSession;
|
protected boolean _newSession;
|
||||||
protected State _state = State.VALID; //state of the session:valid,invalid or being invalidated
|
|
||||||
protected Locker _lock = new Locker(); //sync lock
|
protected State _state = State.VALID; // state of the session:valid,invalid
|
||||||
|
// or being invalidated
|
||||||
|
|
||||||
|
protected Locker _lock = new Locker(); // sync lock
|
||||||
|
protected Condition _stateChangeCompleted = _lock.newCondition();
|
||||||
protected boolean _resident = false;
|
protected boolean _resident = false;
|
||||||
protected final SessionInactivityTimer _sessionInactivityTimer;
|
protected final SessionInactivityTimer _sessionInactivityTimer;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------- */
|
/* ------------------------------------------------------------- */
|
||||||
/**
|
/**
|
||||||
* SessionInactivityTimer
|
* SessionInactivityTimer
|
||||||
*
|
*
|
||||||
* Each Session has a timer associated with it that fires whenever
|
* Each Session has a timer associated with it that fires whenever it has
|
||||||
* it has been idle (ie not accessed by a request) for a
|
* been idle (ie not accessed by a request) for a configurable amount of
|
||||||
* configurable amount of time, or the Session expires.
|
* time, or the Session expires.
|
||||||
*
|
*
|
||||||
* @see SessionCache
|
* @see SessionCache
|
||||||
*
|
*
|
||||||
|
@ -117,7 +125,8 @@ public class Session implements SessionHandler.SessionIf
|
||||||
@Override
|
@Override
|
||||||
public void onTimeoutExpired()
|
public void onTimeoutExpired()
|
||||||
{
|
{
|
||||||
if (LOG.isDebugEnabled()) LOG.debug("Timer expired for session {}", getId());
|
if (LOG.isDebugEnabled())
|
||||||
|
LOG.debug("Timer expired for session {}", getId());
|
||||||
getSessionHandler().sessionInactivityTimerExpired(Session.this);
|
getSessionHandler().sessionInactivityTimerExpired(Session.this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -126,45 +135,47 @@ public class Session implements SessionHandler.SessionIf
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param ms the timeout to set; -1 means that the timer will not be scheduled
|
* @param ms the timeout to set; -1 means that the timer will not be
|
||||||
|
* scheduled
|
||||||
*/
|
*/
|
||||||
public void setTimeout(long ms)
|
public void setTimeout(long ms)
|
||||||
{
|
{
|
||||||
_msec = ms;
|
_msec = ms;
|
||||||
if (LOG.isDebugEnabled()) LOG.debug("Session {} timer={}ms",getId(), ms);
|
if (LOG.isDebugEnabled())
|
||||||
|
LOG.debug("Session {} timer={}ms", getId(), ms);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void schedule()
|
||||||
public void schedule ()
|
|
||||||
{
|
{
|
||||||
if (_msec > 0)
|
if (_msec > 0)
|
||||||
{
|
{
|
||||||
if (LOG.isDebugEnabled()) LOG.debug("(Re)starting timer for session {} at {}ms",getId(), _msec);
|
if (LOG.isDebugEnabled())
|
||||||
|
LOG.debug("(Re)starting timer for session {} at {}ms", getId(), _msec);
|
||||||
_timer.schedule(_msec, TimeUnit.MILLISECONDS);
|
_timer.schedule(_msec, TimeUnit.MILLISECONDS);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (LOG.isDebugEnabled()) LOG.debug("Not starting timer for session {}",getId());
|
if (LOG.isDebugEnabled())
|
||||||
|
LOG.debug("Not starting timer for session {}", getId());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void cancel()
|
public void cancel()
|
||||||
{
|
{
|
||||||
_timer.cancel();
|
_timer.cancel();
|
||||||
if (LOG.isDebugEnabled()) LOG.debug("Cancelled timer for session {}",getId());
|
if (LOG.isDebugEnabled())
|
||||||
|
LOG.debug("Cancelled timer for session {}", getId());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void destroy()
|
||||||
public void destroy ()
|
|
||||||
{
|
{
|
||||||
_timer.destroy();
|
_timer.destroy();
|
||||||
if (LOG.isDebugEnabled()) LOG.debug("Destroyed timer for session {}",getId());
|
if (LOG.isDebugEnabled())
|
||||||
|
LOG.debug("Destroyed timer for session {}", getId());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------- */
|
/* ------------------------------------------------------------- */
|
||||||
/**
|
/**
|
||||||
* Create a new session
|
* Create a new session
|
||||||
|
@ -172,18 +183,18 @@ public class Session implements SessionHandler.SessionIf
|
||||||
* @param request the request the session should be based on
|
* @param request the request the session should be based on
|
||||||
* @param data the session data
|
* @param data the session data
|
||||||
*/
|
*/
|
||||||
public Session (SessionHandler handler, HttpServletRequest request, SessionData data)
|
public Session(SessionHandler handler, HttpServletRequest request, SessionData data)
|
||||||
{
|
{
|
||||||
_handler = handler;
|
_handler = handler;
|
||||||
_sessionData = data;
|
_sessionData = data;
|
||||||
_newSession = true;
|
_newSession = true;
|
||||||
_sessionData.setDirty(true);
|
_sessionData.setDirty(true);
|
||||||
_requests = 1; //access will not be called on this new session, but we are obviously in a request
|
_requests = 1; // access will not be called on this new session, but we
|
||||||
|
// are obviously in a request
|
||||||
_sessionInactivityTimer = new SessionInactivityTimer();
|
_sessionInactivityTimer = new SessionInactivityTimer();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------- */
|
/* ------------------------------------------------------------- */
|
||||||
/**
|
/**
|
||||||
* Re-inflate an existing session from some eg persistent store.
|
* Re-inflate an existing session from some eg persistent store.
|
||||||
|
@ -191,7 +202,7 @@ public class Session implements SessionHandler.SessionIf
|
||||||
* @param handler the SessionHandler managing the session
|
* @param handler the SessionHandler managing the session
|
||||||
* @param data the session data
|
* @param data the session data
|
||||||
*/
|
*/
|
||||||
public Session (SessionHandler handler, SessionData data)
|
public Session(SessionHandler handler, SessionData data)
|
||||||
{
|
{
|
||||||
_handler = handler;
|
_handler = handler;
|
||||||
_sessionData = data;
|
_sessionData = data;
|
||||||
|
@ -201,8 +212,7 @@ public class Session implements SessionHandler.SessionIf
|
||||||
|
|
||||||
/* ------------------------------------------------------------- */
|
/* ------------------------------------------------------------- */
|
||||||
/**
|
/**
|
||||||
* Returns the current number of requests that are active in the
|
* Returns the current number of requests that are active in the Session.
|
||||||
* Session.
|
|
||||||
*
|
*
|
||||||
* @return the number of active requests for this session
|
* @return the number of active requests for this session
|
||||||
*/
|
*/
|
||||||
|
@ -216,10 +226,8 @@ public class Session implements SessionHandler.SessionIf
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------- */
|
/* ------------------------------------------------------------- */
|
||||||
public void setExtendedId (String extendedId)
|
public void setExtendedId(String extendedId)
|
||||||
{
|
{
|
||||||
_extendedId = extendedId;
|
_extendedId = extendedId;
|
||||||
}
|
}
|
||||||
|
@ -239,7 +247,7 @@ public class Session implements SessionHandler.SessionIf
|
||||||
{
|
{
|
||||||
if (!isValid())
|
if (!isValid())
|
||||||
return false;
|
return false;
|
||||||
_newSession=false;
|
_newSession = false;
|
||||||
long lastAccessed = _sessionData.getAccessed();
|
long lastAccessed = _sessionData.getAccessed();
|
||||||
_sessionData.setAccessed(time);
|
_sessionData.setAccessed(time);
|
||||||
_sessionData.setLastAccessed(lastAccessed);
|
_sessionData.setLastAccessed(lastAccessed);
|
||||||
|
@ -251,8 +259,9 @@ public class Session implements SessionHandler.SessionIf
|
||||||
}
|
}
|
||||||
_requests++;
|
_requests++;
|
||||||
|
|
||||||
//temporarily stop the idle timer
|
// temporarily stop the idle timer
|
||||||
if (LOG.isDebugEnabled()) LOG.debug("Session {} accessed, stopping timer, active requests={}",getId(),_requests);
|
if (LOG.isDebugEnabled())
|
||||||
|
LOG.debug("Session {} accessed, stopping timer, active requests={}", getId(), _requests);
|
||||||
_sessionInactivityTimer.cancel();
|
_sessionInactivityTimer.cancel();
|
||||||
|
|
||||||
|
|
||||||
|
@ -267,18 +276,19 @@ public class Session implements SessionHandler.SessionIf
|
||||||
{
|
{
|
||||||
_requests--;
|
_requests--;
|
||||||
|
|
||||||
if (LOG.isDebugEnabled()) LOG.debug("Session {} complete, active requests={}",getId(),_requests);
|
if (LOG.isDebugEnabled())
|
||||||
|
LOG.debug("Session {} complete, active requests={}", getId(), _requests);
|
||||||
|
|
||||||
//start the inactivity timer
|
// start the inactivity timer
|
||||||
if (_requests == 0)
|
if (_requests == 0)
|
||||||
_sessionInactivityTimer.schedule();
|
_sessionInactivityTimer.schedule();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------- */
|
/* ------------------------------------------------------------- */
|
||||||
/** Check to see if session has expired as at the time given.
|
/**
|
||||||
|
* Check to see if session has expired as at the time given.
|
||||||
*
|
*
|
||||||
* @param time the time since the epoch in ms
|
* @param time the time since the epoch in ms
|
||||||
* @return true if expired
|
* @return true if expired
|
||||||
|
@ -291,82 +301,84 @@ public class Session implements SessionHandler.SessionIf
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------- */
|
/* ------------------------------------------------------------- */
|
||||||
/** Check if the Session has been idle longer than a number of seconds.
|
/**
|
||||||
|
* Check if the Session has been idle longer than a number of seconds.
|
||||||
*
|
*
|
||||||
* @param sec the number of seconds
|
* @param sec the number of seconds
|
||||||
* @return true if the session has been idle longer than the interval
|
* @return true if the session has been idle longer than the interval
|
||||||
*/
|
*/
|
||||||
protected boolean isIdleLongerThan (int sec)
|
protected boolean isIdleLongerThan(int sec)
|
||||||
{
|
{
|
||||||
long now = System.currentTimeMillis();
|
long now = System.currentTimeMillis();
|
||||||
try (Lock lock = _lock.lock())
|
try (Lock lock = _lock.lock())
|
||||||
{
|
{
|
||||||
return ((_sessionData.getAccessed() + (sec*1000)) <= now);
|
return ((_sessionData.getAccessed() + (sec * 1000)) <= now);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
/**
|
/**
|
||||||
* Call binding and attribute listeners based on the new and old
|
* Call binding and attribute listeners based on the new and old values of
|
||||||
* values of the attribute.
|
* the attribute.
|
||||||
*
|
*
|
||||||
* @param name name of the attribute
|
* @param name name of the attribute
|
||||||
* @param newValue new value of the attribute
|
* @param newValue new value of the attribute
|
||||||
* @param oldValue previous value of the attribute
|
* @param oldValue previous value of the attribute
|
||||||
* @throws IllegalStateException if no session manager can be find
|
* @throws IllegalStateException if no session manager can be find
|
||||||
*/
|
*/
|
||||||
protected void callSessionAttributeListeners (String name, Object newValue, Object oldValue)
|
protected void callSessionAttributeListeners(String name, Object newValue, Object oldValue)
|
||||||
{
|
{
|
||||||
if (newValue==null || !newValue.equals(oldValue))
|
if (newValue == null || !newValue.equals(oldValue))
|
||||||
{
|
{
|
||||||
if (oldValue!=null)
|
if (oldValue != null)
|
||||||
unbindValue(name,oldValue);
|
unbindValue(name, oldValue);
|
||||||
if (newValue!=null)
|
if (newValue != null)
|
||||||
bindValue(name,newValue);
|
bindValue(name, newValue);
|
||||||
|
|
||||||
if (_handler == null)
|
if (_handler == null)
|
||||||
throw new IllegalStateException ("No session manager for session "+ _sessionData.getId());
|
throw new IllegalStateException("No session manager for session " + _sessionData.getId());
|
||||||
|
|
||||||
_handler.doSessionAttributeListeners(this,name,oldValue,newValue);
|
_handler.doSessionAttributeListeners(this, name, oldValue, newValue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------- */
|
/* ------------------------------------------------------------- */
|
||||||
/**
|
/**
|
||||||
* Unbind value if value implements {@link HttpSessionBindingListener} (calls {@link HttpSessionBindingListener#valueUnbound(HttpSessionBindingEvent)})
|
* Unbind value if value implements {@link HttpSessionBindingListener}
|
||||||
|
* (calls
|
||||||
|
* {@link HttpSessionBindingListener#valueUnbound(HttpSessionBindingEvent)})
|
||||||
|
*
|
||||||
* @param name the name with which the object is bound or unbound
|
* @param name the name with which the object is bound or unbound
|
||||||
* @param value the bound value
|
* @param value the bound value
|
||||||
*/
|
*/
|
||||||
public void unbindValue(java.lang.String name, Object value)
|
public void unbindValue(java.lang.String name, Object value)
|
||||||
{
|
{
|
||||||
if (value!=null&&value instanceof HttpSessionBindingListener)
|
if (value != null && value instanceof HttpSessionBindingListener)
|
||||||
((HttpSessionBindingListener)value).valueUnbound(new HttpSessionBindingEvent(this,name));
|
((HttpSessionBindingListener) value).valueUnbound(new HttpSessionBindingEvent(this, name));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------- */
|
/* ------------------------------------------------------------- */
|
||||||
/**
|
/**
|
||||||
* Bind value if value implements {@link HttpSessionBindingListener} (calls {@link HttpSessionBindingListener#valueBound(HttpSessionBindingEvent)})
|
* Bind value if value implements {@link HttpSessionBindingListener} (calls
|
||||||
|
* {@link HttpSessionBindingListener#valueBound(HttpSessionBindingEvent)})
|
||||||
|
*
|
||||||
* @param name the name with which the object is bound or unbound
|
* @param name the name with which the object is bound or unbound
|
||||||
* @param value the bound value
|
* @param value the bound value
|
||||||
*/
|
*/
|
||||||
public void bindValue(java.lang.String name, Object value)
|
public void bindValue(java.lang.String name, Object value)
|
||||||
{
|
{
|
||||||
if (value!=null&&value instanceof HttpSessionBindingListener)
|
if (value != null && value instanceof HttpSessionBindingListener)
|
||||||
((HttpSessionBindingListener)value).valueBound(new HttpSessionBindingEvent(this,name));
|
((HttpSessionBindingListener) value).valueBound(new HttpSessionBindingEvent(this, name));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------- */
|
/* ------------------------------------------------------------- */
|
||||||
/**
|
/**
|
||||||
* Call the activation listeners. This must be called holding the
|
* Call the activation listeners. This must be called holding the lock.
|
||||||
* lock.
|
|
||||||
*/
|
*/
|
||||||
public void didActivate()
|
public void didActivate()
|
||||||
{
|
{
|
||||||
|
@ -385,8 +397,7 @@ public class Session implements SessionHandler.SessionIf
|
||||||
|
|
||||||
/* ------------------------------------------------------------- */
|
/* ------------------------------------------------------------- */
|
||||||
/**
|
/**
|
||||||
* Call the passivation listeners. This must be called holding the
|
* Call the passivation listeners. This must be called holding the lock
|
||||||
* lock
|
|
||||||
*/
|
*/
|
||||||
public void willPassivate()
|
public void willPassivate()
|
||||||
{
|
{
|
||||||
|
@ -407,10 +418,16 @@ public class Session implements SessionHandler.SessionIf
|
||||||
{
|
{
|
||||||
try (Lock lock = _lock.lock())
|
try (Lock lock = _lock.lock())
|
||||||
{
|
{
|
||||||
return _state==State.VALID;
|
return _state == State.VALID;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
public boolean isChanging()
|
||||||
|
{
|
||||||
|
checkLocked();
|
||||||
|
return _state == State.CHANGING;
|
||||||
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------- */
|
/* ------------------------------------------------------------- */
|
||||||
public long getCookieSetTime()
|
public long getCookieSetTime()
|
||||||
|
@ -433,8 +450,6 @@ public class Session implements SessionHandler.SessionIf
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see javax.servlet.http.HttpSession#getId()
|
* @see javax.servlet.http.HttpSession#getId()
|
||||||
*/
|
*/
|
||||||
|
@ -458,8 +473,7 @@ public class Session implements SessionHandler.SessionIf
|
||||||
return _sessionData.getContextPath();
|
return _sessionData.getContextPath();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getVHost()
|
||||||
public String getVHost ()
|
|
||||||
{
|
{
|
||||||
return _sessionData.getVhost();
|
return _sessionData.getVhost();
|
||||||
}
|
}
|
||||||
|
@ -484,7 +498,7 @@ public class Session implements SessionHandler.SessionIf
|
||||||
public ServletContext getServletContext()
|
public ServletContext getServletContext()
|
||||||
{
|
{
|
||||||
if (_handler == null)
|
if (_handler == null)
|
||||||
throw new IllegalStateException ("No session manager for session "+ _sessionData.getId());
|
throw new IllegalStateException("No session manager for session " + _sessionData.getId());
|
||||||
return _handler._context;
|
return _handler._context;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -496,7 +510,7 @@ public class Session implements SessionHandler.SessionIf
|
||||||
{
|
{
|
||||||
try (Lock lock = _lock.lock())
|
try (Lock lock = _lock.lock())
|
||||||
{
|
{
|
||||||
_sessionData.setMaxInactiveMs((long)secs*1000L);
|
_sessionData.setMaxInactiveMs((long) secs * 1000L);
|
||||||
_sessionData.calcAndSetExpiry();
|
_sessionData.calcAndSetExpiry();
|
||||||
_sessionData.setDirty(true);
|
_sessionData.setDirty(true);
|
||||||
updateInactivityTimer();
|
updateInactivityTimer();
|
||||||
|
@ -510,12 +524,11 @@ public class Session implements SessionHandler.SessionIf
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the inactivity timer to the smaller of the session maxInactivity
|
* Set the inactivity timer to the smaller of the session maxInactivity (ie
|
||||||
* (ie session-timeout from web.xml), or the inactive eviction time.
|
* session-timeout from web.xml), or the inactive eviction time.
|
||||||
*/
|
*/
|
||||||
public void updateInactivityTimer ()
|
public void updateInactivityTimer()
|
||||||
{
|
{
|
||||||
try (Lock lock = _lock.lock())
|
try (Lock lock = _lock.lock())
|
||||||
{
|
{
|
||||||
|
@ -524,47 +537,53 @@ public class Session implements SessionHandler.SessionIf
|
||||||
|
|
||||||
if (maxInactive <= 0)
|
if (maxInactive <= 0)
|
||||||
{
|
{
|
||||||
//sessions are immortal, they never expire
|
// sessions are immortal, they never expire
|
||||||
if (evictionPolicy < SessionCache.EVICT_ON_INACTIVITY)
|
if (evictionPolicy < SessionCache.EVICT_ON_INACTIVITY)
|
||||||
{
|
{
|
||||||
//we do not want to evict inactive sessions
|
// we do not want to evict inactive sessions
|
||||||
_sessionInactivityTimer.setTimeout(-1);
|
_sessionInactivityTimer.setTimeout(-1);
|
||||||
if (LOG.isDebugEnabled()) LOG.debug("Session {} is immortal && no inactivity eviction", getId());
|
if (LOG.isDebugEnabled())
|
||||||
|
LOG.debug("Session {} is immortal && no inactivity eviction", getId());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
//sessions are immortal but we want to evict after inactivity
|
// sessions are immortal but we want to evict after
|
||||||
|
// inactivity
|
||||||
_sessionInactivityTimer.setTimeout(TimeUnit.SECONDS.toMillis(evictionPolicy));
|
_sessionInactivityTimer.setTimeout(TimeUnit.SECONDS.toMillis(evictionPolicy));
|
||||||
if (LOG.isDebugEnabled()) LOG.debug("Session {} is immortal; evict after {} sec inactivity", getId(), evictionPolicy);
|
if (LOG.isDebugEnabled())
|
||||||
|
LOG.debug("Session {} is immortal; evict after {} sec inactivity", getId(), evictionPolicy);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
//sessions are not immortal
|
// sessions are not immortal
|
||||||
if (evictionPolicy == SessionCache.NEVER_EVICT)
|
if (evictionPolicy == SessionCache.NEVER_EVICT)
|
||||||
{
|
{
|
||||||
//timeout is just the maxInactive setting
|
// timeout is just the maxInactive setting
|
||||||
_sessionInactivityTimer.setTimeout(_sessionData.getMaxInactiveMs());
|
_sessionInactivityTimer.setTimeout(_sessionData.getMaxInactiveMs());
|
||||||
if (LOG.isDebugEnabled()) LOG.debug("Session {} no eviction", getId());
|
if (LOG.isDebugEnabled())
|
||||||
|
LOG.debug("Session {} no eviction", getId());
|
||||||
}
|
}
|
||||||
else if (evictionPolicy == SessionCache.EVICT_ON_SESSION_EXIT)
|
else if (evictionPolicy == SessionCache.EVICT_ON_SESSION_EXIT)
|
||||||
{
|
{
|
||||||
//session will not remain in the cache, so no timeout
|
// session will not remain in the cache, so no timeout
|
||||||
_sessionInactivityTimer.setTimeout(-1);
|
_sessionInactivityTimer.setTimeout(-1);
|
||||||
if (LOG.isDebugEnabled()) LOG.debug("Session {} evict on exit", getId());
|
if (LOG.isDebugEnabled())
|
||||||
|
LOG.debug("Session {} evict on exit", getId());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
//want to evict on idle: timer is lesser of the session's maxInactive and eviction timeout
|
// want to evict on idle: timer is lesser of the session's
|
||||||
|
// maxInactive and eviction timeout
|
||||||
_sessionInactivityTimer.setTimeout(Math.min(maxInactive, TimeUnit.SECONDS.toMillis(evictionPolicy)));
|
_sessionInactivityTimer.setTimeout(Math.min(maxInactive, TimeUnit.SECONDS.toMillis(evictionPolicy)));
|
||||||
if (LOG.isDebugEnabled()) LOG.debug("Session {} timer set to lesser of maxInactive={} and inactivityEvict={}", getId(), maxInactive, evictionPolicy);
|
if (LOG.isDebugEnabled())
|
||||||
|
LOG.debug("Session {} timer set to lesser of maxInactive={} and inactivityEvict={}", getId(), maxInactive, evictionPolicy);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see javax.servlet.http.HttpSession#getMaxInactiveInterval()
|
* @see javax.servlet.http.HttpSession#getMaxInactiveInterval()
|
||||||
*/
|
*/
|
||||||
|
@ -574,7 +593,7 @@ public class Session implements SessionHandler.SessionIf
|
||||||
try (Lock lock = _lock.lock())
|
try (Lock lock = _lock.lock())
|
||||||
{
|
{
|
||||||
long maxInactiveMs = _sessionData.getMaxInactiveMs();
|
long maxInactiveMs = _sessionData.getMaxInactiveMs();
|
||||||
return (int)(maxInactiveMs < 0 ? -1 : maxInactiveMs/1000);
|
return (int) (maxInactiveMs < 0 ? -1 : maxInactiveMs / 1000);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -595,7 +614,6 @@ public class Session implements SessionHandler.SessionIf
|
||||||
return _handler;
|
return _handler;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------- */
|
/* ------------------------------------------------------------- */
|
||||||
/**
|
/**
|
||||||
* Check that the session can be modified.
|
* Check that the session can be modified.
|
||||||
|
@ -607,40 +625,58 @@ public class Session implements SessionHandler.SessionIf
|
||||||
checkLocked();
|
checkLocked();
|
||||||
|
|
||||||
if (_state == State.INVALID)
|
if (_state == State.INVALID)
|
||||||
throw new IllegalStateException("Not valid for write: id="+_sessionData.getId()+" created="+_sessionData.getCreated()+" accessed="+_sessionData.getAccessed()+" lastaccessed="+_sessionData.getLastAccessed()+" maxInactiveMs="+_sessionData.getMaxInactiveMs()+" expiry="+_sessionData.getExpiry());
|
throw new IllegalStateException("Not valid for write: id=" + _sessionData.getId()
|
||||||
|
+ " created="
|
||||||
|
+ _sessionData.getCreated()
|
||||||
|
+ " accessed="
|
||||||
|
+ _sessionData.getAccessed()
|
||||||
|
+ " lastaccessed="
|
||||||
|
+ _sessionData.getLastAccessed()
|
||||||
|
+ " maxInactiveMs="
|
||||||
|
+ _sessionData.getMaxInactiveMs()
|
||||||
|
+ " expiry="
|
||||||
|
+ _sessionData.getExpiry());
|
||||||
|
|
||||||
if (_state == State.INVALIDATING)
|
if (_state == State.INVALIDATING)
|
||||||
return; //in the process of being invalidated, listeners may try to remove attributes
|
return; // in the process of being invalidated, listeners may try to
|
||||||
|
// remove attributes
|
||||||
|
|
||||||
if (!isResident())
|
if (!isResident())
|
||||||
throw new IllegalStateException("Not valid for write: id="+_sessionData.getId()+" not resident");
|
throw new IllegalStateException("Not valid for write: id=" + _sessionData.getId() + " not resident");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------- */
|
/* ------------------------------------------------------------- */
|
||||||
/**
|
/**
|
||||||
* Chech that the session data can be read.
|
* Chech that the session data can be read.
|
||||||
*
|
*
|
||||||
* @throws IllegalStateException if the session is invalid
|
* @throws IllegalStateException if the session is invalid
|
||||||
*/
|
*/
|
||||||
protected void checkValidForRead () throws IllegalStateException
|
protected void checkValidForRead() throws IllegalStateException
|
||||||
{
|
{
|
||||||
checkLocked();
|
checkLocked();
|
||||||
|
|
||||||
if (_state == State.INVALID)
|
if (_state == State.INVALID)
|
||||||
throw new IllegalStateException("Invalid for read: id="+_sessionData.getId()+" created="+_sessionData.getCreated()+" accessed="+_sessionData.getAccessed()+" lastaccessed="+_sessionData.getLastAccessed()+" maxInactiveMs="+_sessionData.getMaxInactiveMs()+" expiry="+_sessionData.getExpiry());
|
throw new IllegalStateException("Invalid for read: id=" + _sessionData.getId()
|
||||||
|
+ " created="
|
||||||
|
+ _sessionData.getCreated()
|
||||||
|
+ " accessed="
|
||||||
|
+ _sessionData.getAccessed()
|
||||||
|
+ " lastaccessed="
|
||||||
|
+ _sessionData.getLastAccessed()
|
||||||
|
+ " maxInactiveMs="
|
||||||
|
+ _sessionData.getMaxInactiveMs()
|
||||||
|
+ " expiry="
|
||||||
|
+ _sessionData.getExpiry());
|
||||||
|
|
||||||
if (_state == State.INVALIDATING)
|
if (_state == State.INVALIDATING)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!isResident())
|
if (!isResident())
|
||||||
throw new IllegalStateException("Invalid for read: id="+_sessionData.getId()+" not resident");
|
throw new IllegalStateException("Invalid for read: id=" + _sessionData.getId() + " not resident");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------- */
|
/* ------------------------------------------------------------- */
|
||||||
protected void checkLocked ()
|
protected void checkLocked() throws IllegalStateException
|
||||||
throws IllegalStateException
|
|
||||||
{
|
{
|
||||||
if (!_lock.isLocked())
|
if (!_lock.isLocked())
|
||||||
throw new IllegalStateException("Session not locked");
|
throw new IllegalStateException("Session not locked");
|
||||||
|
@ -682,7 +718,7 @@ public class Session implements SessionHandler.SessionIf
|
||||||
{
|
{
|
||||||
checkValidForRead();
|
checkValidForRead();
|
||||||
final Iterator<String> itor = _sessionData.getKeys().iterator();
|
final Iterator<String> itor = _sessionData.getKeys().iterator();
|
||||||
return new Enumeration<String> ()
|
return new Enumeration<String>()
|
||||||
{
|
{
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -702,8 +738,6 @@ public class Session implements SessionHandler.SessionIf
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
public int getAttributes()
|
public int getAttributes()
|
||||||
{
|
{
|
||||||
|
@ -711,8 +745,6 @@ public class Session implements SessionHandler.SessionIf
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
public Set<String> getNames()
|
public Set<String> getNames()
|
||||||
{
|
{
|
||||||
|
@ -744,38 +776,37 @@ public class Session implements SessionHandler.SessionIf
|
||||||
|
|
||||||
/* ------------------------------------------------------------- */
|
/* ------------------------------------------------------------- */
|
||||||
/**
|
/**
|
||||||
* @see javax.servlet.http.HttpSession#setAttribute(java.lang.String, java.lang.Object)
|
* @see javax.servlet.http.HttpSession#setAttribute(java.lang.String,
|
||||||
|
* java.lang.Object)
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void setAttribute(String name, Object value)
|
public void setAttribute(String name, Object value)
|
||||||
{
|
{
|
||||||
Object old=null;
|
Object old = null;
|
||||||
try (Lock lock = _lock.lock())
|
try (Lock lock = _lock.lock())
|
||||||
{
|
{
|
||||||
//if session is not valid, don't accept the set
|
// if session is not valid, don't accept the set
|
||||||
checkValidForWrite();
|
checkValidForWrite();
|
||||||
old=_sessionData.setAttribute(name,value);
|
old = _sessionData.setAttribute(name, value);
|
||||||
}
|
}
|
||||||
if (value == null && old == null)
|
if (value == null && old == null)
|
||||||
return; //if same as remove attribute but attribute was already removed, no change
|
return; // if same as remove attribute but attribute was already
|
||||||
|
// removed, no change
|
||||||
callSessionAttributeListeners(name, value, old);
|
callSessionAttributeListeners(name, value, old);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------- */
|
/* ------------------------------------------------------------- */
|
||||||
/**
|
/**
|
||||||
* @see javax.servlet.http.HttpSession#putValue(java.lang.String, java.lang.Object)
|
* @see javax.servlet.http.HttpSession#putValue(java.lang.String,
|
||||||
|
* java.lang.Object)
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
@Deprecated
|
@Deprecated
|
||||||
public void putValue(String name, Object value)
|
public void putValue(String name, Object value)
|
||||||
{
|
{
|
||||||
setAttribute(name,value);
|
setAttribute(name, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------- */
|
/* ------------------------------------------------------------- */
|
||||||
/**
|
/**
|
||||||
* @see javax.servlet.http.HttpSession#removeAttribute(java.lang.String)
|
* @see javax.servlet.http.HttpSession#removeAttribute(java.lang.String)
|
||||||
|
@ -786,8 +817,6 @@ public class Session implements SessionHandler.SessionIf
|
||||||
setAttribute(name, null);
|
setAttribute(name, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------- */
|
/* ------------------------------------------------------------- */
|
||||||
/**
|
/**
|
||||||
* @see javax.servlet.http.HttpSession#removeValue(java.lang.String)
|
* @see javax.servlet.http.HttpSession#removeValue(java.lang.String)
|
||||||
|
@ -800,40 +829,91 @@ public class Session implements SessionHandler.SessionIf
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
/** Force a change to the id of a session.
|
/**
|
||||||
|
* Force a change to the id of a session.
|
||||||
*
|
*
|
||||||
* @param request the Request associated with the call to change id.
|
* @param request the Request associated with the call to change id.
|
||||||
*/
|
*/
|
||||||
public void renewId(HttpServletRequest request)
|
public void renewId(HttpServletRequest request)
|
||||||
{
|
{
|
||||||
if (_handler == null)
|
if (_handler == null)
|
||||||
throw new IllegalStateException ("No session manager for session "+ _sessionData.getId());
|
throw new IllegalStateException("No session manager for session " + _sessionData.getId());
|
||||||
|
|
||||||
String id = null;
|
String id = null;
|
||||||
String extendedId = null;
|
String extendedId = null;
|
||||||
try (Lock lock = _lock.lock())
|
try (Lock lock = _lock.lock())
|
||||||
{
|
{
|
||||||
checkValidForWrite(); //don't renew id on a session that is not valid
|
while (true)
|
||||||
id = _sessionData.getId(); //grab the values as they are now
|
{
|
||||||
|
switch (_state)
|
||||||
|
{
|
||||||
|
case INVALID:
|
||||||
|
case INVALIDATING:
|
||||||
|
throw new IllegalStateException();
|
||||||
|
|
||||||
|
case CHANGING:
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_stateChangeCompleted.await();
|
||||||
|
}
|
||||||
|
catch (InterruptedException e)
|
||||||
|
{
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
|
||||||
|
case VALID:
|
||||||
|
_state = State.CHANGING;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new IllegalStateException();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
id = _sessionData.getId(); // grab the values as they are now
|
||||||
extendedId = getExtendedId();
|
extendedId = getExtendedId();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
String newId = _handler._sessionIdManager.renewSessionId(id, extendedId, request);
|
String newId = _handler._sessionIdManager.renewSessionId(id, extendedId, request);
|
||||||
|
|
||||||
try (Lock lock = _lock.lock())
|
try (Lock lock = _lock.lock())
|
||||||
{
|
{
|
||||||
checkValidForWrite();
|
switch (_state)
|
||||||
|
{
|
||||||
|
case CHANGING:
|
||||||
|
if (id.equals(newId))
|
||||||
|
throw new IllegalStateException("Unable to change session id");
|
||||||
|
|
||||||
|
// this shouldn't be necessary to do here EXCEPT that when a
|
||||||
|
// null session cache is
|
||||||
|
// used, a new Session object will be created during the
|
||||||
|
// call to renew, so this
|
||||||
|
// Session object will not have been modified.
|
||||||
_sessionData.setId(newId);
|
_sessionData.setId(newId);
|
||||||
setExtendedId(_handler._sessionIdManager.getExtendedId(newId, request));
|
setExtendedId(_handler._sessionIdManager.getExtendedId(newId, request));
|
||||||
}
|
|
||||||
setIdChanged(true);
|
setIdChanged(true);
|
||||||
}
|
|
||||||
|
|
||||||
|
_state = State.VALID;
|
||||||
|
_stateChangeCompleted.signalAll();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case INVALID:
|
||||||
|
case INVALIDATING:
|
||||||
|
throw new IllegalStateException("Session invalid");
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new IllegalStateException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------- */
|
/* ------------------------------------------------------------- */
|
||||||
/** Called by users to invalidate a session, or called by the
|
/**
|
||||||
* access method as a request enters the session if the session
|
* Called by users to invalidate a session, or called by the access method
|
||||||
* has expired, or called by manager as a result of scavenger
|
* as a request enters the session if the session has expired, or called by
|
||||||
* expiring session
|
* manager as a result of scavenger expiring session
|
||||||
*
|
*
|
||||||
* @see javax.servlet.http.HttpSession#invalidate()
|
* @see javax.servlet.http.HttpSession#invalidate()
|
||||||
*/
|
*/
|
||||||
|
@ -841,16 +921,28 @@ public class Session implements SessionHandler.SessionIf
|
||||||
public void invalidate()
|
public void invalidate()
|
||||||
{
|
{
|
||||||
if (_handler == null)
|
if (_handler == null)
|
||||||
throw new IllegalStateException ("No session manager for session "+ _sessionData.getId());
|
throw new IllegalStateException("No session manager for session " + _sessionData.getId());
|
||||||
|
|
||||||
boolean result = beginInvalidate();
|
boolean result = beginInvalidate();
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
//if the session was not already invalid, or in process of being invalidated, do invalidate
|
// if the session was not already invalid, or in process of being
|
||||||
|
// invalidated, do invalidate
|
||||||
if (result)
|
if (result)
|
||||||
{
|
{
|
||||||
//tell id mgr to remove session from all contexts
|
try
|
||||||
|
{
|
||||||
|
// do the invalidation
|
||||||
|
_handler.callSessionDestroyedListeners(this);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
// call the attribute removed listeners and finally mark it
|
||||||
|
// as invalid
|
||||||
|
finishInvalidate();
|
||||||
|
}
|
||||||
|
// tell id mgr to remove sessions with same id from all contexts
|
||||||
_handler.getSessionIdManager().invalidateAll(_sessionData.getId());
|
_handler.getSessionIdManager().invalidateAll(_sessionData.getId());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -861,20 +953,23 @@ public class Session implements SessionHandler.SessionIf
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------- */
|
/* ------------------------------------------------------------- */
|
||||||
/** Grab the lock on the session
|
/**
|
||||||
|
* Grab the lock on the session
|
||||||
|
*
|
||||||
* @return the lock
|
* @return the lock
|
||||||
*/
|
*/
|
||||||
public Lock lock ()
|
public Lock lock()
|
||||||
{
|
{
|
||||||
return _lock.lock();
|
return _lock.lock();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------- */
|
/* ------------------------------------------------------------- */
|
||||||
/** Grab the lock on the session if it isn't locked already
|
/**
|
||||||
|
* Grab the lock on the session if it isn't locked already
|
||||||
|
*
|
||||||
* @return the lock
|
* @return the lock
|
||||||
*/
|
*/
|
||||||
public Lock lockIfNotHeld ()
|
public Lock lockIfNotHeld()
|
||||||
{
|
{
|
||||||
return _lock.lock();
|
return _lock.lock();
|
||||||
}
|
}
|
||||||
|
@ -888,24 +983,49 @@ public class Session implements SessionHandler.SessionIf
|
||||||
boolean result = false;
|
boolean result = false;
|
||||||
|
|
||||||
try (Lock lock = _lock.lock())
|
try (Lock lock = _lock.lock())
|
||||||
|
{
|
||||||
|
|
||||||
|
while (true)
|
||||||
{
|
{
|
||||||
switch (_state)
|
switch (_state)
|
||||||
{
|
{
|
||||||
case INVALID:
|
case INVALID:
|
||||||
{
|
{
|
||||||
throw new IllegalStateException(); //spec does not allow invalidate of already invalid session
|
throw new IllegalStateException(); // spec does not
|
||||||
|
// allow invalidate
|
||||||
|
// of already invalid
|
||||||
|
// session
|
||||||
|
}
|
||||||
|
case INVALIDATING:
|
||||||
|
{
|
||||||
|
if (LOG.isDebugEnabled())
|
||||||
|
LOG.debug("Session {} already being invalidated", _sessionData.getId());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case CHANGING:
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_stateChangeCompleted.await();
|
||||||
|
}
|
||||||
|
catch (InterruptedException e)
|
||||||
|
{
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
case VALID:
|
case VALID:
|
||||||
{
|
{
|
||||||
//only first change from valid to invalidating should be actionable
|
// only first change from valid to invalidating should
|
||||||
|
// be actionable
|
||||||
result = true;
|
result = true;
|
||||||
_state = State.INVALIDATING;
|
_state = State.INVALIDATING;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
{
|
throw new IllegalStateException();
|
||||||
if (LOG.isDebugEnabled()) LOG.debug("Session {} already being invalidated", _sessionData.getId());
|
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -924,10 +1044,9 @@ public class Session implements SessionHandler.SessionIf
|
||||||
finishInvalidate();
|
finishInvalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------- */
|
/* ------------------------------------------------------------- */
|
||||||
/** Call HttpSessionAttributeListeners as part of invalidating
|
/**
|
||||||
* a Session.
|
* Call HttpSessionAttributeListeners as part of invalidating a Session.
|
||||||
*
|
*
|
||||||
* @throws IllegalStateException if no session manager can be find
|
* @throws IllegalStateException if no session manager can be find
|
||||||
*/
|
*/
|
||||||
|
@ -938,21 +1057,22 @@ public class Session implements SessionHandler.SessionIf
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (LOG.isDebugEnabled())
|
if (LOG.isDebugEnabled())
|
||||||
LOG.debug("invalidate {}",_sessionData.getId());
|
LOG.debug("invalidate {}", _sessionData.getId());
|
||||||
if (_state == State.VALID || _state == State.INVALIDATING)
|
if (_state == State.VALID || _state == State.INVALIDATING)
|
||||||
{
|
{
|
||||||
Set<String> keys = null;
|
Set<String> keys = null;
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
keys = _sessionData.getKeys();
|
keys = _sessionData.getKeys();
|
||||||
for (String key:keys)
|
for (String key : keys)
|
||||||
{
|
{
|
||||||
Object old=_sessionData.setAttribute(key,null);
|
Object old = _sessionData.setAttribute(key, null);
|
||||||
|
// if same as remove attribute but attribute was
|
||||||
|
// already removed, no change
|
||||||
if (old == null)
|
if (old == null)
|
||||||
return; //if same as remove attribute but attribute was already removed, no change
|
continue;
|
||||||
callSessionAttributeListeners(key, null, old);
|
callSessionAttributeListeners(key, null, old);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
while (!keys.isEmpty());
|
while (!keys.isEmpty());
|
||||||
}
|
}
|
||||||
|
@ -961,6 +1081,8 @@ public class Session implements SessionHandler.SessionIf
|
||||||
{
|
{
|
||||||
// mark as invalid
|
// mark as invalid
|
||||||
_state = State.INVALID;
|
_state = State.INVALID;
|
||||||
|
_handler.recordSessionTime(this);
|
||||||
|
_stateChangeCompleted.signalAll();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -977,19 +1099,17 @@ public class Session implements SessionHandler.SessionIf
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------- */
|
/* ------------------------------------------------------------- */
|
||||||
public void setIdChanged(boolean changed)
|
public void setIdChanged(boolean changed)
|
||||||
{
|
{
|
||||||
try (Lock lock = _lock.lock())
|
try (Lock lock = _lock.lock())
|
||||||
{
|
{
|
||||||
_idChanged=changed;
|
_idChanged = changed;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------- */
|
/* ------------------------------------------------------------- */
|
||||||
public boolean isIdChanged ()
|
public boolean isIdChanged()
|
||||||
{
|
{
|
||||||
try (Lock lock = _lock.lock())
|
try (Lock lock = _lock.lock())
|
||||||
{
|
{
|
||||||
|
@ -997,7 +1117,6 @@ public class Session implements SessionHandler.SessionIf
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------- */
|
/* ------------------------------------------------------------- */
|
||||||
@Override
|
@Override
|
||||||
public Session getSession()
|
public Session getSession()
|
||||||
|
@ -1013,7 +1132,7 @@ public class Session implements SessionHandler.SessionIf
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------- */
|
/* ------------------------------------------------------------- */
|
||||||
public void setResident (boolean resident)
|
public void setResident(boolean resident)
|
||||||
{
|
{
|
||||||
_resident = resident;
|
_resident = resident;
|
||||||
|
|
||||||
|
@ -1024,7 +1143,7 @@ public class Session implements SessionHandler.SessionIf
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------- */
|
/* ------------------------------------------------------------- */
|
||||||
public boolean isResident ()
|
public boolean isResident()
|
||||||
{
|
{
|
||||||
return _resident;
|
return _resident;
|
||||||
}
|
}
|
||||||
|
|
|
@ -91,16 +91,41 @@ public interface SessionCache extends LifeCycle
|
||||||
*/
|
*/
|
||||||
Session newSession (SessionData data);
|
Session newSession (SessionData data);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Change the id of a session.
|
||||||
|
*
|
||||||
|
* This method has been superceded by the 4 arg renewSessionId method and
|
||||||
|
* should no longer be called.
|
||||||
|
*
|
||||||
|
* @param oldId the old id
|
||||||
|
* @param newId the new id
|
||||||
|
* @return the changed Session
|
||||||
|
* @throws Exception if anything went wrong
|
||||||
|
* @deprecated use
|
||||||
|
* {@link #renewSessionId(String oldId, String newId, String oldExtendedId, String newExtendedId)}
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
|
default Session renewSessionId(String oldId, String newId) throws Exception
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Change the id of a Session.
|
* Change the id of a Session.
|
||||||
*
|
*
|
||||||
* @param oldId the current session id
|
* @param oldId the current session id
|
||||||
* @param newId the new session id
|
* @param newId the new session id
|
||||||
|
* @param oldExtendedId the current extended session id
|
||||||
|
* @param newExtendedId the new extended session id
|
||||||
* @return the Session after changing its id
|
* @return the Session after changing its id
|
||||||
* @throws Exception if any error occurred
|
* @throws Exception if any error occurred
|
||||||
*/
|
*/
|
||||||
Session renewSessionId (String oldId, String newId) throws Exception;
|
default Session renewSessionId(String oldId, String newId, String oldExtendedId, String newExtendedId) throws Exception
|
||||||
|
{
|
||||||
|
return renewSessionId(oldId, newId);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -18,6 +18,8 @@
|
||||||
|
|
||||||
package org.eclipse.jetty.server.session;
|
package org.eclipse.jetty.server.session;
|
||||||
|
|
||||||
|
import static java.lang.Math.round;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
@ -65,8 +67,6 @@ import org.eclipse.jetty.util.thread.Locker.Lock;
|
||||||
import org.eclipse.jetty.util.thread.ScheduledExecutorScheduler;
|
import org.eclipse.jetty.util.thread.ScheduledExecutorScheduler;
|
||||||
import org.eclipse.jetty.util.thread.Scheduler;
|
import org.eclipse.jetty.util.thread.Scheduler;
|
||||||
|
|
||||||
import static java.lang.Math.round;
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
/**
|
/**
|
||||||
* SessionHandler.
|
* SessionHandler.
|
||||||
|
@ -344,6 +344,60 @@ public class SessionHandler extends ScopedHandler
|
||||||
_sessionIdListeners.clear();
|
_sessionIdListeners.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Call the session lifecycle listeners
|
||||||
|
* @param session the session on which to call the lifecycle listeners
|
||||||
|
*/
|
||||||
|
protected void callSessionDestroyedListeners (Session session)
|
||||||
|
{
|
||||||
|
if (session == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (_sessionListeners!=null)
|
||||||
|
{
|
||||||
|
HttpSessionEvent event=new HttpSessionEvent(session);
|
||||||
|
for (int i = _sessionListeners.size()-1; i>=0; i--)
|
||||||
|
{
|
||||||
|
_sessionListeners.get(i).sessionDestroyed(event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Call the session lifecycle listeners
|
||||||
|
* @param session the session on which to call the lifecycle listeners
|
||||||
|
*/
|
||||||
|
protected void callSessionCreatedListeners (Session session)
|
||||||
|
{
|
||||||
|
if (session == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (_sessionListeners!=null)
|
||||||
|
{
|
||||||
|
HttpSessionEvent event=new HttpSessionEvent(session);
|
||||||
|
for (int i = _sessionListeners.size()-1; i>=0; i--)
|
||||||
|
{
|
||||||
|
_sessionListeners.get(i).sessionCreated(event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
protected void callSessionIdListeners (Session session, String oldId)
|
||||||
|
{
|
||||||
|
//inform the listeners
|
||||||
|
if (!_sessionIdListeners.isEmpty())
|
||||||
|
{
|
||||||
|
HttpSessionEvent event = new HttpSessionEvent(session);
|
||||||
|
for (HttpSessionIdListener l:_sessionIdListeners)
|
||||||
|
{
|
||||||
|
l.sessionIdChanged(event, oldId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
/**
|
/**
|
||||||
* Called by the {@link SessionHandler} when a session is last accessed by a request.
|
* Called by the {@link SessionHandler} when a session is last accessed by a request.
|
||||||
|
@ -793,15 +847,10 @@ public class SessionHandler extends ScopedHandler
|
||||||
_sessionCache.put(id, session);
|
_sessionCache.put(id, session);
|
||||||
_sessionsCreatedStats.increment();
|
_sessionsCreatedStats.increment();
|
||||||
|
|
||||||
if (request.isSecure())
|
if (request!=null && request.isSecure())
|
||||||
session.setAttribute(Session.SESSION_CREATED_SECURE, Boolean.TRUE);
|
session.setAttribute(Session.SESSION_CREATED_SECURE, Boolean.TRUE);
|
||||||
|
|
||||||
if (_sessionListeners!=null)
|
callSessionCreatedListeners(session);
|
||||||
{
|
|
||||||
HttpSessionEvent event=new HttpSessionEvent(session);
|
|
||||||
for (HttpSessionListener listener : _sessionListeners)
|
|
||||||
listener.sessionCreated(event);
|
|
||||||
}
|
|
||||||
|
|
||||||
return session;
|
return session;
|
||||||
}
|
}
|
||||||
|
@ -1183,24 +1232,15 @@ public class SessionHandler extends ScopedHandler
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Session session = _sessionCache.renewSessionId (oldId, newId); //swap the id over
|
Session session = _sessionCache.renewSessionId (oldId, newId, oldExtendedId, newExtendedId); //swap the id over
|
||||||
if (session == null)
|
if (session == null)
|
||||||
{
|
{
|
||||||
//session doesn't exist on this context
|
//session doesn't exist on this context
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
session.setExtendedId(newExtendedId); //remember the extended id
|
|
||||||
|
|
||||||
//inform the listeners
|
//inform the listeners
|
||||||
if (!_sessionIdListeners.isEmpty())
|
callSessionIdListeners(session, oldId);
|
||||||
{
|
|
||||||
HttpSessionEvent event = new HttpSessionEvent(session);
|
|
||||||
for (HttpSessionIdListener l:_sessionIdListeners)
|
|
||||||
{
|
|
||||||
l.sessionIdChanged(event, oldId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
|
@ -1208,30 +1248,64 @@ public class SessionHandler extends ScopedHandler
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Record length of time session has been active. Called when the
|
||||||
|
* session is about to be invalidated.
|
||||||
|
*
|
||||||
|
* @param session the session whose time to record
|
||||||
|
*/
|
||||||
|
protected void recordSessionTime (Session session)
|
||||||
|
{
|
||||||
|
_sessionTimeStats.record(round((System.currentTimeMillis() - session.getSessionData().getCreated())/1000.0));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
/**
|
/**
|
||||||
* Called when a session has expired.
|
* Called by SessionIdManager to remove a session that has been invalidated,
|
||||||
|
* either by this context or another context. Also called by
|
||||||
|
* SessionIdManager when a session has expired in either this context or
|
||||||
|
* another context.
|
||||||
*
|
*
|
||||||
* @param id the id to invalidate
|
* @param id the session id to invalidate
|
||||||
*/
|
*/
|
||||||
public void invalidate (String id)
|
public void invalidate (String id)
|
||||||
{
|
{
|
||||||
|
|
||||||
if (StringUtil.isBlank(id))
|
if (StringUtil.isBlank(id))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
//remove the session and call the destroy listeners
|
// Remove the Session object from the session cache and any backing
|
||||||
Session session = removeSession(id, true);
|
// data store
|
||||||
|
Session session = _sessionCache.delete(id);
|
||||||
if (session != null)
|
if (session != null)
|
||||||
{
|
{
|
||||||
_sessionTimeStats.record(round((System.currentTimeMillis() - session.getSessionData().getCreated())/1000.0));
|
//start invalidating if it is not already begun, and call the listeners
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (session.beginInvalidate())
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
callSessionDestroyedListeners(session);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
LOG.warn("Session listener threw exception", e);
|
||||||
|
}
|
||||||
|
//call the attribute removed listeners and finally mark it as invalid
|
||||||
session.finishInvalidate();
|
session.finishInvalidate();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
catch (IllegalStateException e)
|
||||||
|
{
|
||||||
|
if (LOG.isDebugEnabled()) LOG.debug("Session {} already invalid", session);
|
||||||
|
LOG.ignore(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
LOG.warn(e);
|
LOG.warn(e);
|
||||||
|
|
|
@ -34,7 +34,9 @@ import java.util.concurrent.TimeUnit;
|
||||||
import javax.servlet.http.HttpSessionActivationListener;
|
import javax.servlet.http.HttpSessionActivationListener;
|
||||||
import javax.servlet.http.HttpSessionEvent;
|
import javax.servlet.http.HttpSessionEvent;
|
||||||
|
|
||||||
|
import org.eclipse.jetty.server.Request;
|
||||||
import org.eclipse.jetty.server.Server;
|
import org.eclipse.jetty.server.Server;
|
||||||
|
import org.eclipse.jetty.server.SessionIdManager;
|
||||||
import org.eclipse.jetty.servlet.ServletContextHandler;
|
import org.eclipse.jetty.servlet.ServletContextHandler;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
@ -65,6 +67,100 @@ public class DefaultSessionCacheTest
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRenewIdMultipleRequests() throws Exception
|
||||||
|
{
|
||||||
|
//Test that invalidation happens on ALL copies of the session that are in-use by requests
|
||||||
|
Server server = new Server();
|
||||||
|
|
||||||
|
SessionIdManager sessionIdManager = new DefaultSessionIdManager(server);
|
||||||
|
server.setSessionIdManager(sessionIdManager);
|
||||||
|
ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS);
|
||||||
|
context.setContextPath("/test");
|
||||||
|
context.setServer(server);
|
||||||
|
context.getSessionHandler().setMaxInactiveInterval((int)TimeUnit.DAYS.toSeconds(1));
|
||||||
|
context.getSessionHandler().setSessionIdManager(sessionIdManager);
|
||||||
|
|
||||||
|
DefaultSessionCacheFactory cacheFactory = new DefaultSessionCacheFactory();
|
||||||
|
cacheFactory.setSaveOnCreate(true); //ensures that a session is persisted as soon as it is created
|
||||||
|
|
||||||
|
DefaultSessionCache cache = (DefaultSessionCache)cacheFactory.getSessionCache(context.getSessionHandler());
|
||||||
|
|
||||||
|
TestSessionDataStore store = new TestSessionDataStore();
|
||||||
|
cache.setSessionDataStore(store);
|
||||||
|
context.getSessionHandler().setSessionCache(cache);
|
||||||
|
TestHttpSessionListener listener = new TestHttpSessionListener();
|
||||||
|
context.getSessionHandler().addEventListener(listener);
|
||||||
|
|
||||||
|
server.setHandler(context);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
server.start();
|
||||||
|
|
||||||
|
//create a new session
|
||||||
|
Session s = (Session)context.getSessionHandler().newHttpSession(null);
|
||||||
|
String id = s.getId();
|
||||||
|
context.getSessionHandler().access(s, false); //simulate accessing the request
|
||||||
|
context.getSessionHandler().complete(s); //simulate completing the request
|
||||||
|
|
||||||
|
//make 1st request
|
||||||
|
final Session session = context.getSessionHandler().getSession(id); //get the session again
|
||||||
|
assertNotNull(session);
|
||||||
|
context.getSessionHandler().access(session, false); //simulate accessing the request
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//make 2nd request
|
||||||
|
final Session session2 = context.getSessionHandler().getSession(id); //get the session again
|
||||||
|
context.getSessionHandler().access(session2, false); //simulate accessing the request
|
||||||
|
assertNotNull(session2);
|
||||||
|
assertTrue(session == session2);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Thread t2 = new Thread(new Runnable()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void run()
|
||||||
|
{
|
||||||
|
System.err.println("Starting session id renewal");
|
||||||
|
session2.renewId(new Request(null,null));
|
||||||
|
System.err.println("Finished session id renewal");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
t2.start();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Thread t = new Thread(new Runnable()
|
||||||
|
{
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run()
|
||||||
|
{
|
||||||
|
System.err.println("Starting invalidation");
|
||||||
|
try{Thread.sleep(1000L);}catch (Exception e) {e.printStackTrace();}
|
||||||
|
session.invalidate();
|
||||||
|
System.err.println("Finished invalidation");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
t.start();
|
||||||
|
|
||||||
|
t.join();
|
||||||
|
t2.join();
|
||||||
|
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
server.stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test sessions are saved when shutdown with a store.
|
* Test sessions are saved when shutdown with a store.
|
||||||
|
@ -180,7 +276,7 @@ public class DefaultSessionCacheTest
|
||||||
cache.put("1234", session);
|
cache.put("1234", session);
|
||||||
assertTrue(cache.contains("1234"));
|
assertTrue(cache.contains("1234"));
|
||||||
|
|
||||||
cache.renewSessionId("1234", "5678");
|
cache.renewSessionId("1234", "5678", "1234.foo", "5678.foo");
|
||||||
|
|
||||||
assertTrue(cache.contains("5678"));
|
assertTrue(cache.contains("5678"));
|
||||||
assertFalse(cache.contains("1234"));
|
assertFalse(cache.contains("1234"));
|
||||||
|
|
Loading…
Reference in New Issue