1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.springframework.messaging;
18
19 import java.io.IOException;
20 import java.io.ObjectInputStream;
21 import java.io.ObjectOutputStream;
22 import java.io.Serializable;
23 import java.util.ArrayList;
24 import java.util.Collection;
25 import java.util.Collections;
26 import java.util.HashMap;
27 import java.util.List;
28 import java.util.Map;
29 import java.util.Set;
30 import java.util.UUID;
31
32 import org.apache.commons.logging.Log;
33 import org.apache.commons.logging.LogFactory;
34
35 import org.springframework.util.AlternativeJdkIdGenerator;
36 import org.springframework.util.IdGenerator;
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71 public class MessageHeaders implements Map<String, Object>, Serializable {
72
73 public static final UUID ID_VALUE_NONE = new UUID(0,0);
74
75
76
77
78
79
80
81 public static final String ID = "id";
82
83 public static final String TIMESTAMP = "timestamp";
84
85 public static final String CONTENT_TYPE = "contentType";
86
87 public static final String REPLY_CHANNEL = "replyChannel";
88
89 public static final String ERROR_CHANNEL = "errorChannel";
90
91
92 private static final long serialVersionUID = 7035068984263400920L;
93
94 private static final Log logger = LogFactory.getLog(MessageHeaders.class);
95
96 private static final IdGenerator defaultIdGenerator = new AlternativeJdkIdGenerator();
97
98 private static volatile IdGenerator idGenerator = null;
99
100
101 private final Map<String, Object> headers;
102
103
104
105
106
107
108
109 public MessageHeaders(Map<String, Object> headers) {
110 this(headers, null, null);
111 }
112
113
114
115
116
117
118
119 protected MessageHeaders(Map<String, Object> headers, UUID id, Long timestamp) {
120 this.headers = (headers != null ? new HashMap<String, Object>(headers) : new HashMap<String, Object>());
121
122 if (id == null) {
123 this.headers.put(ID, getIdGenerator().generateId());
124 }
125 else if (id == ID_VALUE_NONE) {
126 this.headers.remove(ID);
127 }
128 else {
129 this.headers.put(ID, id);
130 }
131
132 if (timestamp == null) {
133 this.headers.put(TIMESTAMP, System.currentTimeMillis());
134 }
135 else if (timestamp < 0) {
136 this.headers.remove(TIMESTAMP);
137 }
138 else {
139 this.headers.put(TIMESTAMP, timestamp);
140 }
141 }
142
143
144 protected Map<String, Object> getRawHeaders() {
145 return this.headers;
146 }
147
148 protected static IdGenerator getIdGenerator() {
149 return (idGenerator != null ? idGenerator : defaultIdGenerator);
150 }
151
152 public UUID getId() {
153 return get(ID, UUID.class);
154 }
155
156 public Long getTimestamp() {
157 return get(TIMESTAMP, Long.class);
158 }
159
160 public Object getReplyChannel() {
161 return get(REPLY_CHANNEL);
162 }
163
164 public Object getErrorChannel() {
165 return get(ERROR_CHANNEL);
166 }
167
168 @SuppressWarnings("unchecked")
169 public <T> T get(Object key, Class<T> type) {
170 Object value = this.headers.get(key);
171 if (value == null) {
172 return null;
173 }
174 if (!type.isAssignableFrom(value.getClass())) {
175 throw new IllegalArgumentException("Incorrect type specified for header '" +
176 key + "'. Expected [" + type + "] but actual type is [" + value.getClass() + "]");
177 }
178 return (T) value;
179 }
180
181
182 @Override
183 public boolean equals(Object other) {
184 return (this == other ||
185 (other instanceof MessageHeaders && this.headers.equals(((MessageHeaders) other).headers)));
186 }
187
188 @Override
189 public int hashCode() {
190 return this.headers.hashCode();
191 }
192
193 @Override
194 public String toString() {
195 return this.headers.toString();
196 }
197
198
199
200
201 public boolean containsKey(Object key) {
202 return this.headers.containsKey(key);
203 }
204
205 public boolean containsValue(Object value) {
206 return this.headers.containsValue(value);
207 }
208
209 public Set<Map.Entry<String, Object>> entrySet() {
210 return Collections.unmodifiableSet(this.headers.entrySet());
211 }
212
213 public Object get(Object key) {
214 return this.headers.get(key);
215 }
216
217 public boolean isEmpty() {
218 return this.headers.isEmpty();
219 }
220
221 public Set<String> keySet() {
222 return Collections.unmodifiableSet(this.headers.keySet());
223 }
224
225 public int size() {
226 return this.headers.size();
227 }
228
229 public Collection<Object> values() {
230 return Collections.unmodifiableCollection(this.headers.values());
231 }
232
233
234
235
236
237
238
239
240 public Object put(String key, Object value) {
241 throw new UnsupportedOperationException("MessageHeaders is immutable");
242 }
243
244
245
246
247
248 public void putAll(Map<? extends String, ? extends Object> map) {
249 throw new UnsupportedOperationException("MessageHeaders is immutable");
250 }
251
252
253
254
255
256 public Object remove(Object key) {
257 throw new UnsupportedOperationException("MessageHeaders is immutable");
258 }
259
260
261
262
263
264 public void clear() {
265 throw new UnsupportedOperationException("MessageHeaders is immutable");
266 }
267
268
269
270
271 private void writeObject(ObjectOutputStream out) throws IOException {
272 List<String> keysToRemove = new ArrayList<String>();
273 for (Map.Entry<String, Object> entry : this.headers.entrySet()) {
274 if (!(entry.getValue() instanceof Serializable)) {
275 keysToRemove.add(entry.getKey());
276 }
277 }
278 for (String key : keysToRemove) {
279 if (logger.isInfoEnabled()) {
280 logger.info("Removing non-serializable header: " + key);
281 }
282 this.headers.remove(key);
283 }
284 out.defaultWriteObject();
285 }
286
287 private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
288 in.defaultReadObject();
289 }
290
291 }