Polishing

This commit is contained in:
Juergen Hoeller 2014-07-09 22:25:35 +02:00
parent fa4f51c5d0
commit 0d4ff1adbf
17 changed files with 267 additions and 300 deletions

View File

@ -1,3 +1,4 @@
/**
*
* Useful generic {@code java.util.Comparator} implementations,

View File

@ -2,6 +2,7 @@
/**
*
* Useful generic {@code java.util.concurrent.Future} extension.
*
*/
package org.springframework.util.concurrent;

View File

@ -16,11 +16,7 @@
package org.springframework.jms.listener.adapter;
import static org.junit.Assert.*;
import static org.mockito.BDDMockito.*;
import java.lang.reflect.Method;
import javax.jms.Destination;
import javax.jms.JMSException;
import javax.jms.Session;
@ -32,12 +28,15 @@ import org.junit.Test;
import org.springframework.context.support.StaticApplicationContext;
import org.springframework.jms.StubTextMessage;
import org.springframework.jms.config.DefaultJmsHandlerMethodFactory;
import org.springframework.jms.support.converter.JmsHeaders;
import org.springframework.jms.support.JmsHeaders;
import org.springframework.messaging.Message;
import org.springframework.messaging.converter.MessageConversionException;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.util.ReflectionUtils;
import static org.junit.Assert.*;
import static org.mockito.BDDMockito.*;
/**
*
* @author Stephane Nicoll
@ -48,6 +47,7 @@ public class MessagingMessageListenerAdapterTests {
private final SampleBean sample = new SampleBean();
@Before
public void setup() {
initializeFactory(factory);
@ -85,12 +85,12 @@ public class MessagingMessageListenerAdapterTests {
listener.onMessage(message, session);
fail("Should have thrown an exception");
}
catch (JMSException e) {
catch (JMSException ex) {
fail("Should not have thrown a JMS exception");
}
catch (ListenerExecutionFailedException e) {
assertEquals(IllegalArgumentException.class, e.getCause().getClass());
assertEquals("Expected test exception", e.getCause().getMessage());
catch (ListenerExecutionFailedException ex) {
assertEquals(IllegalArgumentException.class, ex.getCause().getClass());
assertEquals("Expected test exception", ex.getCause().getMessage());
}
}
@ -104,11 +104,11 @@ public class MessagingMessageListenerAdapterTests {
listener.onMessage(message, session);
fail("Should have thrown an exception");
}
catch (JMSException e) {
catch (JMSException ex) {
fail("Should not have thrown a JMS exception");
}
catch (ListenerExecutionFailedException e) {
assertEquals(MessageConversionException.class, e.getCause().getClass());
catch (ListenerExecutionFailedException ex) {
assertEquals(MessageConversionException.class, ex.getCause().getClass());
}
}
@ -145,4 +145,5 @@ public class MessagingMessageListenerAdapterTests {
throw new IllegalArgumentException("Should not have been called");
}
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -27,7 +27,7 @@ package org.springframework.messaging;
public interface Message<T> {
/**
* Return message headers for the message, never {@code null}.
* Return message headers for the message (never {@code null}).
*/
MessageHeaders getHeaders();

View File

