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:
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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());
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user