Skip to content

Commit 0484016

Browse files
committed
DefaultSubscriptionRegistry returns safe to iterate Map
Prior to this change when adding subscriptions DefaultSubscriptionRegistry (incorrectly) made a copy of the given map for its "access" cache rather than for its "update" cache. Issue: SPR-12665
1 parent 6fce6d4 commit 0484016

File tree

3 files changed

+29
-7
lines changed

3 files changed

+29
-7
lines changed

spring-messaging/src/main/java/org/springframework/messaging/simp/broker/DefaultSubscriptionRegistry.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2014 the original author or authors.
2+
* Copyright 2002-2015 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -32,6 +32,7 @@
3232
import org.springframework.util.MultiValueMap;
3333
import org.springframework.util.PathMatcher;
3434

35+
3536
/**
3637
* A default, simple in-memory implementation of {@link SubscriptionRegistry}.
3738
*
@@ -165,8 +166,8 @@ public MultiValueMap<String, String> getSubscriptions(String destination) {
165166

166167
public void addSubscriptions(String destination, MultiValueMap<String, String> subscriptions) {
167168
synchronized (this.updateCache) {
168-
this.updateCache.put(destination, subscriptions);
169-
this.accessCache.put(destination, new LinkedMultiValueMap<String, String>(subscriptions));
169+
this.updateCache.put(destination, new LinkedMultiValueMap<String, String>(subscriptions));
170+
this.accessCache.put(destination, subscriptions);
170171
}
171172
}
172173

spring-messaging/src/main/java/org/springframework/messaging/simp/broker/SubscriptionRegistry.java

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2013 the original author or authors.
2+
* Copyright 2002-2015 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -45,9 +45,11 @@ public interface SubscriptionRegistry {
4545
void unregisterAllSubscriptions(String sessionId);
4646

4747
/**
48-
* Find all subscriptions that should receive the given message.
48+
* Find all subscriptions that should receive the given message. The map
49+
* returned is safe to iterate and will never be modified.
4950
* @param message the message
50-
* @return a {@link MultiValueMap} from sessionId to subscriptionId's, possibly empty.
51+
* @return a {@code MultiValueMap} with sessionId-subscriptionId pairs,
52+
* possibly empty.
5153
*/
5254
MultiValueMap<String, String> findSubscriptions(Message<?> message);
5355

spring-messaging/src/test/java/org/springframework/messaging/simp/broker/DefaultSubscriptionRegistryTests.java

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2014 the original author or authors.
2+
* Copyright 2002-2015 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -18,6 +18,7 @@
1818

1919
import java.util.Arrays;
2020
import java.util.Collections;
21+
import java.util.Iterator;
2122
import java.util.List;
2223

2324
import org.junit.Before;
@@ -31,6 +32,7 @@
3132

3233
import static org.junit.Assert.*;
3334

35+
3436
/**
3537
* Test fixture for {@link org.springframework.messaging.simp.broker.DefaultSubscriptionRegistry}.
3638
*
@@ -326,6 +328,23 @@ public void findSubscriptionsNoMatches() {
326328
assertEquals("Expected no elements " + actual, 0, actual.size());
327329
}
328330

331+
// SPR-12665
332+
333+
@Test
334+
public void findSubscriptionsReturnsMapSafeToIterate() throws Exception {
335+
this.registry.registerSubscription(subscribeMessage("sess1", "1", "/foo"));
336+
this.registry.registerSubscription(subscribeMessage("sess2", "1", "/foo"));
337+
MultiValueMap<String, String> subscriptions = this.registry.findSubscriptions(message("/foo"));
338+
assertEquals(2, subscriptions.size());
339+
340+
Iterator iterator = subscriptions.entrySet().iterator();
341+
iterator.next();
342+
343+
this.registry.registerSubscription(subscribeMessage("sess3", "1", "/foo"));
344+
345+
iterator.next();
346+
// no ConcurrentModificationException
347+
}
329348

330349
private Message<?> subscribeMessage(String sessionId, String subscriptionId, String destination) {
331350
SimpMessageHeaderAccessor headers = SimpMessageHeaderAccessor.create(SimpMessageType.SUBSCRIBE);

0 commit comments

Comments
 (0)