You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@shiro.apache.org by lh...@apache.org on 2009/07/25 01:19:11 UTC
svn commit: r797689 - in /incubator/shiro/trunk:
core/src/main/java/org/apache/shiro/session/
core/src/main/java/org/apache/shiro/session/mgt/
web/src/main/java/org/apache/shiro/web/session/
web/src/test/java/org/apache/shiro/web/
Author: lhazlewood
Date: Fri Jul 24 23:19:11 2009
New Revision: 797689
URL: http://svn.apache.org/viewvc?rev=797689&view=rev
Log:
Fixed a few bugs related to remote proxy Session management (exceptions not properly propagating to the correct layer). Added some performance enhancements in the DelegatingWebSecurityManager to cache the session on a thread-local instead of regularly accessing the back-end system avoiding network round-trips where possible.
Modified:
incubator/shiro/trunk/core/src/main/java/org/apache/shiro/session/SessionListener.java
incubator/shiro/trunk/core/src/main/java/org/apache/shiro/session/mgt/AbstractValidatingSessionManager.java
incubator/shiro/trunk/core/src/main/java/org/apache/shiro/session/mgt/DelegatingSession.java
incubator/shiro/trunk/web/src/main/java/org/apache/shiro/web/session/DefaultWebSessionManager.java
incubator/shiro/trunk/web/src/main/java/org/apache/shiro/web/session/DelegatingWebSessionManager.java
incubator/shiro/trunk/web/src/test/java/org/apache/shiro/web/DelegatingWebSecurityManagerTest.java
Modified: incubator/shiro/trunk/core/src/main/java/org/apache/shiro/session/SessionListener.java
URL: http://svn.apache.org/viewvc/incubator/shiro/trunk/core/src/main/java/org/apache/shiro/session/SessionListener.java?rev=797689&r1=797688&r2=797689&view=diff
==============================================================================
--- incubator/shiro/trunk/core/src/main/java/org/apache/shiro/session/SessionListener.java (original)
+++ incubator/shiro/trunk/core/src/main/java/org/apache/shiro/session/SessionListener.java Fri Jul 24 23:19:11 2009
@@ -19,7 +19,7 @@
package org.apache.shiro.session;
/**
- * Interface to be implemented by components that wish to be notified of events that occur during a
+ * Interface to be implemented by components that wish to be notified of events that occur during a
* {@link Session Session}'s lifecycle.
*
* @author Les Hazlewood
Modified: incubator/shiro/trunk/core/src/main/java/org/apache/shiro/session/mgt/AbstractValidatingSessionManager.java
URL: http://svn.apache.org/viewvc/incubator/shiro/trunk/core/src/main/java/org/apache/shiro/session/mgt/AbstractValidatingSessionManager.java?rev=797689&r1=797688&r2=797689&view=diff
==============================================================================
--- incubator/shiro/trunk/core/src/main/java/org/apache/shiro/session/mgt/AbstractValidatingSessionManager.java (original)
+++ incubator/shiro/trunk/core/src/main/java/org/apache/shiro/session/mgt/AbstractValidatingSessionManager.java Fri Jul 24 23:19:11 2009
@@ -158,8 +158,9 @@
return inet;
}
- private void assertNotNull(Session session, Serializable sessionId) throws UnknownSessionException {
+ private void ensureNotNull(Session session, Serializable sessionId) throws UnknownSessionException {
if (session == null) {
+ onUnknownSession(sessionId);
throw new UnknownSessionException(sessionId);
}
}
@@ -173,14 +174,13 @@
InetAddress hostAddress = null;
try {
Session s = retrieveSession(sessionId);
- assertNotNull(s, sessionId);
+ ensureNotNull(s, sessionId);
// Save the host address in case the session will be invalidated.
// We want to retain it in case it is needed for a replacement session
hostAddress = getHostAddressFallback(s);
validate(s);
return s;
} catch (InvalidSessionException ise) {
- onInvalidSessionId(sessionId);
if (!isAutoCreateWhenInvalid()) {
throw ise;
}
@@ -193,9 +193,6 @@
}
}
- protected void onInvalidSessionId(Serializable id) {
- }
-
/**
* Looks up a session from the underlying data store based on the specified {@code sessionId}.
*
@@ -246,6 +243,20 @@
afterStopped(s);
}
+ /**
+ * Notification callback for subclasses that occurs when a client attempts to reference the session with the
+ * specified ID, but there does not exist any session with that id.
+ * <p/>
+ * A common case of this ocurring is if the client's referenced session times out and is deleted before the next
+ * time they interact with the system (such as often occurs with stale session id cookies in an web environment).
+ * The next time they send a request with the stale session id, this method would be called.
+ *
+ * @param sessionId the session id used to try and reference the non-existent session.
+ * @since 1.0
+ */
+ public void onUnknownSession(Serializable sessionId) {
+ }
+
protected void onExpiration(Session session) {
onChange(session);
}
Modified: incubator/shiro/trunk/core/src/main/java/org/apache/shiro/session/mgt/DelegatingSession.java
URL: http://svn.apache.org/viewvc/incubator/shiro/trunk/core/src/main/java/org/apache/shiro/session/mgt/DelegatingSession.java?rev=797689&r1=797688&r2=797689&view=diff
==============================================================================
--- incubator/shiro/trunk/core/src/main/java/org/apache/shiro/session/mgt/DelegatingSession.java (original)
+++ incubator/shiro/trunk/core/src/main/java/org/apache/shiro/session/mgt/DelegatingSession.java Fri Jul 24 23:19:11 2009
@@ -54,6 +54,7 @@
//cached fields to avoid a server-side method call if out-of-process:
private Date startTimestamp = null;
private InetAddress hostAddress = null;
+ private boolean handleReplacedSessions = true;
/**
* Handle to a server-side SessionManager. See {@link #setSessionManager} for details.
@@ -69,6 +70,14 @@
this.id = id;
}
+ public DelegatingSession(SessionManager sessionManager, Serializable id,
+ InetAddress hostAddress, boolean handleReplacedSessions) {
+ this.sessionManager = sessionManager;
+ this.id = id;
+ this.hostAddress = hostAddress;
+ this.handleReplacedSessions = handleReplacedSessions;
+ }
+
/**
* Returns the {@link SessionManager SessionManager} used by this handle to invoke
* all session-related methods.
@@ -100,6 +109,14 @@
this.sessionManager = sessionManager;
}
+ public boolean isHandleReplacedSessions() {
+ return handleReplacedSessions;
+ }
+
+ public void setHandleReplacedSessions(boolean handleReplacedSessions) {
+ this.handleReplacedSessions = handleReplacedSessions;
+ }
+
/**
* Sets the sessionId used by this handle for all future {@link SessionManager SessionManager}
* method invocations.
@@ -126,6 +143,10 @@
try {
startTimestamp = sessionManager.getStartTimestamp(id);
} catch (ReplacedSessionException e) {
+ if (!isHandleReplacedSessions()) {
+ //propagate immediately
+ throw e;
+ }
this.id = e.getNewSessionId();
startTimestamp = sessionManager.getStartTimestamp(id);
}
@@ -141,6 +162,10 @@
try {
return sessionManager.getLastAccessTime(id);
} catch (ReplacedSessionException e) {
+ if (!isHandleReplacedSessions()) {
+ //propagate immediately
+ throw e;
+ }
this.id = e.getNewSessionId();
return sessionManager.getLastAccessTime(id);
}
@@ -150,6 +175,10 @@
try {
return sessionManager.getTimeout(id);
} catch (ReplacedSessionException e) {
+ if (!isHandleReplacedSessions()) {
+ //propagate immediately
+ throw e;
+ }
this.id = e.getNewSessionId();
return sessionManager.getTimeout(id);
}
@@ -159,6 +188,10 @@
try {
sessionManager.setTimeout(id, maxIdleTimeInMillis);
} catch (ReplacedSessionException e) {
+ if (!isHandleReplacedSessions()) {
+ //propagate immediately
+ throw e;
+ }
this.id = e.getNewSessionId();
sessionManager.setTimeout(id, maxIdleTimeInMillis);
}
@@ -172,6 +205,10 @@
try {
hostAddress = sessionManager.getHostAddress(id);
} catch (ReplacedSessionException e) {
+ if (!isHandleReplacedSessions()) {
+ //propagate immediately
+ throw e;
+ }
this.id = e.getNewSessionId();
hostAddress = sessionManager.getHostAddress(id);
}
@@ -186,6 +223,10 @@
try {
sessionManager.touch(id);
} catch (ReplacedSessionException e) {
+ if (!isHandleReplacedSessions()) {
+ //propagate immediately
+ throw e;
+ }
this.id = e.getNewSessionId();
// No need to 'hit' the session manager again - a newly created session is 'touched' at the time of creation
}
@@ -198,6 +239,10 @@
try {
sessionManager.stop(id);
} catch (ReplacedSessionException e) {
+ if (!isHandleReplacedSessions()) {
+ //propagate immediately
+ throw e;
+ }
this.id = e.getNewSessionId();
//TODO - prevent sessionManager from creating new session when 'stop' is already requested.
sessionManager.stop(id);
@@ -212,6 +257,10 @@
try {
return sessionManager.getAttributeKeys(id);
} catch (ReplacedSessionException e) {
+ if (!isHandleReplacedSessions()) {
+ //propagate immediately
+ throw e;
+ }
this.id = e.getNewSessionId();
// No need to 'hit' the session manager again - a new session won't have any attributes:
return Collections.EMPTY_SET;
@@ -225,6 +274,10 @@
try {
return sessionManager.getAttribute(id, key);
} catch (ReplacedSessionException e) {
+ if (!isHandleReplacedSessions()) {
+ //propagate immediately
+ throw e;
+ }
this.id = e.getNewSessionId();
// No need to 'hit' the session manager again - a new session won't have any attributes
return null;
@@ -241,6 +294,10 @@
try {
sessionManager.setAttribute(id, key, value);
} catch (ReplacedSessionException e) {
+ if (!isHandleReplacedSessions()) {
+ //propagate immediately
+ throw e;
+ }
this.id = e.getNewSessionId();
sessionManager.setAttribute(id, key, value);
}
@@ -254,6 +311,10 @@
try {
return sessionManager.removeAttribute(id, key);
} catch (ReplacedSessionException e) {
+ if (!isHandleReplacedSessions()) {
+ //propagate immediately
+ throw e;
+ }
this.id = e.getNewSessionId();
// No need to 'hit' the session manager again - a new session won't have any attributes:
return null;
Modified: incubator/shiro/trunk/web/src/main/java/org/apache/shiro/web/session/DefaultWebSessionManager.java
URL: http://svn.apache.org/viewvc/incubator/shiro/trunk/web/src/main/java/org/apache/shiro/web/session/DefaultWebSessionManager.java?rev=797689&r1=797688&r2=797689&view=diff
==============================================================================
--- incubator/shiro/trunk/web/src/main/java/org/apache/shiro/web/session/DefaultWebSessionManager.java (original)
+++ incubator/shiro/trunk/web/src/main/java/org/apache/shiro/web/session/DefaultWebSessionManager.java Fri Jul 24 23:19:11 2009
@@ -112,6 +112,10 @@
request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_IS_VALID, Boolean.TRUE);
}
+ private void markSessionIdInvalid(ServletRequest request) {
+ request.removeAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_IS_VALID);
+ }
+
private void removeSessionIdCookie(ServletRequest request, ServletResponse response) {
getSessionIdCookieAttribute().removeValue(request, response);
}
@@ -131,6 +135,9 @@
}
if (id != null) {
request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID, id);
+ //automatically mark it valid here. If it is invalid, the
+ //onUnknownSession method below will be invoked and we'll remove the attribute at that time.
+ markSessionIdValid(id, request);
}
return id;
}
@@ -154,6 +161,12 @@
return getReferencedSessionId(request, response);
}
+ @Override
+ public void onUnknownSession(Serializable sessionId) {
+ markSessionIdInvalid(WebUtils.getRequiredServletRequest());
+ removeSessionIdCookie();
+ }
+
protected void onStop(Session session) {
super.onStop(session);
removeSessionIdCookie();
Modified: incubator/shiro/trunk/web/src/main/java/org/apache/shiro/web/session/DelegatingWebSessionManager.java
URL: http://svn.apache.org/viewvc/incubator/shiro/trunk/web/src/main/java/org/apache/shiro/web/session/DelegatingWebSessionManager.java?rev=797689&r1=797688&r2=797689&view=diff
==============================================================================
--- incubator/shiro/trunk/web/src/main/java/org/apache/shiro/web/session/DelegatingWebSessionManager.java (original)
+++ incubator/shiro/trunk/web/src/main/java/org/apache/shiro/web/session/DelegatingWebSessionManager.java Fri Jul 24 23:19:11 2009
@@ -18,12 +18,20 @@
*/
package org.apache.shiro.web.session;
+import org.apache.shiro.authz.AuthorizationException;
import org.apache.shiro.session.InvalidSessionException;
import org.apache.shiro.session.Session;
+import org.apache.shiro.session.SessionException;
import org.apache.shiro.session.mgt.DelegatingSession;
import org.apache.shiro.session.mgt.SessionManager;
+import org.apache.shiro.util.ThreadContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import java.io.Serializable;
+import java.net.InetAddress;
+import java.util.Collection;
+import java.util.Date;
import java.util.Map;
/**
@@ -44,6 +52,8 @@
*/
public class DelegatingWebSessionManager extends DefaultWebSessionManager {
+ private static transient final Logger log = LoggerFactory.getLogger(DelegatingWebSessionManager.class);
+
private static final String THREAD_CONTEXT_SESSION_KEY =
DelegatingWebSessionManager.class.getName() + ".THREAD_CONTEXT_SESSION_KEY";
@@ -55,11 +65,11 @@
public DelegatingWebSessionManager(SessionManager delegateSessionManager) {
this();
- this.delegateSessionManager = delegateSessionManager;
+ this.delegateSessionManager = new ThreadClearingSessionManager(delegateSessionManager);
}
public void setDelegateSessionManager(SessionManager delegateSessionManager) {
- this.delegateSessionManager = delegateSessionManager;
+ this.delegateSessionManager = new ThreadClearingSessionManager(delegateSessionManager);
}
private void assertDelegateExists() {
@@ -97,19 +107,29 @@
@Override
protected Session retrieveSessionFromDataSource(Serializable id) throws InvalidSessionException {
- /*Session session = (Session)ThreadContext.get(THREAD_CONTEXT_SESSION_KEY);
- if ( session != null ) {
+ //use thread-local caching to eliminate repeated 'hits' on the back-end data store during
+ //the thread execution. We do this here and not in the parent class since we can ensure the
+ //ThreadContext is being cleared at the end of each request due to the ShiroFilter being required in web
+ //environments (which automatically clears the thread).
+ Session session = (Session) ThreadContext.get(THREAD_CONTEXT_SESSION_KEY);
+ if (session != null) {
+ log.trace("Returning thread-cached session.");
return session;
- }*/
+ }
assertDelegateExists();
- this.delegateSessionManager.checkValid(id);
- return new DelegatingSession(this.delegateSessionManager, id);
- /*//we need the DelegatingSession to reference the delegateSessionManager and not 'this' so
- //we avoid an infinite loop:
- session = new DelegatingSession(this.delegateSessionManager, id);
+ //get the host address and bind it to the thread. This call will both validate the session as well as
+ //make it accessible for futher host checks:
+ InetAddress host = this.delegateSessionManager.getHostAddress(id);
+ session = new DelegatingSession(this.delegateSessionManager, id, host, false);
+ log.trace("Cached the session retrieved from the datasource in a thread-local for continued thread access.");
ThreadContext.put(THREAD_CONTEXT_SESSION_KEY, session);
-
- return session;*/
+
+ return session;
+ }
+
+ protected void removeThreadBoundSession() {
+ log.debug("Session is invalid or an invalid id was encountered. Unbinding the thread-cached session.");
+ ThreadContext.remove(THREAD_CONTEXT_SESSION_KEY);
}
@Override
@@ -119,14 +139,157 @@
@Override
protected void doValidate(Session session) throws InvalidSessionException {
- /*if ( session == null ) {
- throw new InvalidSessionException("Session method argument is null!" );
+ //do nothing - we rely on lazy session exceptions and recreation via the SessionManagerProxy to avoid
+ //costly validation checks on each session access.
+ }
+
+
+ private interface SessionManagerCallback {
+ Object doWithSessionManager(SessionManager sm) throws SessionException;
+ }
+
+ private class ThreadClearingSessionManager implements SessionManager {
+
+ private final SessionManager target;
+
+ private ThreadClearingSessionManager(SessionManager target) {
+ this.target = target;
}
- Serializable id = session.getId();
- if ( id == null ) {
- throw new InvalidSessionException("Session does not have an id!" );
+
+ private Object execute(SessionManagerCallback smc) throws SessionException {
+ try {
+ return smc.doWithSessionManager(target);
+ } catch (SessionException se) {
+ removeThreadBoundSession();
+ //propagate after cleanup:
+ throw se;
+ }
+ }
+
+ public Serializable start(final InetAddress originatingHost) throws AuthorizationException {
+ return (Serializable) execute(new SessionManagerCallback() {
+ public Object doWithSessionManager(SessionManager sm) throws SessionException {
+ return sm.start(originatingHost);
+ }
+ });
+ }
+
+ public Serializable start(final Map initData) throws AuthorizationException {
+ return (Serializable) execute(new SessionManagerCallback() {
+ public Object doWithSessionManager(SessionManager sm) throws SessionException {
+ return sm.start(initData);
+ }
+ });
+ }
+
+ public Date getStartTimestamp(final Serializable sessionId) {
+ return (Date) execute(new SessionManagerCallback() {
+ public Object doWithSessionManager(SessionManager sm) throws SessionException {
+ return sm.getStartTimestamp(sessionId);
+ }
+ });
+ }
+
+ public Date getLastAccessTime(final Serializable sessionId) {
+ return (Date) execute(new SessionManagerCallback() {
+ public Object doWithSessionManager(SessionManager sm) throws SessionException {
+ return sm.getLastAccessTime(sessionId);
+ }
+ });
+ }
+
+ public boolean isValid(final Serializable sessionId) {
+ return (Boolean) execute(new SessionManagerCallback() {
+ public Object doWithSessionManager(SessionManager sm) throws SessionException {
+ return sm.isValid(sessionId);
+ }
+ });
+ }
+
+ public void checkValid(final Serializable sessionId) throws InvalidSessionException {
+ execute(new SessionManagerCallback() {
+ public Object doWithSessionManager(SessionManager sm) throws SessionException {
+ sm.checkValid(sessionId);
+ return null;
+ }
+ });
+ }
+
+ public long getTimeout(final Serializable sessionId) throws InvalidSessionException {
+ return (Long) execute(new SessionManagerCallback() {
+ public Object doWithSessionManager(SessionManager sm) throws SessionException {
+ return sm.getTimeout(sessionId);
+ }
+ });
+ }
+
+ public void setTimeout(final Serializable sessionId, final long maxIdleTimeInMillis) throws InvalidSessionException {
+ execute(new SessionManagerCallback() {
+ public Object doWithSessionManager(SessionManager sm) throws SessionException {
+ sm.setTimeout(sessionId, maxIdleTimeInMillis);
+ return null;
+ }
+ });
+ }
+
+ public void touch(final Serializable sessionId) throws InvalidSessionException {
+ execute(new SessionManagerCallback() {
+ public Object doWithSessionManager(SessionManager sm) throws SessionException {
+ sm.touch(sessionId);
+ return null;
+ }
+ });
+ }
+
+ public InetAddress getHostAddress(final Serializable sessionId) {
+ return (InetAddress) execute(new SessionManagerCallback() {
+ public Object doWithSessionManager(SessionManager sm) throws SessionException {
+ return sm.getHostAddress(sessionId);
+ }
+ });
+ }
+
+ public void stop(final Serializable sessionId) throws InvalidSessionException {
+ execute(new SessionManagerCallback() {
+ public Object doWithSessionManager(SessionManager sm) throws SessionException {
+ sm.stop(sessionId);
+ return null;
+ }
+ });
+ }
+
+ @SuppressWarnings({"unchecked"})
+ public Collection<Object> getAttributeKeys(final Serializable sessionId) {
+ return (Collection<Object>) execute(new SessionManagerCallback() {
+ public Object doWithSessionManager(SessionManager sm) throws SessionException {
+ return sm.getAttributeKeys(sessionId);
+ }
+ });
+ }
+
+ public Object getAttribute(final Serializable sessionId, final Object key) throws InvalidSessionException {
+ return execute(new SessionManagerCallback() {
+ public Object doWithSessionManager(SessionManager sm) throws SessionException {
+ return sm.getAttribute(sessionId, key);
+ }
+ });
+ }
+
+ public void setAttribute(final Serializable sessionId, final Object key, final Object value) throws InvalidSessionException {
+ execute(new SessionManagerCallback() {
+ public Object doWithSessionManager(SessionManager sm) throws SessionException {
+ sm.setAttribute(sessionId, key, value);
+ return null;
+ }
+ });
+ }
+
+ public Object removeAttribute(final Serializable sessionId, final Object key) throws InvalidSessionException {
+ return execute(new SessionManagerCallback() {
+ public Object doWithSessionManager(SessionManager sm) throws SessionException {
+ return sm.removeAttribute(sessionId, key);
+ }
+ });
}
- assertDelegateExists();
- this.delegateSessionManager.checkValid(id);*/
}
}
Modified: incubator/shiro/trunk/web/src/test/java/org/apache/shiro/web/DelegatingWebSecurityManagerTest.java
URL: http://svn.apache.org/viewvc/incubator/shiro/trunk/web/src/test/java/org/apache/shiro/web/DelegatingWebSecurityManagerTest.java?rev=797689&r1=797688&r2=797689&view=diff
==============================================================================
--- incubator/shiro/trunk/web/src/test/java/org/apache/shiro/web/DelegatingWebSecurityManagerTest.java (original)
+++ incubator/shiro/trunk/web/src/test/java/org/apache/shiro/web/DelegatingWebSecurityManagerTest.java Fri Jul 24 23:19:11 2009
@@ -1,9 +1,10 @@
package org.apache.shiro.web;
-import org.apache.shiro.SecurityUtils;
-import org.apache.shiro.mgt.DefaultSecurityManager;
-import org.apache.shiro.realm.text.PropertiesRealm;
+import org.apache.shiro.mgt.SecurityManager;
+import org.apache.shiro.session.ExpiredSessionException;
+import org.apache.shiro.session.ReplacedSessionException;
import org.apache.shiro.session.Session;
+import org.apache.shiro.session.mgt.AbstractSessionManager;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.ThreadContext;
import static org.easymock.EasyMock.*;
@@ -16,6 +17,10 @@
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.Serializable;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.Map;
+import java.util.UUID;
/**
* Unit test for the {@link org.apache.shiro.web.DelegatingWebSecurityManager} implementation.
@@ -24,23 +29,18 @@
*/
public class DelegatingWebSecurityManagerTest {
- private DefaultSecurityManager delegate;
private DelegatingWebSecurityManager sm;
@Before
public void setup() {
- delegate = new DefaultSecurityManager();
- delegate.setRealm(new PropertiesRealm());
- sm = new DelegatingWebSecurityManager();
- sm.setDelegateSecurityManager(delegate);
- SecurityUtils.setSecurityManager(sm);
ThreadContext.clear();
+ sm = new DelegatingWebSecurityManager();
+ ThreadContext.bind(sm);
}
@After
public void tearDown() {
sm.destroy();
- delegate.destroy();
ThreadContext.clear();
}
@@ -54,8 +54,9 @@
@Test
public void testSessionTimeout() {
- long globalTimeout = 100;
- delegate.setGlobalSessionTimeout(globalTimeout);
+
+ SecurityManager delegate = createMock(SecurityManager.class);
+ sm.setDelegateSecurityManager(delegate);
HttpServletRequest mockRequest = createNiceMock(HttpServletRequest.class);
WebUtils.bind(mockRequest);
@@ -65,18 +66,48 @@
expect(mockRequest.getCookies()).andReturn(null);
expect(mockRequest.getContextPath()).andReturn("/");
+ InetAddress host;
+ try {
+ host = InetAddress.getByName("192.168.1.1");
+ } catch (UnknownHostException e) {
+ throw new IllegalStateException(e);
+ }
+
+ Serializable sessionId = UUID.randomUUID().toString();
+ expect(delegate.start((Map) null)).andReturn(sessionId);
+ expect(delegate.getHostAddress(sessionId)).andReturn(host);
+ expect(delegate.getTimeout(sessionId)).andReturn(AbstractSessionManager.DEFAULT_GLOBAL_SESSION_TIMEOUT);
+ delegate.setTimeout(sessionId, 125);
+ expectLastCall().times(1);
+ expect(delegate.getTimeout(sessionId)).andReturn(125L);
+ //pretend that 125ms have gone by
+ Serializable replacedSessionId = UUID.randomUUID().toString();
+ @SuppressWarnings({"ThrowableInstanceNeverThrown"})
+ ReplacedSessionException replaced =
+ new ReplacedSessionException("test", new ExpiredSessionException(sessionId),
+ sessionId, replacedSessionId);
+ expect(delegate.getTimeout(sessionId)).andThrow(replaced);
+ //the DelegatingSession will re-try the call on a ReplacedSessionException
+ expect(delegate.getHostAddress(replacedSessionId)).andReturn(host);
+ expect(delegate.getTimeout(replacedSessionId)).andReturn(AbstractSessionManager.DEFAULT_GLOBAL_SESSION_TIMEOUT);
+
+ replay(delegate);
replay(mockRequest);
Subject subject = sm.getSubject();
Session session = subject.getSession();
- Serializable origId = session.getId();
- assertEquals(globalTimeout, session.getTimeout());
+ String id = session.getId().toString();
+ assertEquals(AbstractSessionManager.DEFAULT_GLOBAL_SESSION_TIMEOUT, session.getTimeout());
session.setTimeout(125);
assertEquals(125, session.getTimeout());
- sleep(175);
+ //sleep(175);
//now the underlying session should have been expired and a new one replaced by default.
//so ensure the replaced session has the default session timeout:
- assertEquals(globalTimeout, session.getTimeout());
- assertFalse(origId.equals(session.getId())); //new ID would have been generated
+ long timeout = session.getTimeout();
+ assertEquals(AbstractSessionManager.DEFAULT_GLOBAL_SESSION_TIMEOUT, timeout);
+ assertFalse(id.equals(session.getId())); //new ID would have been generated
+
+ verify(delegate);
+ verify(mockRequest);
}
}