Skip to content

Commit 90c4712

Browse files
committed
Revise UserSessionResolver to UserQueueSuffixResolver
The resolver for /user/{username} prefixed destinations is now more explicitly designed to store queue suffixes rather than session id's, which is what we happen to use as queue suffixes. This allows something other than the sessionId to be used without having to change many places. It also enables applications to construct destinations with user-specific queue suffixes without making assumptions about what's used for queue suffixes. For example a controller may construct a map with subscription destinations and send that down to the client.
1 parent f86a328 commit 90c4712

File tree

7 files changed

+166
-138
lines changed

7 files changed

+166
-138
lines changed
Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,10 @@
2121
* @author Rossen Stoyanchev
2222
* @since 4.0
2323
*/
24-
public interface MutableUserSessionResolver extends UserSessionResolver {
24+
public interface MutableUserQueueSuffixResolver extends UserQueueSuffixResolver {
2525

26-
void addUserSessionId(String user, String sessionId);
26+
void addQueueSuffix(String user, String sessionId, String suffix);
2727

28-
void removeUserSessionId(String user, String sessionId);
28+
void removeQueueSuffix(String user, String sessionId);
2929

3030
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
/*
2+
* Copyright 2002-2013 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.messaging.simp.handler;
18+
19+
import java.util.Collections;
20+
import java.util.HashSet;
21+
import java.util.Map;
22+
import java.util.Set;
23+
import java.util.concurrent.ConcurrentHashMap;
24+
import java.util.concurrent.ConcurrentMap;
25+
26+
27+
/**
28+
* @author Rossen Stoyanchev
29+
* @since 4.0
30+
*/
31+
public class SimpleUserQueueSuffixResolver implements MutableUserQueueSuffixResolver {
32+
33+
// userId -> [sessionId -> queueSuffix]
34+
private final ConcurrentMap<String, Map<String, String>> cache = new ConcurrentHashMap<String, Map<String, String>>();
35+
36+
37+
@Override
38+
public void addQueueSuffix(String user, String sessionId, String suffix) {
39+
Map<String, String> suffixes = this.cache.get(user);
40+
if (suffixes == null) {
41+
suffixes = new ConcurrentHashMap<String, String>();
42+
Map<String, String> prevSuffixes = this.cache.putIfAbsent(user, suffixes);
43+
if (prevSuffixes != null) {
44+
suffixes = prevSuffixes;
45+
}
46+
}
47+
suffixes.put(sessionId, suffix);
48+
}
49+
50+
@Override
51+
public void removeQueueSuffix(String user, String sessionId) {
52+
Map<String, String> suffixes = this.cache.get(user);
53+
if (suffixes != null) {
54+
if (suffixes.remove(sessionId) != null) {
55+
this.cache.remove(user, Collections.emptyMap());
56+
}
57+
}
58+
}
59+
60+
@Override
61+
public Set<String> getUserQueueSuffixes(String user) {
62+
Map<String, String> suffixes = this.cache.get(user);
63+
return (suffixes != null) ? new HashSet<String>(suffixes.values()) : Collections.<String>emptySet();
64+
}
65+
66+
@Override
67+
public String getUserQueueSuffix(String user, String sessionId) {
68+
Map<String, String> suffixes = this.cache.get(user);
69+
if (suffixes != null) {
70+
return suffixes.get(sessionId);
71+
}
72+
return null;
73+
}
74+
75+
}

spring-messaging/src/main/java/org/springframework/messaging/simp/handler/SimpleUserSessionResolver.java

Lines changed: 0 additions & 65 deletions
This file was deleted.

spring-messaging/src/main/java/org/springframework/messaging/simp/handler/UserDestinationMessageHandler.java

Lines changed: 24 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,14 @@
3030

3131

3232
/**
33+
* Supports destinations prefixed with "/user/{username}", transforms the
34+
* destination to a unique queue to which the user is subscribed, and then sends
35+
* the message for further processing.
3336
*
34-
* Supports destinations prefixed with "/user/{username}" and resolves them into a
35-
* destination to which the user is currently subscribed by appending the user session id.
36-
* For example a destination such as "/user/john/queue/trade-confirmation" would resolve
37-
* to "/queue/trade-confirmation/i9oqdfzo" if "i9oqdfzo" is the user's session id.
37+
* <p>The target destination has the prefix removed and a unique queue suffix,
38+
* resolved via {@link #setUserQueueSuffixResolver(UserQueueSuffixResolver)}, appended.
39+
* For example a destination such as "/user/john/queue/trade-confirmation" could
40+
* be transformed to "/queue/trade-confirmation/i9oqdfzo".
3841
*
3942
* @author Rossen Stoyanchev
4043
* @since 4.0
@@ -47,11 +50,22 @@ public class UserDestinationMessageHandler implements MessageHandler {
4750

4851
private String prefix = "/user/";
4952

50-
private UserSessionResolver userSessionResolver = new SimpleUserSessionResolver();
53+
private UserQueueSuffixResolver userQueueSuffixResolver = new SimpleUserQueueSuffixResolver();
5154

5255

53-
public UserDestinationMessageHandler(MessageSendingOperations<String> messagingTemplate) {
56+
/**
57+
*
58+
* @param messagingTemplate
59+
* @param resolver the resolver to use to find queue suffixes for a user
60+
*/
61+
public UserDestinationMessageHandler(MessageSendingOperations<String> messagingTemplate,
62+
UserQueueSuffixResolver userQueueSuffixResolver) {
63+
64+
Assert.notNull(messagingTemplate, "messagingTemplate is required");
65+
Assert.notNull(userQueueSuffixResolver, "userQueueSuffixResolver is required");
66+
5467
this.messagingTemplate = messagingTemplate;
68+
this.userQueueSuffixResolver = userQueueSuffixResolver;
5569
}
5670

5771
/**
@@ -71,17 +85,10 @@ public String getPrefix() {
7185
}
7286

7387
/**
74-
* @param userSessionResolver the userSessionResolver to set
75-
*/
76-
public void setUserSessionResolver(UserSessionResolver userSessionResolver) {
77-
this.userSessionResolver = userSessionResolver;
78-
}
79-
80-
/**
81-
* @return the userSessionResolver
88+
* @return the resolver for queue suffixes for a user
8289
*/
83-
public UserSessionResolver getUserSessionResolver() {
84-
return this.userSessionResolver;
90+
public UserQueueSuffixResolver getUserQueueSuffixResolver() {
91+
return this.userQueueSuffixResolver;
8592
}
8693

8794
/**
@@ -116,7 +123,7 @@ public void handleMessage(Message<?> message) throws MessagingException {
116123
return;
117124
}
118125

119-
for (String sessionId : this.userSessionResolver.resolveUserSessionIds(user)) {
126+
for (String sessionId : this.userQueueSuffixResolver.getUserQueueSuffixes(user)) {
120127

121128
String targetDestination = destinationParser.getTargetDestination(sessionId);
122129
headers.setDestination(targetDestination);

spring-messaging/src/main/java/org/springframework/messaging/simp/handler/UserSessionResolver.java renamed to spring-messaging/src/main/java/org/springframework/messaging/simp/handler/UserQueueSuffixResolver.java

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,19 +20,29 @@
2020

2121

2222
/**
23-
* A strategy for resolving a user name to one or more session id's.
23+
* A strategy for resolving unique queue suffixes for a connected user.
24+
* There can be only one suffix per user per session.
2425
*
2526
* @author Rossen Stoyanchev
2627
* @since 4.0
2728
*/
28-
public interface UserSessionResolver {
29+
public interface UserQueueSuffixResolver {
2930

3031
/**
31-
* Retrieve the sessionId(s) associated with the given user.
32+
* Retrieve the suffixes for all sessions associated with this user.
3233
*
3334
* @param user the user name
34-
* @return a Set with zero, one, or more, current session id's.
35+
* @return a Set with zero, one, or more, queue suffixes
3536
*/
36-
Set<String> resolveUserSessionIds(String user);
37+
Set<String> getUserQueueSuffixes(String user);
38+
39+
/**
40+
* Retrieve the queue suffix associated with the given user session.
41+
*
42+
* @param user the user name
43+
* @param sessionId the session id
44+
* @return a queue suffix or {@code null}
45+
*/
46+
String getUserQueueSuffix(String user, String sessionId);
3747

3848
}

0 commit comments

Comments
 (0)