@ -36,18 +36,19 @@ import org.springframework.util.AlternativeJdkIdGenerator;
import org.springframework.util.IdGenerator;
/**
* The headers for a {@link Message}
* <p>
* <b>IMPORTANT</b>: This class is immutable. Any mutating operation such as
* The headers for a {@link Message}.
*
* <p><b>IMPORTANT</b>: This class is immutable. Any mutating operation such as
* {@code put(..)}, {@code putAll(..)} and others will throw
* {@link UnsupportedOperationException}.
* <p>Subclasses do have access to the raw headers, however, via {@link #getRawHeaders()}.
* <p>
* One way to create message headers is to use the
*
* <p>One way to create message headers is to use the
* {@link org.springframework.messaging.support.MessageBuilder MessageBuilder}:
* <pre class="code">
* MessageBuilder.withPayload("foo").setHeader("key1", "value1").setHeader("key2", "value2");
* </pre>
*
* A second option is to create {@link org.springframework.messaging.support.GenericMessage}
* passing a payload as {@link Object} and headers as a {@link Map java.util.Map}:
* <pre class="code">
@ -56,6 +57,7 @@ import org.springframework.util.IdGenerator;
* headers.put("key2", "value2");
* new GenericMessage("foo", headers);
* </pre>
*
* A third option is to use {@link org.springframework.messaging.support.MessageHeaderAccessor}
* or one of its sub-classes to create specific categories of headers.
*
@ -101,7 +103,6 @@ public class MessageHeaders implements Map<String, Object>, Serializable {
/**
* Construct a {@link MessageHeaders} with the given headers. An {@link #ID} and
* {@link #TIMESTAMP} headers will also be added, overriding any existing values.
*
* @param headers a map with headers to add
*/
public MessageHeaders(Map<String, Object> headers) {
@ -110,14 +111,12 @@ public class MessageHeaders implements Map<String, Object>, Serializable {
/**
* Constructor providing control over the ID and TIMESTAMP header values.
*
* @param headers a map with headers to add
* @param id the {@link #ID} header value
* @param timestamp the {@link #TIMESTAMP} header value
*/
protected MessageHeaders(Map<String, Object> headers, UUID id, Long timestamp) {
this.headers = (headers != null) ? new HashMap<String, Object>(headers) : new HashMap<String, Object>();
this.headers = (headers != null ? new HashMap<String, Object>(headers) : new HashMap<String, Object>());
if (id == null) {
this.headers.put(ID, getIdGenerator().generateId());
@ -146,7 +145,7 @@ public class MessageHeaders implements Map<String, Object>, Serializable {
}
protected static IdGenerator getIdGenerator() {
return ((idGenerator != null) ? idGenerator : defaultIdGenerator);
return (idGenerator != null ? idGenerator : defaultIdGenerator);
}
public UUID getId() {
@ -179,20 +178,14 @@ public class MessageHeaders implements Map<String, Object>, Serializable {
}
@Override
public int hashCode() {
return this.headers.hashCode();
public boolean equals(Object other) {
return (this == other ||
(other instanceof MessageHeaders && this.headers.equals(((MessageHeaders) other).headers)));
}
@Override
public boolean equals(Object object) {
if (this == object) {
return true;
}
if (object != null && object instanceof MessageHeaders) {
MessageHeaders other = (MessageHeaders) object;
return this.headers.equals(other.headers);
}
return false;
public int hashCode() {
return this.headers.hashCode();
}
@Override
@ -200,9 +193,8 @@ public class MessageHeaders implements Map<String, Object>, Serializable {
return this.headers.toString();
}
/*
* Map implementation
*/
// Map implementation
public boolean containsKey(Object key) {
return this.headers.containsKey(key);
@ -236,7 +228,8 @@ public class MessageHeaders implements Map<String, Object>, Serializable {
return Collections.unmodifiableCollection(this.headers.values());
}
// Unsupported operations
// Unsupported Map operations
/**
* Since MessageHeaders are immutable, the call to this method will result in {@link UnsupportedOperationException}.
@ -266,6 +259,7 @@ public class MessageHeaders implements Map<String, Object>, Serializable {
throw new UnsupportedOperationException("MessageHeaders is immutable");
}
// Serialization methods
private void writeObject(ObjectOutputStream out) throws IOException {
@ -277,7 +271,7 @@ public class MessageHeaders implements Map<String, Object>, Serializable {
}
for (String key : keysToRemove) {
if (logger.isInfoEnabled()) {
logger.info("removing non-serializable header: " + key);
logger.info("Removing non-serializable header: " + key);
}
this.headers.remove(key);
}

View File

@ -18,8 +18,10 @@ package org.springframework.messaging.converter;
import org.springframework.core.convert.ConversionException;
import org.springframework.core.convert.ConversionService;
import org.springframework.core.convert.support.DefaultConversionService;
import org.springframework.messaging.Message;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
/**
* An extension of the {@link SimpleMessageConverter} that uses a
@ -37,26 +39,39 @@ public class GenericMessageConverter extends SimpleMessageConverter {
private final ConversionService conversionService;
/**
* Create a new instance with the {@link ConversionService} to use.
* Create a new instance with a default {@link ConversionService}.
*/
public GenericMessageConverter() {
this.conversionService = new DefaultConversionService();
}
/**
* Create a new instance with the given {@link ConversionService}.
*/
public GenericMessageConverter(ConversionService conversionService) {
Assert.notNull(conversionService, "ConversionService must not be null");
this.conversionService = conversionService;
}
@Override
public Object fromMessage(Message<?> message, Class<?> targetClass) {
Object payload = message.getPayload();
if (conversionService.canConvert(payload.getClass(), targetClass)) {
if (targetClass == null) {
return payload;
}
if (payload != null && this.conversionService.canConvert(payload.getClass(), targetClass)) {
try {
return conversionService.convert(payload, targetClass);
return this.conversionService.convert(payload, targetClass);
}
catch (ConversionException e) {
throw new MessageConversionException(message, "Failed to convert message payload '"
+ payload + "' to '" + targetClass.getName() + "'", e);
catch (ConversionException ex) {
throw new MessageConversionException(message, "Failed to convert message payload '" +
payload + "' to '" + targetClass.getName() + "'", ex);
}
}
return null;
return (ClassUtils.isAssignableValue(targetClass, payload) ? payload : null);
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -38,7 +38,7 @@ public interface MessageConverter {
* conversion, it should return {@code null}.
* @param message the input message
* @param targetClass the target class for the conversion
* @return the result of the conversion or {@code null} if the converter cannot
* @return the result of the conversion, or {@code null} if the converter cannot
* perform the conversion
*/
Object fromMessage(Message<?> message, Class<?> targetClass);

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -40,7 +40,7 @@ public class SimpleMessageConverter implements MessageConverter {
if (targetClass == null) {
return payload;
}
return ClassUtils.isAssignableValue(targetClass, payload) ? payload : null;
return (ClassUtils.isAssignableValue(targetClass, payload) ? payload : null);
}
@Override

View File

@ -13,17 +13,19 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.messaging.simp;
import java.util.Map;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageHeaders;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import java.util.Map;
/**
* A wrapper class for access to attributes associated with a SiMP session
* (e.g. WebSocket session).
@ -62,24 +64,6 @@ public class SimpAttributes {
this.attributes = attributes;
}
/**
* Extract the SiMP session attributes from the given message, wrap them in
* a {@link SimpAttributes} instance.
* @param message the message to extract session attributes from
*/
public static SimpAttributes fromMessage(Message<?> message) {
Assert.notNull(message);
MessageHeaders headers = message.getHeaders();
String sessionId = SimpMessageHeaderAccessor.getSessionId(headers);
Map<String, Object> sessionAttributes = SimpMessageHeaderAccessor.getSessionAttributes(headers);
if (sessionId == null) {
throw new IllegalStateException("No session id in " + message);
}
if (sessionAttributes == null) {
throw new IllegalStateException("No session attributes in " + message);
}
return new SimpAttributes(sessionId, sessionAttributes);
}
/**
* Return the value for the attribute of the given name, if any.
@ -193,4 +177,24 @@ public class SimpAttributes {
}
}
/**
* Extract the SiMP session attributes from the given message and
* wrap them in a {@link SimpAttributes} instance.
* @param message the message to extract session attributes from
*/
public static SimpAttributes fromMessage(Message<?> message) {
Assert.notNull(message, "Message must not be null");
MessageHeaders headers = message.getHeaders();
String sessionId = SimpMessageHeaderAccessor.getSessionId(headers);
Map<String, Object> sessionAttributes = SimpMessageHeaderAccessor.getSessionAttributes(headers);
if (sessionId == null) {
throw new IllegalStateException("No session id in " + message);
}
if (sessionAttributes == null) {
throw new IllegalStateException("No session attributes in " + message);
}
return new SimpAttributes(sessionId, sessionAttributes);
}
}

View File

@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.messaging.simp;
import org.springframework.core.NamedThreadLocal;
@ -41,7 +42,6 @@ public abstract class SimpAttributesContextHolder {
/**
* Bind the given SimpAttributes to the current thread,
*
* @param attributes the RequestAttributes to expose
*/
public static void setAttributes(SimpAttributes attributes) {
@ -56,7 +56,6 @@ public abstract class SimpAttributesContextHolder {
/**
* Extract the SiMP session attributes from the given message, wrap them in
* a {@link SimpAttributes} instance and bind it to the current thread,
*
* @param message the message to extract session attributes from
*/
public static void setAttributesFromMessage(Message<?> message) {
@ -65,7 +64,6 @@ public abstract class SimpAttributesContextHolder {
/**
* Return the SimpAttributes currently bound to the thread.
*
* @return the attributes or {@code null} if not bound
*/
public static SimpAttributes getAttributes() {
@ -75,7 +73,6 @@ public abstract class SimpAttributesContextHolder {
/**
* Return the SimpAttributes currently bound to the thread or raise an
* {@link java.lang.IllegalStateException} if none are bound..
*
* @return the attributes, never {@code null}
* @throws java.lang.IllegalStateException if attributes are not bound
*/

View File

@ -20,7 +20,6 @@ import java.security.Principal;
import java.util.List;
import java.util.Map;
import org.apache.commons.logging.Log;
import org.springframework.messaging.Message;
import org.springframework.messaging.support.IdTimestampMessageHeaderInitializer;
import org.springframework.messaging.support.MessageHeaderAccessor;
@ -68,7 +67,6 @@ public class SimpMessageHeaderAccessor extends NativeMessageHeaderAccessor {
/**
* For internal use.
*
* <p>The original destination used by a client when subscribing. Such a
* destination may have been modified (e.g. user destinations) on the server
* side. This header provides a hint so messages sent to clients may have
@ -98,30 +96,6 @@ public class SimpMessageHeaderAccessor extends NativeMessageHeaderAccessor {
}
/**
* Create an instance with
* {@link org.springframework.messaging.simp.SimpMessageType} {@code MESSAGE}.
*/
public static SimpMessageHeaderAccessor create() {
return new SimpMessageHeaderAccessor(SimpMessageType.MESSAGE, null);
}
/**
* Create an instance with the given
* {@link org.springframework.messaging.simp.SimpMessageType}.
*/
public static SimpMessageHeaderAccessor create(SimpMessageType messageType) {
return new SimpMessageHeaderAccessor(messageType, null);
}
/**
* Create an instance from the payload and headers of the given Message.
*/
public static SimpMessageHeaderAccessor wrap(Message<?> message) {
return new SimpMessageHeaderAccessor(message);
}
@Override
protected MessageHeaderAccessor createAccessor(Message<?> message) {
return wrap(message);
@ -133,57 +107,27 @@ public class SimpMessageHeaderAccessor extends NativeMessageHeaderAccessor {
}
}
/**
* @return the message type
*/
public SimpMessageType getMessageType() {
return (SimpMessageType) getHeader(MESSAGE_TYPE_HEADER);
}
/**
* A static alternative for access to the message type.
*/
public static SimpMessageType getMessageType(Map<String, Object> headers) {
return (SimpMessageType) headers.get(MESSAGE_TYPE_HEADER);
}
public void setDestination(String destination) {
Assert.notNull(destination, "Destination must not be null");
setHeader(DESTINATION_HEADER, destination);
}
/**
* @return the message destination
*/
public String getDestination() {
return (String) getHeader(DESTINATION_HEADER);
}
/**
* A static alternative for access to the destination header.
*/
public static String getDestination(Map<String, Object> headers) {
return (String) headers.get(DESTINATION_HEADER);
}
public void setSubscriptionId(String subscriptionId) {
setHeader(SUBSCRIPTION_ID_HEADER, subscriptionId);
}
/**
* @return the subscription id (if any) of the message
*/
public String getSubscriptionId() {
return (String) getHeader(SUBSCRIPTION_ID_HEADER);
}
/**
* A static alternative for access to the subscription id header.
*/
public static String getSubscriptionId(Map<String, Object> headers) {
return (String) headers.get(SUBSCRIPTION_ID_HEADER);
}
public void setSessionId(String sessionId) {
setHeader(SESSION_ID_HEADER, sessionId);
}
@ -195,13 +139,6 @@ public class SimpMessageHeaderAccessor extends NativeMessageHeaderAccessor {
return (String) getHeader(SESSION_ID_HEADER);
}
/**
* A static alternative for access to the session id header.
*/
public static String getSessionId(Map<String, Object> headers) {
return (String) headers.get(SESSION_ID_HEADER);
}
/**
* A static alternative for access to the session attributes header.
*/
@ -210,39 +147,24 @@ public class SimpMessageHeaderAccessor extends NativeMessageHeaderAccessor {
}
/**
* @return attributes associated with the current session.
* Return the attributes associated with the current session.
*/
@SuppressWarnings("unchecked")
public Map<String, Object> getSessionAttributes() {
return (Map<String, Object>) getHeader(SESSION_ATTRIBUTES);
}
/**
* A static alternative for access to the session attributes header.
*/
@SuppressWarnings("unchecked")
public static Map<String, Object> getSessionAttributes(Map<String, Object> headers) {
return (Map<String, Object>) headers.get(SESSION_ATTRIBUTES);
}
public void setUser(Principal principal) {
setHeader(USER_HEADER, principal);
}
/**
* @return the user associated with the current session.
* Return the user associated with the current session.
*/
public Principal getUser() {
return (Principal) getHeader(USER_HEADER);
}
/**
* A static alternative for access to the user header.
*/
public static Principal getUser(Map<String, Object> headers) {
return (Principal) headers.get(USER_HEADER);
}
@Override
public String getShortLogMessage(Object payload) {
if (getMessageType() == null) {
@ -289,4 +211,55 @@ public class SimpMessageHeaderAccessor extends NativeMessageHeaderAccessor {
return sb;
}
// Static factory methods and accessors
/**
* Create an instance with
* {@link org.springframework.messaging.simp.SimpMessageType} {@code MESSAGE}.
*/
public static SimpMessageHeaderAccessor create() {
return new SimpMessageHeaderAccessor(SimpMessageType.MESSAGE, null);
}
/**
* Create an instance with the given
* {@link org.springframework.messaging.simp.SimpMessageType}.
*/
public static SimpMessageHeaderAccessor create(SimpMessageType messageType) {
return new SimpMessageHeaderAccessor(messageType, null);
}
/**
* Create an instance from the payload and headers of the given Message.
*/
public static SimpMessageHeaderAccessor wrap(Message<?> message) {
return new SimpMessageHeaderAccessor(message);
}
public static SimpMessageType getMessageType(Map<String, Object> headers) {
return (SimpMessageType) headers.get(MESSAGE_TYPE_HEADER);
}
public static String getDestination(Map<String, Object> headers) {
return (String) headers.get(DESTINATION_HEADER);
}
public static String getSubscriptionId(Map<String, Object> headers) {
return (String) headers.get(SUBSCRIPTION_ID_HEADER);
}
public static String getSessionId(Map<String, Object> headers) {
return (String) headers.get(SESSION_ID_HEADER);
}
@SuppressWarnings("unchecked")
public static Map<String, Object> getSessionAttributes(Map<String, Object> headers) {
return (Map<String, Object>) headers.get(SESSION_ATTRIBUTES);
}
public static Principal getUser(Map<String, Object> headers) {
return (Principal) headers.get(USER_HEADER);
}
}

View File

@ -24,15 +24,13 @@ import org.springframework.beans.factory.config.Scope;
* (e.g. WebSocket session).
*
* <p>Relies on a thread-bound {@link SimpAttributes} instance exported by
* {@link org.springframework.messaging.simp.annotation.support.SimpAnnotationMethodMessageHandler
* SimpAnnotationMethodMessageHandler}.
* {@link org.springframework.messaging.simp.annotation.support.SimpAnnotationMethodMessageHandler}.
*
* @author Rossen Stoyanchev
* @since 4.1
*/
public class SimpSessionScope implements Scope {
@Override
public Object get(String name, ObjectFactory<?> objectFactory) {
SimpAttributes simpAttributes = SimpAttributesContextHolder.currentAttributes();
@ -78,4 +76,5 @@ public class SimpSessionScope implements Scope {
public String getConversationId() {
return SimpAttributesContextHolder.currentAttributes().getSessionId();
}
}

View File

@ -131,6 +131,7 @@ public class StompHeaderAccessor extends SimpMessageHeaderAccessor {
super(SimpMessageType.HEARTBEAT, null);
}
void updateSimpMessageHeadersFromStompHeaders() {
if (getNativeHeaders() == null) {
return;
@ -171,35 +172,6 @@ public class StompHeaderAccessor extends SimpMessageHeaderAccessor {
trySetStompHeaderForSubscriptionId();
}
/**
* Create an instance for the given STOMP command.
*/
public static StompHeaderAccessor create(StompCommand command) {
return new StompHeaderAccessor(command, null);
}
/**
* Create an instance for the given STOMP command and headers.
*/
public static StompHeaderAccessor create(StompCommand command, Map<String, List<String>> headers) {
return new StompHeaderAccessor(command, headers);
}
/**
* Create headers for a heartbeat. While a STOMP heartbeat frame does not
* have headers, a session id is needed for processing purposes at a minimum.
*/
public static StompHeaderAccessor createForHeartbeat() {
return new StompHeaderAccessor();
}
/**
* Create an instance from the payload and headers of the given Message.
*/
public static StompHeaderAccessor wrap(Message<?> message) {
return new StompHeaderAccessor(message);
}
@Override
protected MessageHeaderAccessor createAccessor(Message<?> message) {
@ -213,23 +185,18 @@ public class StompHeaderAccessor extends SimpMessageHeaderAccessor {
}
public StompCommand updateStompCommandAsClientMessage() {
Assert.state(SimpMessageType.MESSAGE.equals(getMessageType()), "Unexpected message type " + getMessage());
if (getCommand() == null) {
setHeader(COMMAND_HEADER, StompCommand.SEND);
}
else if (!getCommand().equals(StompCommand.SEND)) {
throw new IllegalStateException("Unexpected STOMP command " + getCommand());
}
return getCommand();
}
public void updateStompCommandAsServerMessage() {
Assert.state(SimpMessageType.MESSAGE.equals(getMessageType()), "Unexpected message type " + getMessage());
StompCommand command = getCommand();
if ((command == null) || StompCommand.SEND.equals(command)) {
setHeader(COMMAND_HEADER, StompCommand.MESSAGE);
@ -237,9 +204,7 @@ public class StompHeaderAccessor extends SimpMessageHeaderAccessor {
else if (!StompCommand.MESSAGE.equals(command)) {
throw new IllegalStateException("Unexpected STOMP command " + command);
}
trySetStompHeaderForSubscriptionId();
if (getMessageId() == null) {
String messageId = getSessionId() + "-" + messageIdCounter.getAndIncrement();
setNativeHeader(STOMP_MESSAGE_ID_HEADER, messageId);
@ -247,22 +212,15 @@ public class StompHeaderAccessor extends SimpMessageHeaderAccessor {
}
/**
* @return the STOMP command, or {@code null} if not yet set.
* Return the STOMP command, or {@code null} if not yet set.
*/
public StompCommand getCommand() {
return (StompCommand) getHeader(COMMAND_HEADER);
}
/**
* A static alternative for access to the STOMP command.
*/
public static StompCommand getCommand(Map<String, Object> headers) {
return (StompCommand) headers.get(COMMAND_HEADER);
}
public Set<String> getAcceptVersion() {
String rawValue = getFirstNativeHeader(STOMP_ACCEPT_VERSION_HEADER);
return (rawValue != null) ? StringUtils.commaDelimitedListToSet(rawValue) : Collections.<String>emptySet();
return (rawValue != null ? StringUtils.commaDelimitedListToSet(rawValue) : Collections.<String>emptySet());
}
public boolean isHeartbeat() {
@ -329,15 +287,6 @@ public class StompHeaderAccessor extends SimpMessageHeaderAccessor {
return null;
}
public static Integer getContentLength(Map<String, List<String>> nativeHeaders) {
if (nativeHeaders.containsKey(STOMP_CONTENT_LENGTH_HEADER)) {
List<String> values = nativeHeaders.get(STOMP_CONTENT_LENGTH_HEADER);
String value = (values != null ? values.get(0) : null);
return Integer.valueOf(value);
}
return null;
}
public void setContentLength(int contentLength) {
setNativeHeader(STOMP_CONTENT_LENGTH_HEADER, String.valueOf(contentLength));
}
@ -370,7 +319,6 @@ public class StompHeaderAccessor extends SimpMessageHeaderAccessor {
return getFirstNativeHeader(STOMP_LOGIN_HEADER);
}
public void setPasscode(String passcode) {
setNativeHeader(STOMP_PASSCODE_HEADER, passcode);
protectPasscode();
@ -385,21 +333,13 @@ public class StompHeaderAccessor extends SimpMessageHeaderAccessor {
}
/**
* @return the passcode header value or {@code null}.
* Return the passcode header value, or {@code null} if not set.
*/
public String getPasscode() {
StompPasscode credentials = (StompPasscode) getHeader(CREDENTIALS_HEADER);
return (credentials != null ? credentials.passcode : null);
}
/**
* A static alternative for access to the passcode header.
*/
public static String getPasscode(Map<String, Object> headers) {
StompPasscode credentials = (StompPasscode) headers.get(CREDENTIALS_HEADER);
return (credentials != null ? credentials.passcode : null);
}
public void setReceiptId(String receiptId) {
setNativeHeader(STOMP_RECEIPT_ID_HEADER, receiptId);
}
@ -440,6 +380,7 @@ public class StompHeaderAccessor extends SimpMessageHeaderAccessor {
setNativeHeader(STOMP_VERSION_HEADER, version);
}
// Logging related
@Override
@ -506,6 +447,62 @@ public class StompHeaderAccessor extends SimpMessageHeaderAccessor {
}
// Static factory methods and accessors
/**
* Create an instance for the given STOMP command.
*/
public static StompHeaderAccessor create(StompCommand command) {
return new StompHeaderAccessor(command, null);
}
/**
* Create an instance for the given STOMP command and headers.
*/
public static StompHeaderAccessor create(StompCommand command, Map<String, List<String>> headers) {
return new StompHeaderAccessor(command, headers);
}
/**
* Create headers for a heartbeat. While a STOMP heartbeat frame does not
* have headers, a session id is needed for processing purposes at a minimum.
*/
public static StompHeaderAccessor createForHeartbeat() {
return new StompHeaderAccessor();
}
/**
* Create an instance from the payload and headers of the given Message.
*/
public static StompHeaderAccessor wrap(Message<?> message) {
return new StompHeaderAccessor(message);
}
/**
* Return the STOMP command from the given headers, or {@code null} if not set.
*/
public static StompCommand getCommand(Map<String, Object> headers) {
return (StompCommand) headers.get(COMMAND_HEADER);
}
/**
* Return the passcode header value, or {@code null} if not set.
*/
public static String getPasscode(Map<String, Object> headers) {
StompPasscode credentials = (StompPasscode) headers.get(CREDENTIALS_HEADER);
return (credentials != null ? credentials.passcode : null);
}
public static Integer getContentLength(Map<String, List<String>> nativeHeaders) {
if (nativeHeaders.containsKey(STOMP_CONTENT_LENGTH_HEADER)) {
List<String> values = nativeHeaders.get(STOMP_CONTENT_LENGTH_HEADER);
String value = (values != null ? values.get(0) : null);
return Integer.valueOf(value);
}
return null;
}
private static class StompPasscode {
private final String passcode;

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -16,11 +16,11 @@
package org.springframework.messaging.support;
import java.util.UUID;
import org.springframework.messaging.MessageHeaders;
import org.springframework.util.IdGenerator;
import java.util.UUID;
/**
* A {@link org.springframework.messaging.support.MessageHeaderInitializer MessageHeaderInitializer}
* to customize the strategy for ID and TIMESTAMP message header generation.
@ -38,10 +38,8 @@ public class IdTimestampMessageHeaderInitializer implements MessageHeaderInitial
/**
* Configure the IdGenerator strategy to initialize {@code MessageHeaderAccessor}
* instances with.
*
* <p>By default this property is set to {@code null} in which case the default
* IdGenerator of {@link org.springframework.messaging.MessageHeaders} is used.
*
* <p>To have no id's generated at all, see {@@link #setDisableIdGeneration()}.
*/
public void setIdGenerator(IdGenerator idGenerator) {
@ -49,17 +47,15 @@ public class IdTimestampMessageHeaderInitializer implements MessageHeaderInitial
}
/**
* A shortcut for calling
* {@link #setIdGenerator(org.springframework.util.IdGenerator)} with an
* id generation strategy to
*
* A shortcut for calling {@link #setIdGenerator(org.springframework.util.IdGenerator)}
* with an id generation strategy to disable id generation completely.
*/
public void setDisableIdGeneration() {
this.idGenerator = ID_VALUE_NONE_GENERATOR;
}
/**
* @return the configured {@code IdGenerator} if any.
* Return the configured {@code IdGenerator}, if any.
*/
public IdGenerator getIdGenerator() {
return this.idGenerator;
@ -69,7 +65,6 @@ public class IdTimestampMessageHeaderInitializer implements MessageHeaderInitial
* Whether to enable the automatic addition of the
* {@link org.springframework.messaging.MessageHeaders#TIMESTAMP} header on
* {@code MessageHeaderAccessor} instances being initialized.
*
* <p>By default this property is set to false.
*/
public void setEnableTimestamp(boolean enableTimestamp) {
@ -77,12 +72,13 @@ public class IdTimestampMessageHeaderInitializer implements MessageHeaderInitial
}
/**
* @return Whether the timestamp header is enabled or not.
* Return whether the timestamp header is enabled or not.
*/
public boolean isEnableTimestamp() {
return this.enableTimestamp;
}
@Override
public void initHeaders(MessageHeaderAccessor headerAccessor) {
headerAccessor.setIdGenerator(getIdGenerator());

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -24,14 +24,13 @@ import org.springframework.messaging.MessageHeaders;
import org.springframework.util.Assert;
/**
* A builder for creating a {@link GenericMessage} (or {@link ErrorMessage} if
* the payload is of type {@link Throwable}).
* A builder for creating a {@link GenericMessage}
* (or {@link ErrorMessage} if the payload is of type {@link Throwable}).
*
* @author Arjen Poutsma
* @author Mark Fisher
* @author Rossen Stoyanchev
* @since 4.0
*
* @see GenericMessage
* @see ErrorMessage
*/
@ -59,52 +58,9 @@ public final class MessageBuilder<T> {
this.originalMessage = null;
}
/**
* Create a builder for a new {@link Message} instance pre-populated with all of the
* headers copied from the provided message. The payload of the provided Message will
* also be used as the payload for the new message.
*
* @param message the Message from which the payload and all headers will be copied
*/
public static <T> MessageBuilder<T> fromMessage(Message<T> message) {
return new MessageBuilder<T>(message);
}
/**
* Create a new builder for a message with the given payload.
* @param payload the payload
*/
public static <T> MessageBuilder<T> withPayload(T payload) {
return new MessageBuilder<T>(payload, new MessageHeaderAccessor());
}
/**
* A shortcut factory method for creating a message with the given payload
* and {@code MessageHeaders}.
*
* <p><strong>Note:</strong> the given {@code MessageHeaders} instance is used
* directly in the new message, i.e. it is not copied.
*
* @param payload the payload to use, never {@code null}
* @param messageHeaders the headers to use, never {@code null}
* @return the created message
* @since 4.1
*/
@SuppressWarnings("unchecked")
public static <T> Message<T> createMessage(T payload, MessageHeaders messageHeaders) {
Assert.notNull(payload, "'payload' must not be null");
Assert.notNull(messageHeaders, "'messageHeaders' must not be null");
if (payload instanceof Throwable) {
return (Message<T>) new ErrorMessage((Throwable) payload, messageHeaders);
}
else {
return new GenericMessage<T>(payload, messageHeaders);
}
}
/**
* Set the message headers to use by providing a {@code MessageHeaderAccessor}.
*
* @param accessor the headers to use
*/
public MessageBuilder<T> setHeaders(MessageHeaderAccessor accessor) {
@ -189,11 +145,9 @@ public final class MessageBuilder<T> {
@SuppressWarnings("unchecked")
public Message<T> build() {
if (this.originalMessage != null && !this.headerAccessor.isModified()) {
return this.originalMessage;
}
if (this.payload instanceof Throwable) {
return (Message<T>) new ErrorMessage((Throwable) this.payload, this.headerAccessor.toMap());
}
@ -202,4 +156,45 @@ public final class MessageBuilder<T> {
}
}
/**
* Create a builder for a new {@link Message} instance pre-populated with all of the
* headers copied from the provided message. The payload of the provided Message will
* also be used as the payload for the new message.
* @param message the Message from which the payload and all headers will be copied
*/
public static <T> MessageBuilder<T> fromMessage(Message<T> message) {
return new MessageBuilder<T>(message);
}
/**
* Create a new builder for a message with the given payload.
* @param payload the payload
*/
public static <T> MessageBuilder<T> withPayload(T payload) {
return new MessageBuilder<T>(payload, new MessageHeaderAccessor());
}
/**
* A shortcut factory method for creating a message with the given payload
* and {@code MessageHeaders}.
* <p><strong>Note:</strong> the given {@code MessageHeaders} instance is used
* directly in the new message, i.e. it is not copied.
* @param payload the payload to use, never {@code null}
* @param messageHeaders the headers to use, never {@code null}
* @return the created message
* @since 4.1
*/
@SuppressWarnings("unchecked")
public static <T> Message<T> createMessage(T payload, MessageHeaders messageHeaders) {
Assert.notNull(payload, "'payload' must not be null");
Assert.notNull(messageHeaders, "'messageHeaders' must not be null");
if (payload instanceof Throwable) {
return (Message<T>) new ErrorMessage((Throwable) payload, messageHeaders);
}
else {
return new GenericMessage<T>(payload, messageHeaders);
}
}
}

View File

@ -17,8 +17,7 @@
package org.springframework.messaging.support;
/**
* Callback interface for initializing a
* {@link org.springframework.messaging.support.MessageHeaderAccessor MessageHeaderAccessor}.
* Callback interface for initializing a {@link MessageHeaderAccessor}.
*
* @author Rossen Stoyanchev
* @since 4.1
@ -27,8 +26,7 @@ public interface MessageHeaderInitializer {
/**
* Initialize the given {@code MessageHeaderAccessor}.
*
* @param headerAccessor the instance to initialize
* @param headerAccessor the MessageHeaderAccessor to initialize
*/
void initHeaders(MessageHeaderAccessor headerAccessor);

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -16,28 +16,26 @@
package org.springframework.messaging.core;
import java.io.Writer;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.springframework.core.convert.ConversionFailedException;
import org.springframework.core.convert.support.DefaultConversionService;
import org.springframework.messaging.Message;
import org.springframework.messaging.converter.GenericMessageConverter;
import org.springframework.messaging.converter.MessageConversionException;
import org.springframework.messaging.support.GenericMessage;
import static org.hamcrest.CoreMatchers.isA;
import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;
import java.io.Writer;
/**
* Unit tests for receiving operations in {@link AbstractMessagingTemplate}.
*
* @author Rossen Stoyanchev
*
* @see MessageRequestReplyTemplateTests
*/
public class MessageReceivingTemplateTests {
@ -104,7 +102,7 @@ public class MessageReceivingTemplateTests {
public void receiveAndConvertFailed() {
Message<?> expected = new GenericMessage<Object>("not a number test");
this.template.setReceiveMessage(expected);
this.template.setMessageConverter(new GenericMessageConverter(new DefaultConversionService()));
this.template.setMessageConverter(new GenericMessageConverter());
thrown.expect(MessageConversionException.class);
thrown.expectCause(isA(ConversionFailedException.class));
@ -116,13 +114,13 @@ public class MessageReceivingTemplateTests {
Message<?> expected = new GenericMessage<Object>("payload");
this.template.setDefaultDestination("home");
this.template.setReceiveMessage(expected);
this.template.setMessageConverter(new GenericMessageConverter(new DefaultConversionService()));
this.template.setMessageConverter(new GenericMessageConverter());
try {
this.template.receiveAndConvert(Writer.class);
}
catch (MessageConversionException e) {
assertTrue("Invalid exception message '"+e.getMessage()+"'", e.getMessage().contains("payload"));
assertSame(expected, e.getFailedMessage());
catch (MessageConversionException ex) {
assertTrue("Invalid exception message '" + ex.getMessage() + "'", ex.getMessage().contains("payload"));
assertSame(expected, ex.getFailedMessage());
}
}
@ -134,7 +132,6 @@ public class MessageReceivingTemplateTests {
private Message<?> receiveMessage;
private void setReceiveMessage(Message<?> receiveMessage) {
this.receiveMessage = receiveMessage;
}
@ -154,7 +151,6 @@ public class MessageReceivingTemplateTests {
this.destination = destination;
return null;
}
}
}