SEC-484: fixed concurrency issue

This commit is contained in:
Vishal Puri 2007-07-23 07:58:31 +00:00
parent e70f01c260
commit 5ea8232f84
2 changed files with 203 additions and 178 deletions

View File

@ -34,7 +34,6 @@ import java.util.Set;
import javax.servlet.http.HttpSession; import javax.servlet.http.HttpSession;
/** /**
* Base implementation of {@link org.acegisecurity.concurrent.SessionRegistry} * Base implementation of {@link org.acegisecurity.concurrent.SessionRegistry}
* which also listens for {@link * which also listens for {@link
@ -49,16 +48,19 @@ import javax.servlet.http.HttpSession;
* </p> * </p>
* *
* @author Ben Alex * @author Ben Alex
* @version $Id${date} * @version $Id: SessionRegistryImpl.java 1862 2007-05-25 01:38:42Z benalex
* ${date}
*/ */
public class SessionRegistryImpl implements SessionRegistry, public class SessionRegistryImpl implements SessionRegistry,
ApplicationListener { ApplicationListener {
//~ Instance fields ======================================================== // ~ Instance fields
// ========================================================
private Map principals = Collections.synchronizedMap(new HashMap()); // <principal:Object,SessionIdSet> private Map principals = Collections.synchronizedMap(new HashMap()); // <principal:Object,SessionIdSet>
private Map sessionIds = Collections.synchronizedMap(new HashMap()); // <sessionId:Object,SessionInformation> private Map sessionIds = Collections.synchronizedMap(new HashMap()); // <sessionId:Object,SessionInformation>
//~ Methods ================================================================ // ~ Methods
// ================================================================
public Object[] getAllPrincipals() { public Object[] getAllPrincipals() {
return principals.keySet().toArray(); return principals.keySet().toArray();
@ -67,16 +69,15 @@ public class SessionRegistryImpl implements SessionRegistry,
public SessionInformation[] getAllSessions(Object principal, public SessionInformation[] getAllSessions(Object principal,
boolean includeExpiredSessions) { boolean includeExpiredSessions) {
Set sessionsUsedByPrincipal = (Set) principals.get(principal); Set sessionsUsedByPrincipal = (Set) principals.get(principal);
if (sessionsUsedByPrincipal == null) { if (sessionsUsedByPrincipal == null) {
return null; return null;
} }
List list = new ArrayList(); List list = new ArrayList();
Iterator iter = sessionsUsedByPrincipal.iterator();
while (iter.hasNext()) {
synchronized (sessionsUsedByPrincipal) { synchronized (sessionsUsedByPrincipal) {
for (Iterator iter = sessionsUsedByPrincipal.iterator(); iter
.hasNext();) {
String sessionId = (String) iter.next(); String sessionId = (String) iter.next();
SessionInformation sessionInformation = getSessionInformation(sessionId); SessionInformation sessionInformation = getSessionInformation(sessionId);
@ -90,7 +91,8 @@ public class SessionRegistryImpl implements SessionRegistry,
} }
public SessionInformation getSessionInformation(String sessionId) { public SessionInformation getSessionInformation(String sessionId) {
Assert.hasText(sessionId, "SessionId required as per interface contract"); Assert.hasText(sessionId,
"SessionId required as per interface contract");
return (SessionInformation) sessionIds.get(sessionId); return (SessionInformation) sessionIds.get(sessionId);
} }
@ -103,7 +105,8 @@ public class SessionRegistryImpl implements SessionRegistry,
} }
public void refreshLastRequest(String sessionId) { public void refreshLastRequest(String sessionId) {
Assert.hasText(sessionId, "SessionId required as per interface contract"); Assert.hasText(sessionId,
"SessionId required as per interface contract");
SessionInformation info = getSessionInformation(sessionId); SessionInformation info = getSessionInformation(sessionId);
@ -112,21 +115,25 @@ public class SessionRegistryImpl implements SessionRegistry,
} }
} }
public synchronized void registerNewSession(String sessionId, Object principal) { public synchronized void registerNewSession(String sessionId,
Assert.hasText(sessionId, "SessionId required as per interface contract"); Object principal) {
Assert.notNull(principal, "Principal required as per interface contract"); Assert.hasText(sessionId,
"SessionId required as per interface contract");
Assert.notNull(principal,
"Principal required as per interface contract");
if (getSessionInformation(sessionId) != null) { if (getSessionInformation(sessionId) != null) {
removeSessionInformation(sessionId); removeSessionInformation(sessionId);
} }
sessionIds.put(sessionId, sessionIds.put(sessionId, new SessionInformation(principal, sessionId,
new SessionInformation(principal, sessionId, new Date())); new Date()));
Set sessionsUsedByPrincipal = (Set) principals.get(principal); Set sessionsUsedByPrincipal = (Set) principals.get(principal);
if (sessionsUsedByPrincipal == null) { if (sessionsUsedByPrincipal == null) {
sessionsUsedByPrincipal = Collections.synchronizedSet(new HashSet()); sessionsUsedByPrincipal = Collections
.synchronizedSet(new HashSet());
} }
sessionsUsedByPrincipal.add(sessionId); sessionsUsedByPrincipal.add(sessionId);
@ -135,14 +142,16 @@ public class SessionRegistryImpl implements SessionRegistry,
} }
public void removeSessionInformation(String sessionId) { public void removeSessionInformation(String sessionId) {
Assert.hasText(sessionId, "SessionId required as per interface contract"); Assert.hasText(sessionId,
"SessionId required as per interface contract");
SessionInformation info = getSessionInformation(sessionId); SessionInformation info = getSessionInformation(sessionId);
if (info != null) { if (info != null) {
sessionIds.remove(sessionId); sessionIds.remove(sessionId);
Set sessionsUsedByPrincipal = (Set) principals.get(info.getPrincipal()); Set sessionsUsedByPrincipal = (Set) principals.get(info
.getPrincipal());
if (sessionsUsedByPrincipal != null) { if (sessionsUsedByPrincipal != null) {
synchronized (sessionsUsedByPrincipal) { synchronized (sessionsUsedByPrincipal) {

View File

@ -23,7 +23,6 @@ import org.springframework.mock.web.MockHttpSession;
import java.util.Date; import java.util.Date;
/** /**
* Tests {@link SessionRegistryImpl}. * Tests {@link SessionRegistryImpl}.
* *
@ -31,7 +30,8 @@ import java.util.Date;
* @version $Id$ * @version $Id$
*/ */
public class SessionRegistryImplTests extends TestCase { public class SessionRegistryImplTests extends TestCase {
//~ Methods ======================================================================================================== // ~ Methods
// ========================================================================================================
public void testEventPublishing() { public void testEventPublishing() {
MockHttpSession httpSession = new MockHttpSession(); MockHttpSession httpSession = new MockHttpSession();
@ -45,7 +45,8 @@ public class SessionRegistryImplTests extends TestCase {
sessionRegistry.registerNewSession(sessionId, principal); sessionRegistry.registerNewSession(sessionId, principal);
// Deregister session via an ApplicationEvent // Deregister session via an ApplicationEvent
sessionRegistry.onApplicationEvent(new HttpSessionDestroyedEvent(httpSession)); sessionRegistry.onApplicationEvent(new HttpSessionDestroyedEvent(
httpSession));
// Check attempts to retrieve cleared session return null // Check attempts to retrieve cleared session return null
assertNull(sessionRegistry.getSessionInformation(sessionId)); assertNull(sessionRegistry.getSessionInformation(sessionId));
@ -77,10 +78,14 @@ public class SessionRegistryImplTests extends TestCase {
sessionRegistry.registerNewSession(sessionId, principal); sessionRegistry.registerNewSession(sessionId, principal);
// Retrieve existing session by session ID // Retrieve existing session by session ID
Date currentDateTime = sessionRegistry.getSessionInformation(sessionId).getLastRequest(); Date currentDateTime = sessionRegistry.getSessionInformation(sessionId)
assertEquals(principal, sessionRegistry.getSessionInformation(sessionId).getPrincipal()); .getLastRequest();
assertEquals(sessionId, sessionRegistry.getSessionInformation(sessionId).getSessionId()); assertEquals(principal, sessionRegistry
assertNotNull(sessionRegistry.getSessionInformation(sessionId).getLastRequest()); .getSessionInformation(sessionId).getPrincipal());
assertEquals(sessionId, sessionRegistry
.getSessionInformation(sessionId).getSessionId());
assertNotNull(sessionRegistry.getSessionInformation(sessionId)
.getLastRequest());
// Retrieve existing session by principal // Retrieve existing session by principal
assertEquals(1, sessionRegistry.getAllSessions(principal, false).length); assertEquals(1, sessionRegistry.getAllSessions(principal, false).length);
@ -91,11 +96,13 @@ public class SessionRegistryImplTests extends TestCase {
// Update request date/time // Update request date/time
sessionRegistry.refreshLastRequest(sessionId); sessionRegistry.refreshLastRequest(sessionId);
Date retrieved = sessionRegistry.getSessionInformation(sessionId).getLastRequest(); Date retrieved = sessionRegistry.getSessionInformation(sessionId)
.getLastRequest();
assertTrue(retrieved.after(currentDateTime)); assertTrue(retrieved.after(currentDateTime));
// Check it retrieves correctly when looked up via principal // Check it retrieves correctly when looked up via principal
assertEquals(retrieved, sessionRegistry.getAllSessions(principal, false)[0].getLastRequest()); assertEquals(retrieved, sessionRegistry
.getAllSessions(principal, false)[0].getLastRequest());
// Clear session information // Clear session information
sessionRegistry.removeSessionInformation(sessionId); sessionRegistry.removeSessionInformation(sessionId);
@ -114,20 +121,25 @@ public class SessionRegistryImplTests extends TestCase {
// Register new Session // Register new Session
sessionRegistry.registerNewSession(sessionId1, principal); sessionRegistry.registerNewSession(sessionId1, principal);
assertEquals(1, sessionRegistry.getAllSessions(principal, false).length); assertEquals(1, sessionRegistry.getAllSessions(principal, false).length);
assertEquals(sessionId1, sessionRegistry.getAllSessions(principal, false)[0].getSessionId()); assertEquals(sessionId1, sessionRegistry.getAllSessions(principal,
false)[0].getSessionId());
// Register new Session // Register new Session
sessionRegistry.registerNewSession(sessionId2, principal); sessionRegistry.registerNewSession(sessionId2, principal);
assertEquals(2, sessionRegistry.getAllSessions(principal, false).length); assertEquals(2, sessionRegistry.getAllSessions(principal, false).length);
assertEquals(sessionId2, sessionRegistry.getAllSessions(principal, false)[1].getSessionId()); assertEquals(sessionId2, sessionRegistry.getAllSessions(principal,
false)[1].getSessionId());
// Expire one session // Expire one session
SessionInformation session = sessionRegistry.getSessionInformation(sessionId2); SessionInformation session = sessionRegistry
.getSessionInformation(sessionId2);
session.expireNow(); session.expireNow();
// Check retrieval still correct // Check retrieval still correct
assertTrue(sessionRegistry.getSessionInformation(sessionId2).isExpired()); assertTrue(sessionRegistry.getSessionInformation(sessionId2)
assertFalse(sessionRegistry.getSessionInformation(sessionId1).isExpired()); .isExpired());
assertFalse(sessionRegistry.getSessionInformation(sessionId1)
.isExpired());
} }
public void testTwoSessionsOnePrincipalHandling() throws Exception { public void testTwoSessionsOnePrincipalHandling() throws Exception {
@ -139,21 +151,25 @@ public class SessionRegistryImplTests extends TestCase {
// Register new Session // Register new Session
sessionRegistry.registerNewSession(sessionId1, principal); sessionRegistry.registerNewSession(sessionId1, principal);
assertEquals(1, sessionRegistry.getAllSessions(principal, false).length); assertEquals(1, sessionRegistry.getAllSessions(principal, false).length);
assertEquals(sessionId1, sessionRegistry.getAllSessions(principal, false)[0].getSessionId()); assertEquals(sessionId1, sessionRegistry.getAllSessions(principal,
false)[0].getSessionId());
// Register new Session // Register new Session
sessionRegistry.registerNewSession(sessionId2, principal); sessionRegistry.registerNewSession(sessionId2, principal);
assertEquals(2, sessionRegistry.getAllSessions(principal, false).length); assertEquals(2, sessionRegistry.getAllSessions(principal, false).length);
assertEquals(sessionId2, sessionRegistry.getAllSessions(principal, false)[1].getSessionId()); assertEquals(sessionId2, sessionRegistry.getAllSessions(principal,
false)[1].getSessionId());
// Clear session information // Clear session information
sessionRegistry.removeSessionInformation(sessionId1); sessionRegistry.removeSessionInformation(sessionId1);
assertEquals(1, sessionRegistry.getAllSessions(principal, false).length); assertEquals(1, sessionRegistry.getAllSessions(principal, false).length);
assertEquals(sessionId2, sessionRegistry.getAllSessions(principal, false)[0].getSessionId()); assertEquals(sessionId2, sessionRegistry.getAllSessions(principal,
false)[0].getSessionId());
// Clear final session // Clear final session
sessionRegistry.removeSessionInformation(sessionId2); sessionRegistry.removeSessionInformation(sessionId2);
assertNull(sessionRegistry.getSessionInformation(sessionId2)); assertNull(sessionRegistry.getSessionInformation(sessionId2));
assertNull(sessionRegistry.getAllSessions(principal, false)); assertNull(sessionRegistry.getAllSessions(principal, false));
} }
} }