Update SessionEventRegistry to store all events

This ensures that if multiple events are published, we wait until the event
with the expected session id is fired.

Fixes gh-382
This commit is contained in:
Rob Winch
2016-02-23 15:19:40 -06:00
parent d5259bf0e9
commit 1871915c62
3 changed files with 47 additions and 38 deletions

View File

@@ -15,44 +15,58 @@
*/
package org.springframework.session.data;
import java.util.HashMap;
import java.util.Map;
import org.springframework.context.ApplicationListener;
import org.springframework.session.events.AbstractSessionEvent;
public class SessionEventRegistry implements ApplicationListener<AbstractSessionEvent> {
private AbstractSessionEvent event;
private Object lock = new Object();
private Map<String,AbstractSessionEvent> events = new HashMap<String,AbstractSessionEvent>();
private Map<String,Object> locks = new HashMap<String,Object>();
public void onApplicationEvent(AbstractSessionEvent event) {
this.event = event;
String sessionId = event.getSessionId();
this.events.put(sessionId, event);
Object lock = getLock(sessionId);
synchronized (lock) {
lock.notifyAll();
}
}
public void setLock(Object lock) {
this.lock = lock;
}
public void clear() {
this.event = null;
this.events.clear();
this.locks.clear();
}
public boolean receivedEvent() throws InterruptedException {
return waitForEvent() != null;
public boolean receivedEvent(String sessionId) throws InterruptedException {
return waitForEvent(sessionId) != null;
}
@SuppressWarnings("unchecked")
public <E extends AbstractSessionEvent> E getEvent() throws InterruptedException {
return (E) waitForEvent();
public <E extends AbstractSessionEvent> E getEvent(String sessionId) throws InterruptedException {
return (E) waitForEvent(sessionId);
}
@SuppressWarnings("unchecked")
private <E extends AbstractSessionEvent> E waitForEvent() throws InterruptedException {
private <E extends AbstractSessionEvent> E waitForEvent(String sessionId) throws InterruptedException {
Object lock = getLock(sessionId);
synchronized(lock) {
if(event == null) {
if(!events.containsKey(sessionId)) {
lock.wait(10000);
}
}
return (E) event;
return (E) events.get(sessionId);
}
private Object getLock(String sessionId) {
synchronized(locks) {
Object lock = locks.get(sessionId);
if(lock == null) {
lock = new Object();
locks.put(sessionId, lock);
}
return lock;
}
}
}

View File

@@ -97,8 +97,8 @@ public class RedisOperationsSessionRepositoryITests {
repository.save(toSave);
assertThat(registry.receivedEvent()).isTrue();
assertThat(registry.getEvent()).isInstanceOf(SessionCreatedEvent.class);
assertThat(registry.receivedEvent(toSave.getId())).isTrue();
assertThat(registry.getEvent(toSave.getId())).isInstanceOf(SessionCreatedEvent.class);
assertThat(redis.boundSetOps(usernameSessionKey).members()).contains(toSave.getId());
Session session = repository.getSession(toSave.getId());
@@ -112,10 +112,10 @@ public class RedisOperationsSessionRepositoryITests {
repository.delete(toSave.getId());
assertThat(repository.getSession(toSave.getId())).isNull();
assertThat(registry.getEvent()).isInstanceOf(SessionDestroyedEvent.class);
assertThat(registry.getEvent(toSave.getId())).isInstanceOf(SessionDestroyedEvent.class);
assertThat(redis.boundSetOps(usernameSessionKey).members()).doesNotContain(toSave.getId());
assertThat(registry.getEvent().getSession().getAttribute(expectedAttributeName))
assertThat(registry.getEvent(toSave.getId()).getSession().getAttribute(expectedAttributeName))
.isEqualTo(expectedAttributeValue);
}
@@ -157,7 +157,7 @@ public class RedisOperationsSessionRepositoryITests {
assertThat(findByPrincipalName.keySet()).containsOnly(toSave.getId());
repository.delete(toSave.getId());
registry.receivedEvent();
assertThat(registry.receivedEvent(toSave.getId())).isTrue();
findByPrincipalName = repository.findByIndexNameAndIndexValue(INDEX_NAME, principalName);
@@ -319,7 +319,7 @@ public class RedisOperationsSessionRepositoryITests {
assertThat(findByPrincipalName.keySet()).containsOnly(toSave.getId());
repository.delete(toSave.getId());
registry.receivedEvent();
assertThat(registry.receivedEvent(toSave.getId())).isTrue();
findByPrincipalName = repository.findByIndexNameAndIndexValue(INDEX_NAME, getSecurityName());

View File

@@ -63,12 +63,9 @@ public class EnableHazelcastHttpSessionEventsTests<S extends ExpiringSession> {
@Autowired
private SessionEventRegistry registry;
private final Object lock = new Object();
@Before
public void setup() {
registry.clear();
registry.setLock(lock);
}
@Test
@@ -88,8 +85,8 @@ public class EnableHazelcastHttpSessionEventsTests<S extends ExpiringSession> {
repository.save(sessionToSave);
assertThat(registry.receivedEvent()).isTrue();
assertThat(registry.getEvent()).isInstanceOf(SessionCreatedEvent.class);
assertThat(registry.receivedEvent(sessionToSave.getId())).isTrue();
assertThat(registry.getEvent(sessionToSave.getId())).isInstanceOf(SessionCreatedEvent.class);
Session session = repository.getSession(sessionToSave.getId());
@@ -104,18 +101,14 @@ public class EnableHazelcastHttpSessionEventsTests<S extends ExpiringSession> {
repository.save(sessionToSave);
assertThat(registry.receivedEvent()).isTrue();
assertThat(registry.getEvent()).isInstanceOf(SessionCreatedEvent.class);
assertThat(registry.receivedEvent(sessionToSave.getId())).isTrue();
assertThat(registry.getEvent(sessionToSave.getId())).isInstanceOf(SessionCreatedEvent.class);
registry.clear();
assertThat(sessionToSave.getMaxInactiveIntervalInSeconds()).isEqualTo(MAX_INACTIVE_INTERVAL_IN_SECONDS);
synchronized (lock) {
lock.wait((sessionToSave.getMaxInactiveIntervalInSeconds() * 1000) + 1);
}
assertThat(registry.receivedEvent()).isTrue();
assertThat(registry.getEvent()).isInstanceOf(SessionExpiredEvent.class);
assertThat(registry.receivedEvent(sessionToSave.getId())).isTrue();
assertThat(registry.getEvent(sessionToSave.getId())).isInstanceOf(SessionExpiredEvent.class);
assertThat(repository.getSession(sessionToSave.getId())).isNull();
}
@@ -126,20 +119,22 @@ public class EnableHazelcastHttpSessionEventsTests<S extends ExpiringSession> {
repository.save(sessionToSave);
assertThat(registry.receivedEvent()).isTrue();
assertThat(registry.getEvent()).isInstanceOf(SessionCreatedEvent.class);
assertThat(registry.receivedEvent(sessionToSave.getId())).isTrue();
assertThat(registry.getEvent(sessionToSave.getId())).isInstanceOf(SessionCreatedEvent.class);
registry.clear();
repository.delete(sessionToSave.getId());
assertThat(registry.receivedEvent()).isTrue();
assertThat(registry.getEvent()).isInstanceOf(SessionDeletedEvent.class);
assertThat(registry.receivedEvent(sessionToSave.getId())).isTrue();
assertThat(registry.getEvent(sessionToSave.getId())).isInstanceOf(SessionDeletedEvent.class);
assertThat(repository.getSession(sessionToSave.getId())).isNull();
}
@Test
public void saveUpdatesTimeToLiveTest() throws InterruptedException {
Object lock = new Object();
S sessionToSave = repository.createSession();
repository.save(sessionToSave);