Browse Source
A new type MessageHeaderAccesssor provides read/write access to MessageHeaders along with typed getter/setter methods along the lines of the existing MessageBuilder methods (internally MessageBuilder merely delegates to MessageHeaderAccessor). This class is extensible with sub-classes expected to provide typed getter/setter methods for specific categories of message headers. NativeMessageHeaderAccessor is one specific sub-class that further provides read/write access to headers from some external message source (e.g. STOMP headers). Native headers are stored in a separate MultiValueMap and kept under a specific key.pull/286/merge
19 changed files with 653 additions and 643 deletions
@ -0,0 +1,219 @@
@@ -0,0 +1,219 @@
|
||||
/* |
||||
* Copyright 2002-2013 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. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package org.springframework.messaging.support; |
||||
|
||||
import java.util.ArrayList; |
||||
import java.util.HashMap; |
||||
import java.util.List; |
||||
import java.util.Map; |
||||
import java.util.Set; |
||||
|
||||
import org.apache.commons.logging.Log; |
||||
import org.apache.commons.logging.LogFactory; |
||||
import org.springframework.messaging.Message; |
||||
import org.springframework.messaging.MessageChannel; |
||||
import org.springframework.messaging.MessageHeaders; |
||||
import org.springframework.util.Assert; |
||||
import org.springframework.util.ObjectUtils; |
||||
import org.springframework.util.PatternMatchUtils; |
||||
import org.springframework.util.StringUtils; |
||||
|
||||
|
||||
/** |
||||
* A base class for read/write access to {@link MessageHeaders}. Supports creation of new |
||||
* headers or modification of existing message headers. |
||||
* <p> |
||||
* Sub-classes can provide additinoal typed getters and setters for convenient access to |
||||
* specific headers. Getters and setters should delegate to {@link #getHeader(String)} or |
||||
* {@link #setHeader(String, Object)} respectively. At the end {@link #toMap()} can be |
||||
* used to obtain the resulting headers. |
||||
* |
||||
* @author Rossen Stoyanchev |
||||
* @since 4.0 |
||||
*/ |
||||
public class MessageHeaderAccesssor { |
||||
|
||||
protected Log logger = LogFactory.getLog(getClass()); |
||||
|
||||
|
||||
// wrapped read-only message headers
|
||||
private final MessageHeaders originalHeaders; |
||||
|
||||
// header updates
|
||||
private final Map<String, Object> headers = new HashMap<String, Object>(4); |
||||
|
||||
|
||||
/** |
||||
* A constructor for creating new message headers. |
||||
*/ |
||||
public MessageHeaderAccesssor() { |
||||
this.originalHeaders = null; |
||||
} |
||||
|
||||
/** |
||||
* A constructor for accessing and modifying existing message headers. |
||||
*/ |
||||
public MessageHeaderAccesssor(Message<?> message) { |
||||
this.originalHeaders = (message != null) ? message.getHeaders() : null; |
||||
} |
||||
|
||||
|
||||
/** |
||||
* Return a header map including original, wrapped headers (if any) plus additional |
||||
* header updates made through accessor methods. |
||||
*/ |
||||
public Map<String, Object> toMap() { |
||||
Map<String, Object> result = new HashMap<String, Object>(); |
||||
if (this.originalHeaders != null) { |
||||
result.putAll(this.originalHeaders); |
||||
} |
||||
for (String key : this.headers.keySet()) { |
||||
Object value = this.headers.get(key); |
||||
if (value == null) { |
||||
result.remove(key); |
||||
} |
||||
else { |
||||
result.put(key, value); |
||||
} |
||||
} |
||||
return result; |
||||
} |
||||
|
||||
public boolean isModified() { |
||||
return (!this.headers.isEmpty()); |
||||
} |
||||
|
||||
public Object getHeader(String headerName) { |
||||
if (this.headers.containsKey(headerName)) { |
||||
return this.headers.get(headerName); |
||||
} |
||||
else if (this.originalHeaders != null) { |
||||
return this.originalHeaders.get(headerName); |
||||
} |
||||
return null; |
||||
} |
||||
|
||||
/** |
||||
* Set the value for the given header name. If the provided value is {@code null} the |
||||
* header will be removed. |
||||
*/ |
||||
public void setHeader(String name, Object value) { |
||||
Assert.isTrue(!isReadOnly(name), "The '" + name + "' header is read-only."); |
||||
if (!ObjectUtils.nullSafeEquals(value, getHeader(name))) { |
||||
this.headers.put(name, value); |
||||
} |
||||
} |
||||
|
||||
protected boolean isReadOnly(String headerName) { |
||||
return MessageHeaders.ID.equals(headerName) || MessageHeaders.TIMESTAMP.equals(headerName); |
||||
} |
||||
|
||||
/** |
||||
* Set the value for the given header name only if the header name is not already associated with a value. |
||||
*/ |
||||
public void setHeaderIfAbsent(String name, Object value) { |
||||
if (getHeader(name) == null) { |
||||
setHeader(name, value); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Removes all headers provided via array of 'headerPatterns'. As the name suggests |
||||
* the array may contain simple matching patterns for header names. Supported pattern |
||||
* styles are: "xxx*", "*xxx", "*xxx*" and "xxx*yyy". |
||||
*/ |
||||
public void removeHeaders(String... headerPatterns) { |
||||
List<String> headersToRemove = new ArrayList<String>(); |
||||
for (String pattern : headerPatterns) { |
||||
if (StringUtils.hasLength(pattern)){ |
||||
if (pattern.contains("*")){ |
||||
for (String headerName : this.headers.keySet()) { |
||||
if (PatternMatchUtils.simpleMatch(pattern, headerName)){ |
||||
headersToRemove.add(headerName); |
||||
} |
||||
} |
||||
} |
||||
else { |
||||
headersToRemove.add(pattern); |
||||
} |
||||
} |
||||
} |
||||
for (String headerToRemove : headersToRemove) { |
||||
removeHeader(headerToRemove); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Remove the value for the given header name. |
||||
*/ |
||||
public void removeHeader(String headerName) { |
||||
if (StringUtils.hasLength(headerName) && !isReadOnly(headerName)) { |
||||
setHeader(headerName, null); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Copy the name-value pairs from the provided Map. This operation will overwrite any |
||||
* existing values. Use { {@link #copyHeadersIfAbsent(Map)} to avoid overwriting |
||||
* values. |
||||
*/ |
||||
public void copyHeaders(Map<String, ?> headersToCopy) { |
||||
Set<String> keys = headersToCopy.keySet(); |
||||
for (String key : keys) { |
||||
if (!isReadOnly(key)) { |
||||
setHeader(key, headersToCopy.get(key)); |
||||
} |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Copy the name-value pairs from the provided Map. This operation will <em>not</em> |
||||
* overwrite any existing values. |
||||
*/ |
||||
public void copyHeadersIfAbsent(Map<String, ?> headersToCopy) { |
||||
Set<String> keys = headersToCopy.keySet(); |
||||
for (String key : keys) { |
||||
if (!this.isReadOnly(key)) { |
||||
setHeaderIfAbsent(key, headersToCopy.get(key)); |
||||
} |
||||
} |
||||
} |
||||
|
||||
public void setReplyChannel(MessageChannel replyChannel) { |
||||
setHeader(MessageHeaders.REPLY_CHANNEL, replyChannel); |
||||
} |
||||
|
||||
public void setReplyChannelName(String replyChannelName) { |
||||
setHeader(MessageHeaders.REPLY_CHANNEL, replyChannelName); |
||||
} |
||||
|
||||
public void setErrorChannel(MessageChannel errorChannel) { |
||||
setHeader(MessageHeaders.ERROR_CHANNEL, errorChannel); |
||||
} |
||||
|
||||
public void setErrorChannelName(String errorChannelName) { |
||||
setHeader(MessageHeaders.ERROR_CHANNEL, errorChannelName); |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public String toString() { |
||||
return getClass().getSimpleName() + " [originalHeaders=" + this.originalHeaders |
||||
+ ", updated headers=" + this.headers + "]"; |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,140 @@
@@ -0,0 +1,140 @@
|
||||
/* |
||||
* Copyright 2002-2013 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. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package org.springframework.messaging.support; |
||||
|
||||
import java.util.HashMap; |
||||
import java.util.List; |
||||
import java.util.Map; |
||||
|
||||
import org.springframework.messaging.Message; |
||||
import org.springframework.util.CollectionUtils; |
||||
import org.springframework.util.LinkedMultiValueMap; |
||||
import org.springframework.util.MultiValueMap; |
||||
import org.springframework.util.ObjectUtils; |
||||
|
||||
|
||||
/** |
||||
* An extension of {@link MessageHeaderAccesssor} that also provides read/write access to |
||||
* message headers from an external message source. Native message headers are kept |
||||
* in a {@link MultiValueMap} under the key {@link #NATIVE_HEADERS}. |
||||
* |
||||
* @author Rossen Stoyanchev |
||||
* @since 4.0 |
||||
*/ |
||||
public class NativeMessageHeaderAccessor extends MessageHeaderAccesssor { |
||||
|
||||
|
||||
public static final String NATIVE_HEADERS = "nativeHeaders"; |
||||
|
||||
// wrapped native headers
|
||||
private final Map<String, List<String>> originalNativeHeaders; |
||||
|
||||
// native header updates
|
||||
private final MultiValueMap<String, String> nativeHeaders = new LinkedMultiValueMap<String, String>(4); |
||||
|
||||
|
||||
/** |
||||
* A constructor for creating new headers, accepting an optional native header map. |
||||
*/ |
||||
public NativeMessageHeaderAccessor(Map<String, List<String>> nativeHeaders) { |
||||
super(); |
||||
this.originalNativeHeaders = nativeHeaders; |
||||
} |
||||
|
||||
/** |
||||
* A constructor for accessing and modifying existing message headers. |
||||
*/ |
||||
public NativeMessageHeaderAccessor(Message<?> message) { |
||||
super(message); |
||||
this.originalNativeHeaders = initNativeHeaders(message); |
||||
} |
||||
|
||||
private static Map<String, List<String>> initNativeHeaders(Message<?> message) { |
||||
if (message != null) { |
||||
@SuppressWarnings("unchecked") |
||||
Map<String, List<String>> headers = (Map<String, List<String>>) message.getHeaders().get(NATIVE_HEADERS); |
||||
if (headers != null) { |
||||
return headers; |
||||
} |
||||
} |
||||
return null; |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public Map<String, Object> toMap() { |
||||
Map<String, Object> result = super.toMap(); |
||||
result.put(NATIVE_HEADERS, toNativeHeaderMap()); |
||||
return result; |
||||
} |
||||
|
||||
@Override |
||||
public boolean isModified() { |
||||
return (super.isModified() || (!this.nativeHeaders.isEmpty())); |
||||
} |
||||
|
||||
/** |
||||
* Return a map with native headers including original, wrapped headers (if any) plus |
||||
* additional header updates made through accessor methods. |
||||
*/ |
||||
public Map<String, List<String>> toNativeHeaderMap() { |
||||
Map<String, List<String>> result = new HashMap<String, List<String>>(); |
||||
if (this.originalNativeHeaders != null) { |
||||
result.putAll(this.originalNativeHeaders); |
||||
} |
||||
for (String key : this.nativeHeaders.keySet()) { |
||||
List<String> value = this.nativeHeaders.get(key); |
||||
if (value == null) { |
||||
result.remove(key); |
||||
} |
||||
else { |
||||
result.put(key, value); |
||||
} |
||||
} |
||||
return result; |
||||
} |
||||
|
||||
protected List<String> getNativeHeader(String headerName) { |
||||
if (this.nativeHeaders.containsKey(headerName)) { |
||||
return this.nativeHeaders.get(headerName); |
||||
} |
||||
else if (this.originalNativeHeaders != null) { |
||||
return this.originalNativeHeaders.get(headerName); |
||||
} |
||||
return null; |
||||
} |
||||
|
||||
protected String getFirstNativeHeader(String headerName) { |
||||
List<String> values = getNativeHeader(headerName); |
||||
return CollectionUtils.isEmpty(values) ? null : values.get(0); |
||||
} |
||||
|
||||
/** |
||||
* Set the value for the given header name. If the provided value is {@code null} the |
||||
* header will be removed. |
||||
*/ |
||||
protected void putNativeHeader(String name, List<String> value) { |
||||
if (!ObjectUtils.nullSafeEquals(value, getHeader(name))) { |
||||
this.nativeHeaders.put(name, value); |
||||
} |
||||
} |
||||
|
||||
protected void setNativeHeader(String name, String value) { |
||||
this.nativeHeaders.set(name, value); |
||||
} |
||||
|
||||
} |
||||
@ -1,251 +0,0 @@
@@ -1,251 +0,0 @@
|
||||
/* |
||||
* Copyright 2002-2013 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. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package org.springframework.web.messaging.support; |
||||
|
||||
import java.util.Arrays; |
||||
import java.util.Collections; |
||||
import java.util.HashMap; |
||||
import java.util.List; |
||||
import java.util.Map; |
||||
|
||||
import org.apache.commons.logging.Log; |
||||
import org.apache.commons.logging.LogFactory; |
||||
import org.springframework.http.MediaType; |
||||
import org.springframework.messaging.Message; |
||||
import org.springframework.messaging.MessageHeaders; |
||||
import org.springframework.util.Assert; |
||||
import org.springframework.util.CollectionUtils; |
||||
import org.springframework.util.LinkedMultiValueMap; |
||||
import org.springframework.web.messaging.MessageType; |
||||
|
||||
|
||||
/** |
||||
* A base class for working with message headers in Web, messaging protocols that support |
||||
* the publish-subscribe message pattern. Provides uniform access to specific values |
||||
* common across protocols such as a destination, message type (publish, |
||||
* subscribe/unsubscribe), session id, and others. |
||||
* <p> |
||||
* This class can be used to prepare headers for a new pub-sub message, or to access |
||||
* and/or modify headers of an existing message. |
||||
* <p> |
||||
* Use one of the static factory method in this class, then call getters and setters, and |
||||
* at the end if necessary call {@link #toHeaders()} to obtain the updated headers. |
||||
* |
||||
* @author Rossen Stoyanchev |
||||
* @since 4.0 |
||||
*/ |
||||
public class PubSubHeaderAccesssor { |
||||
|
||||
protected Log logger = LogFactory.getLog(getClass()); |
||||
|
||||
public static final String DESTINATIONS = "destinations"; |
||||
|
||||
public static final String CONTENT_TYPE = "contentType"; |
||||
|
||||
public static final String MESSAGE_TYPE = "messageType"; |
||||
|
||||
public static final String PROTOCOL_MESSAGE_TYPE = "protocolMessageType"; |
||||
|
||||
public static final String SESSION_ID = "sessionId"; |
||||
|
||||
public static final String SUBSCRIPTION_ID = "subscriptionId"; |
||||
|
||||
public static final String EXTERNAL_SOURCE_HEADERS = "extSourceHeaders"; |
||||
|
||||
|
||||
private static final Map<String, List<String>> emptyMultiValueMap = |
||||
Collections.unmodifiableMap(new LinkedMultiValueMap<String, String>(0)); |
||||
|
||||
|
||||
// wrapped read-only message headers
|
||||
private final MessageHeaders originalHeaders; |
||||
|
||||
// header updates
|
||||
private final Map<String, Object> headers = new HashMap<String, Object>(4); |
||||
|
||||
// saved headers from a message from a remote source
|
||||
private final Map<String, List<String>> externalSourceHeaders; |
||||
|
||||
|
||||
|
||||
/** |
||||
* A constructor for creating new message headers. |
||||
* This constructor is protected. See factory methods in this and sub-classes. |
||||
*/ |
||||
protected PubSubHeaderAccesssor(MessageType messageType, Object protocolMessageType, |
||||
Map<String, List<String>> externalSourceHeaders) { |
||||
|
||||
this.originalHeaders = null; |
||||
|
||||
Assert.notNull(messageType, "messageType is required"); |
||||
this.headers.put(MESSAGE_TYPE, messageType); |
||||
|
||||
if (protocolMessageType != null) { |
||||
this.headers.put(PROTOCOL_MESSAGE_TYPE, protocolMessageType); |
||||
} |
||||
|
||||
if (externalSourceHeaders == null) { |
||||
this.externalSourceHeaders = emptyMultiValueMap; |
||||
} |
||||
else { |
||||
this.externalSourceHeaders = Collections.unmodifiableMap(externalSourceHeaders); // TODO: list values must also be read-only
|
||||
this.headers.put(EXTERNAL_SOURCE_HEADERS, this.externalSourceHeaders); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* A constructor for accessing and modifying existing message headers. This |
||||
* constructor is protected. See factory methods in this and sub-classes. |
||||
*/ |
||||
@SuppressWarnings("unchecked") |
||||
protected PubSubHeaderAccesssor(Message<?> message) { |
||||
Assert.notNull(message, "message is required"); |
||||
this.originalHeaders = message.getHeaders(); |
||||
this.externalSourceHeaders = (this.originalHeaders.get(EXTERNAL_SOURCE_HEADERS) != null) ? |
||||
(Map<String, List<String>>) this.originalHeaders.get(EXTERNAL_SOURCE_HEADERS) : emptyMultiValueMap; |
||||
} |
||||
|
||||
|
||||
/** |
||||
* Create {@link PubSubHeaderAccesssor} for a new {@link Message} with |
||||
* {@link MessageType#MESSAGE}. |
||||
*/ |
||||
public static PubSubHeaderAccesssor create() { |
||||
return new PubSubHeaderAccesssor(MessageType.MESSAGE, null, null); |
||||
} |
||||
|
||||
/** |
||||
* Create {@link PubSubHeaderAccesssor} for a new {@link Message} of a specific type. |
||||
*/ |
||||
public static PubSubHeaderAccesssor create(MessageType messageType) { |
||||
return new PubSubHeaderAccesssor(messageType, null, null); |
||||
} |
||||
|
||||
/** |
||||
* Create {@link PubSubHeaderAccesssor} from the headers of an existing message. |
||||
*/ |
||||
public static PubSubHeaderAccesssor wrap(Message<?> message) { |
||||
return new PubSubHeaderAccesssor(message); |
||||
} |
||||
|
||||
|
||||
/** |
||||
* Return the original, wrapped headers (i.e. unmodified) or a new Map including any |
||||
* updates made via setters. |
||||
*/ |
||||
public Map<String, Object> toHeaders() { |
||||
if (!isModified()) { |
||||
return this.originalHeaders; |
||||
} |
||||
Map<String, Object> result = new HashMap<String, Object>(); |
||||
if (this.originalHeaders != null) { |
||||
result.putAll(this.originalHeaders); |
||||
} |
||||
result.putAll(this.headers); |
||||
return result; |
||||
} |
||||
|
||||
public boolean isModified() { |
||||
return ((this.originalHeaders == null) || !this.headers.isEmpty()); |
||||
} |
||||
|
||||
public MessageType getMessageType() { |
||||
return (MessageType) getHeaderValue(MESSAGE_TYPE); |
||||
} |
||||
|
||||
private Object getHeaderValue(String headerName) { |
||||
if (this.headers.get(headerName) != null) { |
||||
return this.headers.get(headerName); |
||||
} |
||||
else if ((this.originalHeaders != null) && (this.originalHeaders.get(headerName) != null)) { |
||||
return this.originalHeaders.get(headerName); |
||||
} |
||||
return null; |
||||
} |
||||
|
||||
protected void setProtocolMessageType(Object protocolMessageType) { |
||||
this.headers.put(PROTOCOL_MESSAGE_TYPE, protocolMessageType); |
||||
} |
||||
|
||||
protected Object getProtocolMessageType() { |
||||
return getHeaderValue(PROTOCOL_MESSAGE_TYPE); |
||||
} |
||||
|
||||
public void setDestination(String destination) { |
||||
Assert.notNull(destination, "destination is required"); |
||||
this.headers.put(DESTINATIONS, Arrays.asList(destination)); |
||||
} |
||||
|
||||
@SuppressWarnings("unchecked") |
||||
public String getDestination() { |
||||
List<String> destinations = (List<String>) getHeaderValue(DESTINATIONS); |
||||
return CollectionUtils.isEmpty(destinations) ? null : destinations.get(0); |
||||
} |
||||
|
||||
@SuppressWarnings("unchecked") |
||||
public List<String> getDestinations() { |
||||
List<String> destinations = (List<String>) getHeaderValue(DESTINATIONS); |
||||
return CollectionUtils.isEmpty(destinations) ? null : destinations; |
||||
} |
||||
|
||||
public void setDestinations(List<String> destinations) { |
||||
Assert.notNull(destinations, "destinations are required"); |
||||
this.headers.put(DESTINATIONS, destinations); |
||||
} |
||||
|
||||
public MediaType getContentType() { |
||||
return (MediaType) getHeaderValue(CONTENT_TYPE); |
||||
} |
||||
|
||||
public void setContentType(MediaType contentType) { |
||||
Assert.notNull(contentType, "contentType is required"); |
||||
this.headers.put(CONTENT_TYPE, contentType); |
||||
} |
||||
|
||||
public String getSubscriptionId() { |
||||
return (String) getHeaderValue(SUBSCRIPTION_ID); |
||||
} |
||||
|
||||
public void setSubscriptionId(String subscriptionId) { |
||||
this.headers.put(SUBSCRIPTION_ID, subscriptionId); |
||||
} |
||||
|
||||
public String getSessionId() { |
||||
return (String) getHeaderValue(SESSION_ID); |
||||
} |
||||
|
||||
public void setSessionId(String sessionId) { |
||||
this.headers.put(SESSION_ID, sessionId); |
||||
} |
||||
|
||||
/** |
||||
* Return a read-only map of headers originating from a message received by the |
||||
* application from an external source (e.g. from a remote WebSocket endpoint). The |
||||
* header names and values are exactly as they were, and are protocol specific but may |
||||
* also be custom application headers if the protocol allows that. |
||||
*/ |
||||
public Map<String, List<String>> getExternalSourceHeaders() { |
||||
return this.externalSourceHeaders; |
||||
} |
||||
|
||||
@Override |
||||
public String toString() { |
||||
return "PubSubHeaders [originalHeaders=" + this.originalHeaders + ", headers=" |
||||
+ this.headers + ", externalSourceHeaders=" + this.externalSourceHeaders + "]"; |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,167 @@
@@ -0,0 +1,167 @@
|
||||
/* |
||||
* Copyright 2002-2013 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. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package org.springframework.web.messaging.support; |
||||
|
||||
import java.util.Arrays; |
||||
import java.util.List; |
||||
import java.util.Map; |
||||
|
||||
import org.springframework.http.MediaType; |
||||
import org.springframework.messaging.Message; |
||||
import org.springframework.messaging.support.NativeMessageHeaderAccessor; |
||||
import org.springframework.util.Assert; |
||||
import org.springframework.util.CollectionUtils; |
||||
import org.springframework.web.messaging.MessageType; |
||||
|
||||
|
||||
/** |
||||
* A base class for working with message headers in Web, messaging protocols that support |
||||
* the publish-subscribe message pattern. Provides uniform access to specific values |
||||
* common across protocols such as a destination, message type (publish, |
||||
* subscribe/unsubscribe), session id, and others. |
||||
* <p> |
||||
* Use one of the static factory method in this class, then call getters and setters, and |
||||
* at the end if necessary call {@link #toMap()} to obtain the updated headers. |
||||
* |
||||
* @author Rossen Stoyanchev |
||||
* @since 4.0 |
||||
*/ |
||||
public class WebMessageHeaderAccesssor extends NativeMessageHeaderAccessor { |
||||
|
||||
public static final String DESTINATIONS = "destinations"; |
||||
|
||||
public static final String CONTENT_TYPE = "contentType"; |
||||
|
||||
public static final String MESSAGE_TYPE = "messageType"; |
||||
|
||||
public static final String PROTOCOL_MESSAGE_TYPE = "protocolMessageType"; |
||||
|
||||
public static final String SESSION_ID = "sessionId"; |
||||
|
||||
public static final String SUBSCRIPTION_ID = "subscriptionId"; |
||||
|
||||
|
||||
/** |
||||
* A constructor for creating new message headers. |
||||
* This constructor is protected. See factory methods in this and sub-classes. |
||||
*/ |
||||
protected WebMessageHeaderAccesssor(MessageType messageType, Object protocolMessageType, |
||||
Map<String, List<String>> externalSourceHeaders) { |
||||
|
||||
super(externalSourceHeaders); |
||||
|
||||
Assert.notNull(messageType, "messageType is required"); |
||||
setHeader(MESSAGE_TYPE, messageType); |
||||
|
||||
if (protocolMessageType != null) { |
||||
setHeader(PROTOCOL_MESSAGE_TYPE, protocolMessageType); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* A constructor for accessing and modifying existing message headers. This |
||||
* constructor is protected. See factory methods in this and sub-classes. |
||||
*/ |
||||
protected WebMessageHeaderAccesssor(Message<?> message) { |
||||
super(message); |
||||
Assert.notNull(message, "message is required"); |
||||
} |
||||
|
||||
|
||||
/** |
||||
* Create {@link WebMessageHeaderAccesssor} for a new {@link Message} with |
||||
* {@link MessageType#MESSAGE}. |
||||
*/ |
||||
public static WebMessageHeaderAccesssor create() { |
||||
return new WebMessageHeaderAccesssor(MessageType.MESSAGE, null, null); |
||||
} |
||||
|
||||
/** |
||||
* Create {@link WebMessageHeaderAccesssor} for a new {@link Message} of a specific type. |
||||
*/ |
||||
public static WebMessageHeaderAccesssor create(MessageType messageType) { |
||||
return new WebMessageHeaderAccesssor(messageType, null, null); |
||||
} |
||||
|
||||
/** |
||||
* Create {@link WebMessageHeaderAccesssor} from the headers of an existing message. |
||||
*/ |
||||
public static WebMessageHeaderAccesssor wrap(Message<?> message) { |
||||
return new WebMessageHeaderAccesssor(message); |
||||
} |
||||
|
||||
|
||||
public MessageType getMessageType() { |
||||
return (MessageType) getHeader(MESSAGE_TYPE); |
||||
} |
||||
|
||||
protected void setProtocolMessageType(Object protocolMessageType) { |
||||
setHeader(PROTOCOL_MESSAGE_TYPE, protocolMessageType); |
||||
} |
||||
|
||||
protected Object getProtocolMessageType() { |
||||
return getHeader(PROTOCOL_MESSAGE_TYPE); |
||||
} |
||||
|
||||
public void setDestination(String destination) { |
||||
Assert.notNull(destination, "destination is required"); |
||||
setHeader(DESTINATIONS, Arrays.asList(destination)); |
||||
} |
||||
|
||||
@SuppressWarnings("unchecked") |
||||
public String getDestination() { |
||||
List<String> destinations = (List<String>) getHeader(DESTINATIONS); |
||||
return CollectionUtils.isEmpty(destinations) ? null : destinations.get(0); |
||||
} |
||||
|
||||
@SuppressWarnings("unchecked") |
||||
public List<String> getDestinations() { |
||||
List<String> destinations = (List<String>) getHeader(DESTINATIONS); |
||||
return CollectionUtils.isEmpty(destinations) ? null : destinations; |
||||
} |
||||
|
||||
public void setDestinations(List<String> destinations) { |
||||
Assert.notNull(destinations, "destinations are required"); |
||||
setHeader(DESTINATIONS, destinations); |
||||
} |
||||
|
||||
public MediaType getContentType() { |
||||
return (MediaType) getHeader(CONTENT_TYPE); |
||||
} |
||||
|
||||
public void setContentType(MediaType contentType) { |
||||
Assert.notNull(contentType, "contentType is required"); |
||||
setHeader(CONTENT_TYPE, contentType); |
||||
} |
||||
|
||||
public String getSubscriptionId() { |
||||
return (String) getHeader(SUBSCRIPTION_ID); |
||||
} |
||||
|
||||
public void setSubscriptionId(String subscriptionId) { |
||||
setHeader(SUBSCRIPTION_ID, subscriptionId); |
||||
} |
||||
|
||||
public String getSessionId() { |
||||
return (String) getHeader(SESSION_ID); |
||||
} |
||||
|
||||
public void setSessionId(String sessionId) { |
||||
setHeader(SESSION_ID, sessionId); |
||||
} |
||||
|
||||
} |
||||
Loading…
Reference in new issue