Skip to content

Commit 55dae74

Browse files
committed
Add ReplyTo annotation
1 parent e0d393e commit 55dae74

File tree

7 files changed

+94
-67
lines changed

7 files changed

+94
-67
lines changed

spring-messaging/src/main/java/org/springframework/messaging/simp/MessageHolder.java renamed to spring-messaging/src/main/java/org/springframework/messaging/handler/annotation/ReplyTo.java

Lines changed: 14 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -14,34 +14,28 @@
1414
* limitations under the License.
1515
*/
1616

17-
package org.springframework.messaging.simp;
17+
package org.springframework.messaging.handler.annotation;
1818

19-
import org.springframework.core.NamedThreadLocal;
20-
import org.springframework.messaging.Message;
19+
import java.lang.annotation.Documented;
20+
import java.lang.annotation.ElementType;
21+
import java.lang.annotation.Retention;
22+
import java.lang.annotation.RetentionPolicy;
23+
import java.lang.annotation.Target;
2124

2225

23-
// TODO: remove?
24-
2526
/**
2627
* @author Rossen Stoyanchev
2728
* @since 4.0
2829
*/
29-
public class MessageHolder {
30-
31-
private static final NamedThreadLocal<Message<?>> messageHolder =
32-
new NamedThreadLocal<Message<?>>("Current message");
33-
34-
35-
public static void setMessage(Message<?> message) {
36-
messageHolder.set(message);
37-
}
30+
@Target(ElementType.METHOD)
31+
@Retention(RetentionPolicy.RUNTIME)
32+
@Documented
33+
public @interface ReplyTo {
3834

39-
public static Message<?> getMessage() {
40-
return messageHolder.get();
41-
}
4235

43-
public static void reset() {
44-
messageHolder.remove();
45-
}
36+
/**
37+
* The destination value for the reply.
38+
*/
39+
String value();
4640

4741
}
Lines changed: 3 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616

1717
package org.springframework.messaging.handler.method;
1818

19-
import org.springframework.core.MethodParameter;
2019
import org.springframework.messaging.Message;
2120
import org.springframework.messaging.MessagingException;
2221

@@ -26,29 +25,13 @@
2625
* @author Rossen Stoyanchev
2726
* @since 4.0
2827
*/
29-
public class InvalidMessageMethodParameterException extends MessagingException {
28+
public class MissingSessionUserException extends MessagingException {
3029

3130
private static final long serialVersionUID = -6905878930083523161L;
3231

33-
private final MethodParameter parameter;
3432

35-
36-
public InvalidMessageMethodParameterException(Message<?> message, String description,
37-
MethodParameter parameter, Throwable cause) {
38-
super(message, description, cause);
39-
this.parameter = parameter;
40-
}
41-
42-
public InvalidMessageMethodParameterException(Message<?> message, String description,
43-
MethodParameter parameter) {
44-
45-
super(message, description);
46-
this.parameter = parameter;
47-
}
48-
49-
50-
public MethodParameter getParameter() {
51-
return this.parameter;
33+
public MissingSessionUserException(Message<?> message) {
34+
super(message, "No \"user\" header in message");
5235
}
5336

5437
}
Lines changed: 53 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,30 +16,47 @@
1616

1717
package org.springframework.messaging.simp.annotation.support;
1818

19+
import java.security.Principal;
20+
1921
import org.springframework.core.MethodParameter;
2022
import org.springframework.messaging.Message;
2123
import org.springframework.messaging.MessageChannel;
24+
import org.springframework.messaging.handler.annotation.ReplyTo;
2225
import org.springframework.messaging.handler.method.MessageReturnValueHandler;
26+
import org.springframework.messaging.handler.method.MissingSessionUserException;
2327
import org.springframework.messaging.simp.SimpMessageHeaderAccessor;
2428
import org.springframework.messaging.support.MessageBuilder;
2529
import org.springframework.messaging.support.converter.MessageConverter;
2630
import org.springframework.util.Assert;
2731

2832

2933
/**
34+
* Expects return values to be either a {@link Message} or the payload of a message to be
35+
* converted and sent on a {@link MessageChannel}.
36+
*
37+
* <p>This {@link MessageReturnValueHandler} should be ordered last as it supports all
38+
* return value types.
39+
*
3040
* @author Rossen Stoyanchev
3141
* @since 4.0
3242
*/
33-
public class MessageSendingReturnValueHandler implements MessageReturnValueHandler {
43+
public class DefaultMessageReturnValueHandler implements MessageReturnValueHandler {
44+
45+
private MessageChannel inboundChannel;
3446

3547
private MessageChannel outboundChannel;
3648

3749
private final MessageConverter converter;
3850

3951

40-
public MessageSendingReturnValueHandler(MessageChannel outboundChannel, MessageConverter<?> converter) {
52+
public DefaultMessageReturnValueHandler(MessageChannel inboundChannel, MessageChannel outboundChannel,
53+
MessageConverter<?> converter) {
54+
55+
Assert.notNull(inboundChannel, "inboundChannel is required");
4156
Assert.notNull(outboundChannel, "outboundChannel is required");
4257
Assert.notNull(converter, "converter is required");
58+
59+
this.inboundChannel = inboundChannel;
4360
this.outboundChannel = outboundChannel;
4461
this.converter = converter;
4562
}
@@ -60,6 +77,7 @@ public void handleReturnValue(Object returnValue, MethodParameter returnType, Me
6077
}
6178

6279
SimpMessageHeaderAccessor inputHeaders = SimpMessageHeaderAccessor.wrap(message);
80+
6381
Message<?> returnMessage = (returnValue instanceof Message) ? (Message<?>) returnValue : null;
6482
Object returnPayload = (returnMessage != null) ? returnMessage.getPayload() : returnValue;
6583

@@ -68,14 +86,43 @@ public void handleReturnValue(Object returnValue, MethodParameter returnType, Me
6886

6987
returnHeaders.setSessionId(inputHeaders.getSessionId());
7088
returnHeaders.setSubscriptionId(inputHeaders.getSubscriptionId());
71-
if (returnHeaders.getDestination() == null) {
72-
returnHeaders.setDestination(inputHeaders.getDestination());
73-
}
89+
90+
String destination = getDestination(message, returnType, inputHeaders, returnHeaders);
91+
returnHeaders.setDestination(destination);
7492

7593
returnMessage = this.converter.toMessage(returnPayload);
7694
returnMessage = MessageBuilder.fromMessage(returnMessage).copyHeaders(returnHeaders.toMap()).build();
7795

78-
this.outboundChannel.send(returnMessage);
96+
if (destination.startsWith("/user/")) {
97+
this.inboundChannel.send(returnMessage);
98+
}
99+
else {
100+
this.outboundChannel.send(returnMessage);
101+
}
79102
}
80103

104+
protected String getDestination(Message<?> inputMessage, MethodParameter returnType,
105+
SimpMessageHeaderAccessor inputHeaders, SimpMessageHeaderAccessor returnHeaders) {
106+
107+
ReplyTo annot = returnType.getMethodAnnotation(ReplyTo.class);
108+
109+
if (returnHeaders.getDestination() != null) {
110+
return returnHeaders.getDestination();
111+
}
112+
else if (annot != null) {
113+
Principal user = inputHeaders.getUser();
114+
if (user == null) {
115+
throw new MissingSessionUserException(inputMessage);
116+
}
117+
return "/user/" + user.getName() + annot.value();
118+
}
119+
else if (inputHeaders.getDestination() != null) {
120+
return inputHeaders.getDestination();
121+
}
122+
else {
123+
return null;
124+
}
125+
126+
}
127+
81128
}

spring-messaging/src/main/java/org/springframework/messaging/simp/annotation/support/PrincipalMessageArgumentResolver.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@
2020

2121
import org.springframework.core.MethodParameter;
2222
import org.springframework.messaging.Message;
23-
import org.springframework.messaging.handler.method.InvalidMessageMethodParameterException;
2423
import org.springframework.messaging.handler.method.MessageArgumentResolver;
24+
import org.springframework.messaging.handler.method.MissingSessionUserException;
2525
import org.springframework.messaging.simp.SimpMessageHeaderAccessor;
2626

2727

@@ -43,7 +43,7 @@ public Object resolveArgument(MethodParameter parameter, Message<?> message) thr
4343
SimpMessageHeaderAccessor headers = SimpMessageHeaderAccessor.wrap(message);
4444
Principal user = headers.getUser();
4545
if (user == null) {
46-
throw new InvalidMessageMethodParameterException(message, "User not available", parameter);
46+
throw new MissingSessionUserException(message);
4747
}
4848
return user;
4949
}

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

Lines changed: 20 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -43,12 +43,11 @@
4343
import org.springframework.messaging.handler.method.InvocableMessageHandlerMethod;
4444
import org.springframework.messaging.handler.method.MessageArgumentResolverComposite;
4545
import org.springframework.messaging.handler.method.MessageReturnValueHandlerComposite;
46-
import org.springframework.messaging.simp.MessageHolder;
4746
import org.springframework.messaging.simp.SimpMessageHeaderAccessor;
4847
import org.springframework.messaging.simp.SimpMessageType;
4948
import org.springframework.messaging.simp.annotation.SubscribeEvent;
5049
import org.springframework.messaging.simp.annotation.UnsubscribeEvent;
51-
import org.springframework.messaging.simp.annotation.support.MessageSendingReturnValueHandler;
50+
import org.springframework.messaging.simp.annotation.support.DefaultMessageReturnValueHandler;
5251
import org.springframework.messaging.simp.annotation.support.PrincipalMessageArgumentResolver;
5352
import org.springframework.messaging.support.converter.MessageConverter;
5453
import org.springframework.stereotype.Controller;
@@ -67,6 +66,8 @@ public class AnnotationMethodMessageHandler implements MessageHandler, Applicati
6766

6867
private static final Log logger = LogFactory.getLog(AnnotationMethodMessageHandler.class);
6968

69+
private final MessageChannel inboundChannel;
70+
7071
private final MessageChannel outboundChannel;
7172

7273
private MessageConverter<?> messageConverter;
@@ -91,8 +92,10 @@ public class AnnotationMethodMessageHandler implements MessageHandler, Applicati
9192
* @param inboundChannel a channel for processing incoming messages from clients
9293
* @param outboundChannel a channel for messages going out to clients
9394
*/
94-
public AnnotationMethodMessageHandler(MessageChannel outboundChannel) {
95+
public AnnotationMethodMessageHandler(MessageChannel inboundChannel, MessageChannel outboundChannel) {
96+
Assert.notNull(inboundChannel, "inboundChannel is required");
9597
Assert.notNull(outboundChannel, "outboundChannel is required");
98+
this.inboundChannel = inboundChannel;
9699
this.outboundChannel = outboundChannel;
97100
}
98101

@@ -116,8 +119,8 @@ public void afterPropertiesSet() {
116119
this.argumentResolvers.addResolver(new PrincipalMessageArgumentResolver());
117120
this.argumentResolvers.addResolver(new MessageBodyArgumentResolver(this.messageConverter));
118121

119-
this.returnValueHandlers.addHandler(
120-
new MessageSendingReturnValueHandler(this.outboundChannel, this.messageConverter));
122+
this.returnValueHandlers.addHandler(new DefaultMessageReturnValueHandler(
123+
this.inboundChannel, this.outboundChannel, this.messageConverter));
121124
}
122125

123126
protected void initHandlerMethods() {
@@ -215,16 +218,13 @@ private void handleMessageInternal(final Message<?> message, Map<MappingInfo, Ha
215218
invocableHandlerMethod.setMessageMethodArgumentResolvers(this.argumentResolvers);
216219

217220
try {
218-
MessageHolder.setMessage(message);
219-
220-
Object value = invocableHandlerMethod.invoke(message);
221+
Object returnValue = invocableHandlerMethod.invoke(message);
221222

222223
MethodParameter returnType = handlerMethod.getReturnType();
223224
if (void.class.equals(returnType.getParameterType())) {
224225
return;
225226
}
226-
227-
this.returnValueHandlers.handleReturnValue(value, returnType, message);
227+
this.returnValueHandlers.handleReturnValue(returnValue, returnType, message);
228228
}
229229
catch (Exception ex) {
230230
invokeExceptionHandler(message, handlerMethod, ex);
@@ -233,14 +233,11 @@ private void handleMessageInternal(final Message<?> message, Map<MappingInfo, Ha
233233
// TODO
234234
ex.printStackTrace();
235235
}
236-
finally {
237-
MessageHolder.reset();
238-
}
239236
}
240237

241238
private void invokeExceptionHandler(Message<?> message, HandlerMethod handlerMethod, Exception ex) {
242239

243-
InvocableMessageHandlerMethod invocableHandlerMethod;
240+
InvocableMessageHandlerMethod exceptionHandlerMethod;
244241
Class<?> beanType = handlerMethod.getBeanType();
245242
MessageExceptionHandlerMethodResolver resolver = this.exceptionHandlerCache.get(beanType);
246243
if (resolver == null) {
@@ -254,11 +251,17 @@ private void invokeExceptionHandler(Message<?> message, HandlerMethod handlerMet
254251
return;
255252
}
256253

257-
invocableHandlerMethod = new InvocableMessageHandlerMethod(handlerMethod.getBean(), method);
258-
invocableHandlerMethod.setMessageMethodArgumentResolvers(this.argumentResolvers);
254+
exceptionHandlerMethod = new InvocableMessageHandlerMethod(handlerMethod.getBean(), method);
255+
exceptionHandlerMethod.setMessageMethodArgumentResolvers(this.argumentResolvers);
259256

260257
try {
261-
invocableHandlerMethod.invoke(message, ex);
258+
Object returnValue = exceptionHandlerMethod.invoke(message, ex);
259+
260+
MethodParameter returnType = exceptionHandlerMethod.getReturnType();
261+
if (void.class.equals(returnType.getParameterType())) {
262+
return;
263+
}
264+
this.returnValueHandlers.handleReturnValue(returnValue, returnType, message);
262265
}
263266
catch (Throwable t) {
264267
logger.error("Error while handling exception", t);
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
* @author Rossen Stoyanchev
2828
* @since 4.0
2929
*/
30-
public class InMemoryUserSessionResolver implements UserSessionResolver, UserSessionStore {
30+
public class SimpleUserSessionResolver implements UserSessionResolver, UserSessionStore {
3131

3232
// userId -> sessionId's
3333
private final Map<String, Set<String>> userSessionIds = new ConcurrentHashMap<String, Set<String>>();

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ public class UserDestinationMessageHandler implements MessageHandler {
4747

4848
private String prefix = "/user/";
4949

50-
private UserSessionResolver userSessionResolver = new InMemoryUserSessionResolver();
50+
private UserSessionResolver userSessionResolver = new SimpleUserSessionResolver();
5151

5252

5353
public UserDestinationMessageHandler(MessageSendingOperations<String> messagingTemplate) {

0 commit comments

Comments
 (0)