001/* 002 * Copyright 2002-2014 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * https://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.springframework.messaging.support; 018 019import java.util.Map; 020 021import org.springframework.messaging.Message; 022import org.springframework.messaging.MessageChannel; 023import org.springframework.messaging.MessageHeaders; 024import org.springframework.util.Assert; 025 026/** 027 * A builder for creating a {@link GenericMessage} 028 * (or {@link ErrorMessage} if the payload is of type {@link Throwable}). 029 * 030 * @author Arjen Poutsma 031 * @author Mark Fisher 032 * @author Rossen Stoyanchev 033 * @since 4.0 034 * @see GenericMessage 035 * @see ErrorMessage 036 */ 037public final class MessageBuilder<T> { 038 039 private final T payload; 040 041 private final Message<T> originalMessage; 042 043 private MessageHeaderAccessor headerAccessor; 044 045 046 private MessageBuilder(Message<T> originalMessage) { 047 Assert.notNull(originalMessage, "Message must not be null"); 048 this.payload = originalMessage.getPayload(); 049 this.originalMessage = originalMessage; 050 this.headerAccessor = new MessageHeaderAccessor(originalMessage); 051 } 052 053 private MessageBuilder(T payload, MessageHeaderAccessor accessor) { 054 Assert.notNull(payload, "Payload must not be null"); 055 Assert.notNull(accessor, "MessageHeaderAccessor must not be null"); 056 this.payload = payload; 057 this.originalMessage = null; 058 this.headerAccessor = accessor; 059 } 060 061 062 /** 063 * Set the message headers to use by providing a {@code MessageHeaderAccessor}. 064 * @param accessor the headers to use 065 */ 066 public MessageBuilder<T> setHeaders(MessageHeaderAccessor accessor) { 067 Assert.notNull(accessor, "MessageHeaderAccessor must not be null"); 068 this.headerAccessor = accessor; 069 return this; 070 } 071 072 /** 073 * Set the value for the given header name. If the provided value is {@code null}, 074 * the header will be removed. 075 */ 076 public MessageBuilder<T> setHeader(String headerName, Object headerValue) { 077 this.headerAccessor.setHeader(headerName, headerValue); 078 return this; 079 } 080 081 /** 082 * Set the value for the given header name only if the header name is not already 083 * associated with a value. 084 */ 085 public MessageBuilder<T> setHeaderIfAbsent(String headerName, Object headerValue) { 086 this.headerAccessor.setHeaderIfAbsent(headerName, headerValue); 087 return this; 088 } 089 090 /** 091 * Removes all headers provided via array of 'headerPatterns'. As the name suggests 092 * the array may contain simple matching patterns for header names. Supported pattern 093 * styles are: "xxx*", "*xxx", "*xxx*" and "xxx*yyy". 094 */ 095 public MessageBuilder<T> removeHeaders(String... headerPatterns) { 096 this.headerAccessor.removeHeaders(headerPatterns); 097 return this; 098 } 099 /** 100 * Remove the value for the given header name. 101 */ 102 public MessageBuilder<T> removeHeader(String headerName) { 103 this.headerAccessor.removeHeader(headerName); 104 return this; 105 } 106 107 /** 108 * Copy the name-value pairs from the provided Map. This operation will overwrite any 109 * existing values. Use { {@link #copyHeadersIfAbsent(Map)} to avoid overwriting 110 * values. Note that the 'id' and 'timestamp' header values will never be overwritten. 111 */ 112 public MessageBuilder<T> copyHeaders(Map<String, ?> headersToCopy) { 113 this.headerAccessor.copyHeaders(headersToCopy); 114 return this; 115 } 116 117 /** 118 * Copy the name-value pairs from the provided Map. This operation will <em>not</em> 119 * overwrite any existing values. 120 */ 121 public MessageBuilder<T> copyHeadersIfAbsent(Map<String, ?> headersToCopy) { 122 this.headerAccessor.copyHeadersIfAbsent(headersToCopy); 123 return this; 124 } 125 126 public MessageBuilder<T> setReplyChannel(MessageChannel replyChannel) { 127 this.headerAccessor.setReplyChannel(replyChannel); 128 return this; 129 } 130 131 public MessageBuilder<T> setReplyChannelName(String replyChannelName) { 132 this.headerAccessor.setReplyChannelName(replyChannelName); 133 return this; 134 } 135 136 public MessageBuilder<T> setErrorChannel(MessageChannel errorChannel) { 137 this.headerAccessor.setErrorChannel(errorChannel); 138 return this; 139 } 140 141 public MessageBuilder<T> setErrorChannelName(String errorChannelName) { 142 this.headerAccessor.setErrorChannelName(errorChannelName); 143 return this; 144 } 145 146 @SuppressWarnings("unchecked") 147 public Message<T> build() { 148 if (this.originalMessage != null && !this.headerAccessor.isModified()) { 149 return this.originalMessage; 150 } 151 MessageHeaders headersToUse = this.headerAccessor.toMessageHeaders(); 152 if (this.payload instanceof Throwable) { 153 return (Message<T>) new ErrorMessage((Throwable) this.payload, headersToUse); 154 } 155 else { 156 return new GenericMessage<T>(this.payload, headersToUse); 157 } 158 } 159 160 161 /** 162 * Create a builder for a new {@link Message} instance pre-populated with all of the 163 * headers copied from the provided message. The payload of the provided Message will 164 * also be used as the payload for the new message. 165 * @param message the Message from which the payload and all headers will be copied 166 */ 167 public static <T> MessageBuilder<T> fromMessage(Message<T> message) { 168 return new MessageBuilder<T>(message); 169 } 170 171 /** 172 * Create a new builder for a message with the given payload. 173 * @param payload the payload 174 */ 175 public static <T> MessageBuilder<T> withPayload(T payload) { 176 return new MessageBuilder<T>(payload, new MessageHeaderAccessor()); 177 } 178 179 /** 180 * A shortcut factory method for creating a message with the given payload 181 * and {@code MessageHeaders}. 182 * <p><strong>Note:</strong> the given {@code MessageHeaders} instance is used 183 * directly in the new message, i.e. it is not copied. 184 * @param payload the payload to use (never {@code null}) 185 * @param messageHeaders the headers to use (never {@code null}) 186 * @return the created message 187 * @since 4.1 188 */ 189 @SuppressWarnings("unchecked") 190 public static <T> Message<T> createMessage(T payload, MessageHeaders messageHeaders) { 191 Assert.notNull(payload, "Payload must not be null"); 192 Assert.notNull(messageHeaders, "MessageHeaders must not be null"); 193 if (payload instanceof Throwable) { 194 return (Message<T>) new ErrorMessage((Throwable) payload, messageHeaders); 195 } 196 else { 197 return new GenericMessage<T>(payload, messageHeaders); 198 } 199 } 200 201}