|
1 | 1 | /*
|
2 |
| - * Copyright 2002-2018 the original author or authors. |
| 2 | + * Copyright 2002-2020 the original author or authors. |
3 | 3 | *
|
4 | 4 | * Licensed under the Apache License, Version 2.0 (the "License");
|
5 | 5 | * you may not use this file except in compliance with the License.
|
|
39 | 39 | import org.springframework.util.StringUtils;
|
40 | 40 |
|
41 | 41 | /**
|
42 |
| - * A base for classes providing strongly typed getters and setters as well as |
43 |
| - * behavior around specific categories of headers (e.g. STOMP headers). |
44 |
| - * Supports creating new headers, modifying existing headers (when still mutable), |
45 |
| - * or copying and modifying existing headers. |
46 |
| - * |
47 |
| - * <p>The method {@link #getMessageHeaders()} provides access to the underlying, |
48 |
| - * fully-prepared {@link MessageHeaders} that can then be used as-is (i.e. |
49 |
| - * without copying) to create a single message as follows: |
| 42 | + * Wrapper around {@link MessageHeaders} that provides extra features such as |
| 43 | + * strongly typed accessors for specific headers, the ability to leave headers |
| 44 | + * in a {@link Message} mutable, and the option to suppress automatic generation |
| 45 | + * of {@link MessageHeaders#ID id} and {@link MessageHeaders#TIMESTAMP |
| 46 | + * timesteamp} headers. Sub-classes such as {@link NativeMessageHeaderAccessor} |
| 47 | + * and others provide support for managing processing vs external source headers |
| 48 | + * as well as protocol specific headers. |
50 | 49 | *
|
| 50 | + * <p>Below is a workflow to initialize headers via {@code MessageHeaderAccessor}, |
| 51 | + * or one of its sub-classes, then create a {@link Message}, and then re-obtain |
| 52 | + * the accessor possibly from a different component: |
51 | 53 | * <pre class="code">
|
| 54 | + * // Create a message with headers |
52 | 55 | * MessageHeaderAccessor accessor = new MessageHeaderAccessor();
|
53 | 56 | * accessor.setHeader("foo", "bar");
|
54 |
| - * Message message = MessageBuilder.createMessage("payload", accessor.getMessageHeaders()); |
55 |
| - * </pre> |
| 57 | + * MessageHeaders headers = accessor.getMessageHeaders(); |
| 58 | + * Message message = MessageBuilder.createMessage("payload", headers); |
56 | 59 | *
|
57 |
| - * <p>After the above, by default the {@code MessageHeaderAccessor} becomes |
58 |
| - * immutable. However it is possible to leave it mutable for further initialization |
59 |
| - * in the same thread, for example: |
| 60 | + * // Later on |
| 61 | + * MessageHeaderAccessor accessor = MessageHeaderAccessor.getAccessor(message); |
| 62 | + * Assert.notNull(accessor, "No MessageHeaderAccessor"); |
| 63 | + * </pre> |
60 | 64 | *
|
| 65 | + * <p>In order for the above to work, all participating components must use |
| 66 | + * {@code MessageHeaders} to create, access, or modify headers, or otherwise |
| 67 | + * {@link MessageHeaderAccessor#getAccessor(Message, Class)} will return null. |
| 68 | + * Below is a workflow that shows how headers are created and left mutable, |
| 69 | + * then modified possibly by a different component, and finally made immutable |
| 70 | + * perhaps before the possibility of being accessed on a different thread: |
61 | 71 | * <pre class="code">
|
| 72 | + * // Create a message with mutable headers |
62 | 73 | * MessageHeaderAccessor accessor = new MessageHeaderAccessor();
|
63 | 74 | * accessor.setHeader("foo", "bar");
|
64 | 75 | * accessor.setLeaveMutable(true);
|
65 |
| - * Message message = MessageBuilder.createMessage("payload", accessor.getMessageHeaders()); |
| 76 | + * MessageHeaders headers = accessor.getMessageHeaders(); |
| 77 | + * Message message = MessageBuilder.createMessage("payload", headers); |
66 | 78 | *
|
67 |
| - * // later on in the same thread... |
| 79 | + * // Later on |
| 80 | + * MessageHeaderAccessor accessor = MessageHeaderAccessor.getAccessor(message); |
| 81 | + * if (accessor.isMutable()) { |
| 82 | + * // It's mutable, just change the headers |
| 83 | + * accessor.setHeader("bar", "baz"); |
| 84 | + * } |
| 85 | + * else { |
| 86 | + * // It's not, so get a mutable copy, change and re-create |
| 87 | + * accessor = MessageHeaderAccessor.getMutableAccessor(message); |
| 88 | + * accessor.setHeader("bar", "baz"); |
| 89 | + * accessor.setLeaveMutable(true); // leave mutable again or not? |
| 90 | + * message = MessageBuilder.createMessage(message.getPayload(), accessor); |
| 91 | + * } |
68 | 92 | *
|
| 93 | + * // Make the accessor immutable |
69 | 94 | * MessageHeaderAccessor accessor = MessageHeaderAccessor.getAccessor(message);
|
70 |
| - * accessor.setHeader("bar", "baz"); |
71 | 95 | * accessor.setImmutable();
|
72 | 96 | * </pre>
|
73 | 97 | *
|
74 |
| - * <p>The method {@link #toMap()} returns a copy of the underlying headers. It can |
75 |
| - * be used to prepare multiple messages from the same {@code MessageHeaderAccessor} |
76 |
| - * instance: |
77 |
| - * <pre class="code"> |
78 |
| - * MessageHeaderAccessor accessor = new MessageHeaderAccessor(); |
79 |
| - * MessageBuilder builder = MessageBuilder.withPayload("payload").setHeaders(accessor); |
80 |
| - * |
81 |
| - * accessor.setHeader("foo", "bar1"); |
82 |
| - * Message message1 = builder.build(); |
83 |
| - * |
84 |
| - * accessor.setHeader("foo", "bar2"); |
85 |
| - * Message message2 = builder.build(); |
86 |
| - * |
87 |
| - * accessor.setHeader("foo", "bar3"); |
88 |
| - * Message message3 = builder.build(); |
89 |
| - * </pre> |
90 |
| - * |
91 |
| - * <p>However note that with the above style, the header accessor is shared and |
92 |
| - * cannot be re-obtained later on. Alternatively it is also possible to create |
93 |
| - * one {@code MessageHeaderAccessor} per message: |
94 |
| - * |
95 |
| - * <pre class="code"> |
96 |
| - * MessageHeaderAccessor accessor1 = new MessageHeaderAccessor(); |
97 |
| - * accessor.set("foo", "bar1"); |
98 |
| - * Message message1 = MessageBuilder.createMessage("payload", accessor1.getMessageHeaders()); |
99 |
| - * |
100 |
| - * MessageHeaderAccessor accessor2 = new MessageHeaderAccessor(); |
101 |
| - * accessor.set("foo", "bar2"); |
102 |
| - * Message message2 = MessageBuilder.createMessage("payload", accessor2.getMessageHeaders()); |
103 |
| - * |
104 |
| - * MessageHeaderAccessor accessor3 = new MessageHeaderAccessor(); |
105 |
| - * accessor.set("foo", "bar3"); |
106 |
| - * Message message3 = MessageBuilder.createMessage("payload", accessor3.getMessageHeaders()); |
107 |
| - * </pre> |
108 |
| - * |
109 |
| - * <p>Note that the above examples aim to demonstrate the general idea of using |
110 |
| - * header accessors. The most likely usage however is through subclasses. |
111 |
| - * |
112 | 98 | * @author Rossen Stoyanchev
|
113 | 99 | * @author Juergen Hoeller
|
114 | 100 | * @since 4.0
|
@@ -568,6 +554,21 @@ public String toString() {
|
568 | 554 |
|
569 | 555 | // Static factory methods
|
570 | 556 |
|
| 557 | + /** |
| 558 | + * Return the original {@code MessageHeaderAccessor} used to create the headers |
| 559 | + * of the given {@code Message}, or {@code null} if that's not available or if |
| 560 | + * its type does not match the required type. |
| 561 | + * <p>This is for cases where the existence of an accessor is strongly expected |
| 562 | + * (followed up with an assertion) or where an accessor will be created otherwise. |
| 563 | + * @param message the message to get an accessor for |
| 564 | + * @return an accessor instance of the specified type, or {@code null} if none |
| 565 | + * @since 5.1.19 |
| 566 | + */ |
| 567 | + @Nullable |
| 568 | + public static MessageHeaderAccessor getAccessor(Message<?> message) { |
| 569 | + return getAccessor(message.getHeaders(), null); |
| 570 | + } |
| 571 | + |
571 | 572 | /**
|
572 | 573 | * Return the original {@code MessageHeaderAccessor} used to create the headers
|
573 | 574 | * of the given {@code Message}, or {@code null} if that's not available or if
|
@@ -627,6 +628,11 @@ public static MessageHeaderAccessor getMutableAccessor(Message<?> message) {
|
627 | 628 | }
|
628 | 629 |
|
629 | 630 |
|
| 631 | + /** |
| 632 | + * Extension of {@link MessageHeaders} that helps to preserve the link to |
| 633 | + * the outer {@link MessageHeaderAccessor} instance that created it as well |
| 634 | + * as keeps track of whether headers are still mutable. |
| 635 | + */ |
630 | 636 | @SuppressWarnings("serial")
|
631 | 637 | private class MutableMessageHeaders extends MessageHeaders {
|
632 | 638 |
|
|
0 commit comments