INT-4457: Add logAndReply() terminal operator

JIRA: https://jira.spring.io/browse/INT-4457

When an `IntegrationFlow` is reply-based (we expect a reply in the
beginning) and `log()` (or `wireTap()`) is used in the end, we are
forced to add an empty `bridge()` in the end to ensure a `replyChannel`
header routing

* Fix `IntegrationFlowDefinition` to add `enrichHeaders()` in the end
to populate a `nullChannel` as a `replyChannel` header if that is missed
in the request message headers.
This way we cover both use-cases when we expect reply from the flow and
when it is used as a one-way scenario
* Improve a `HeaderEnricher` do not create a new `Message` if there are
no new headers to add/remove
* Remove a note from the `dsl.adoc` about now redundant `bridge()` after
`log()`
* Resolve TODO in the `.handle()` paragraph

* Restore anonymous class in the MessageHistoryIntegrationTests:
Mockito can't mock/spy lambdas because they are `final` classes

* Introduce `IntegrationFlowDefinition.logAndReply()` operator

* Fix logging message

Doc Polishing
This commit is contained in:
Artem Bilan
2018-08-02 16:36:35 -04:00
committed by Gary Russell
parent 4a85849bcc
commit 055e9a40db
7 changed files with 386 additions and 72 deletions

View File

@@ -2194,6 +2194,9 @@ public abstract class IntegrationFlowDefinition<B extends IntegrationFlowDefinit
* logging level and {@code org.springframework.integration.handler.LoggingHandler}
* as a default logging category.
* <p> The full request {@link Message} will be logged.
* <p> When this operator is used in the end of flow, it is treated
* as one-way handler without any replies to continue.
* The {@link #logAndReply()} should be used for request-reply configuration.
* @return the current {@link IntegrationFlowDefinition}.
* @see #wireTap(WireTapSpec)
*/
@@ -2207,6 +2210,9 @@ public abstract class IntegrationFlowDefinition<B extends IntegrationFlowDefinit
* logging level and {@code org.springframework.integration.handler.LoggingHandler}
* as a default logging category.
* <p> The full request {@link Message} will be logged.
* <p> When this operator is used in the end of flow, it is treated
* as one-way handler without any replies to continue.
* The {@link #logAndReply()} should be used for request-reply configuration.
* @param level the {@link LoggingHandler.Level}.
* @return the current {@link IntegrationFlowDefinition}.
* @see #wireTap(WireTapSpec)
@@ -2220,6 +2226,9 @@ public abstract class IntegrationFlowDefinition<B extends IntegrationFlowDefinit
* with the {@link LoggingHandler} subscriber for the provided logging category
* and {@code INFO} logging level.
* <p> The full request {@link Message} will be logged.
* <p> When this operator is used in the end of flow, it is treated
* as one-way handler without any replies to continue.
* The {@link #logAndReply()} should be used for request-reply configuration.
* @param category the logging category to use.
* @return the current {@link IntegrationFlowDefinition}.
* @see #wireTap(WireTapSpec)
@@ -2233,6 +2242,9 @@ public abstract class IntegrationFlowDefinition<B extends IntegrationFlowDefinit
* with the {@link LoggingHandler} subscriber for the provided
* {@link LoggingHandler.Level} logging level and logging category.
* <p> The full request {@link Message} will be logged.
* <p> When this operator is used in the end of flow, it is treated
* as one-way handler without any replies to continue.
* The {@link #logAndReply()} should be used for request-reply configuration.
* @param level the {@link LoggingHandler.Level}.
* @param category the logging category to use.
* @return the current {@link IntegrationFlowDefinition}.
@@ -2247,6 +2259,9 @@ public abstract class IntegrationFlowDefinition<B extends IntegrationFlowDefinit
* with the {@link LoggingHandler} subscriber for the provided
* {@link LoggingHandler.Level} logging level, logging category
* and SpEL expression for the log message.
* <p> When this operator is used in the end of flow, it is treated
* as one-way handler without any replies to continue.
* The {@link #logAndReply()} should be used for request-reply configuration.
* @param level the {@link LoggingHandler.Level}.
* @param category the logging category.
* @param logExpression the SpEL expression to evaluate logger message at runtime
@@ -2264,6 +2279,9 @@ public abstract class IntegrationFlowDefinition<B extends IntegrationFlowDefinit
* with the {@link LoggingHandler} subscriber for the {@code INFO} logging level,
* the {@code org.springframework.integration.handler.LoggingHandler}
* as a default logging category and {@link Function} for the log message.
* <p> When this operator is used in the end of flow, it is treated
* as one-way handler without any replies to continue.
* The {@link #logAndReply()} should be used for request-reply configuration.
* @param function the function to evaluate logger message at runtime
* @param <P> the expected payload type.
* against the request {@link Message}.
@@ -2281,6 +2299,9 @@ public abstract class IntegrationFlowDefinition<B extends IntegrationFlowDefinit
* the {@code org.springframework.integration.handler.LoggingHandler}
* as a default logging category and SpEL expression to evaluate
* logger message at runtime against the request {@link Message}.
* <p> When this operator is used in the end of flow, it is treated
* as one-way handler without any replies to continue.
* The {@link #logAndReply()} should be used for request-reply configuration.
* @param logExpression the {@link Expression} to evaluate logger message at runtime
* against the request {@link Message}.
* @return the current {@link IntegrationFlowDefinition}.
@@ -2297,6 +2318,9 @@ public abstract class IntegrationFlowDefinition<B extends IntegrationFlowDefinit
* the {@code org.springframework.integration.handler.LoggingHandler}
* as a default logging category and SpEL expression to evaluate
* logger message at runtime against the request {@link Message}.
* <p> When this operator is used in the end of flow, it is treated
* as one-way handler without any replies to continue.
* The {@link #logAndReply()} should be used for request-reply configuration.
* @param level the {@link LoggingHandler.Level}.
* @param logExpression the {@link Expression} to evaluate logger message at runtime
* against the request {@link Message}.
@@ -2307,13 +2331,15 @@ public abstract class IntegrationFlowDefinition<B extends IntegrationFlowDefinit
return log(level, null, logExpression);
}
/**
* Populate a {@link WireTap} for the {@link #currentMessageChannel}
* with the {@link LoggingHandler} subscriber for the {@code INFO}
* {@link LoggingHandler.Level} logging level,
* the provided logging category and SpEL expression to evaluate
* logger message at runtime against the request {@link Message}.
* <p> When this operator is used in the end of flow, it is treated
* as one-way handler without any replies to continue.
* The {@link #logAndReply()} should be used for request-reply configuration.
* @param category the logging category.
* @param logExpression the {@link Expression} to evaluate logger message at runtime
* against the request {@link Message}.
@@ -2330,6 +2356,9 @@ public abstract class IntegrationFlowDefinition<B extends IntegrationFlowDefinit
* {@link LoggingHandler.Level} logging level,
* the {@code org.springframework.integration.handler.LoggingHandler}
* as a default logging category and {@link Function} for the log message.
* <p> When this operator is used in the end of flow, it is treated
* as one-way handler without any replies to continue.
* The {@link #logAndReply()} should be used for request-reply configuration.
* @param level the {@link LoggingHandler.Level}.
* @param function the function to evaluate logger message at runtime
* @param <P> the expected payload type.
@@ -2346,6 +2375,9 @@ public abstract class IntegrationFlowDefinition<B extends IntegrationFlowDefinit
* with the {@link LoggingHandler} subscriber for the provided
* {@link LoggingHandler.Level} logging level,
* the provided logging category and {@link Function} for the log message.
* <p> When this operator is used in the end of flow, it is treated
* as one-way handler without any replies to continue.
* The {@link #logAndReply()} should be used for request-reply configuration.
* @param category the logging category.
* @param function the function to evaluate logger message at runtime
* @param <P> the expected payload type.
@@ -2362,6 +2394,9 @@ public abstract class IntegrationFlowDefinition<B extends IntegrationFlowDefinit
* with the {@link LoggingHandler} subscriber for the provided
* {@link LoggingHandler.Level} logging level, logging category
* and {@link Function} for the log message.
* <p> When this operator is used in the end of flow, it is treated
* as one-way handler without any replies to continue.
* The {@link #logAndReply()} should be used for request-reply configuration.
* @param level the {@link LoggingHandler.Level}.
* @param category the logging category.
* @param function the function to evaluate logger message at runtime
@@ -2375,12 +2410,14 @@ public abstract class IntegrationFlowDefinition<B extends IntegrationFlowDefinit
return log(level, category, new FunctionExpression<>(function));
}
/**
* Populate a {@link WireTap} for the {@link #currentMessageChannel}
* with the {@link LoggingHandler} subscriber for the provided
* {@link LoggingHandler.Level} logging level, logging category
* and SpEL expression for the log message.
* <p> When this operator is used in the end of flow, it is treated
* as one-way handler without any replies to continue.
* The {@link #logAndReply()} should be used for request-reply configuration.
* @param level the {@link LoggingHandler.Level}.
* @param category the logging category.
* @param logExpression the {@link Expression} to evaluate logger message at runtime
@@ -2406,6 +2443,264 @@ public abstract class IntegrationFlowDefinition<B extends IntegrationFlowDefinit
return wireTap(loggerChannel);
}
/**
* Populate a {@link WireTap} for the {@link #currentMessageChannel}
* with the {@link LoggingHandler} subscriber for the {@code INFO}
* logging level and {@code org.springframework.integration.handler.LoggingHandler}
* as a default logging category.
* <p> The full request {@link Message} will be logged.
* <p> A {@link #bridge()} is added after this operator to make the flow reply-producing
* if the {@code replyChannel} header is present.
* <p> This operator can be used only in the end of flow.
* @return an {@link IntegrationFlow} instance based on this builder.
* @see #log()
* @see #bridge()
*/
public IntegrationFlow logAndReply() {
return logAndReply(LoggingHandler.Level.INFO);
}
/**
* Populate a {@link WireTap} for the {@link #currentMessageChannel}
* with the {@link LoggingHandler} subscriber for provided {@link LoggingHandler.Level}
* logging level and {@code org.springframework.integration.handler.LoggingHandler}
* as a default logging category.
* <p> The full request {@link Message} will be logged.
* <p> A {@link #bridge()} is added after this operator to make the flow reply-producing
* if the {@code replyChannel} header is present.
* <p> This operator can be used only in the end of flow.
* @param level the {@link LoggingHandler.Level}.
* @return an {@link IntegrationFlow} instance based on this builder.
* @see #log()
* @see #bridge()
*/
public IntegrationFlow logAndReply(LoggingHandler.Level level) {
return logAndReply(level, (String) null);
}
/**
* Populate a {@link WireTap} for the {@link #currentMessageChannel}
* with the {@link LoggingHandler} subscriber for the provided logging category
* and {@code INFO} logging level.
* <p> The full request {@link Message} will be logged.
* <p> A {@link #bridge()} is added after this operator to make the flow reply-producing
* if the {@code replyChannel} header is present.
* <p> This operator can be used only in the end of flow.
* @param category the logging category to use.
* @return an {@link IntegrationFlow} instance based on this builder.
* @see #log()
* @see #bridge()
*/
public IntegrationFlow logAndReply(String category) {
return logAndReply(LoggingHandler.Level.INFO, category);
}
/**
* Populate a {@link WireTap} for the {@link #currentMessageChannel}
* with the {@link LoggingHandler} subscriber for the provided
* {@link LoggingHandler.Level} logging level and logging category.
* <p> The full request {@link Message} will be logged.
* <p> A {@link #bridge()} is added after this operator to make the flow reply-producing
* if the {@code replyChannel} header is present.
* <p> This operator can be used only in the end of flow.
* @param level the {@link LoggingHandler.Level}.
* @param category the logging category to use.
* @return an {@link IntegrationFlow} instance based on this builder.
* @see #log()
* @see #bridge()
*/
public IntegrationFlow logAndReply(LoggingHandler.Level level, String category) {
return logAndReply(level, category, (Expression) null);
}
/**
* Populate a {@link WireTap} for the {@link #currentMessageChannel}
* with the {@link LoggingHandler} subscriber for the provided
* {@link LoggingHandler.Level} logging level, logging category
* and SpEL expression for the log message.
* <p> A {@link #bridge()} is added after this operator to make the flow reply-producing
* if the {@code replyChannel} header is present.
* <p> This operator can be used only in the end of flow.
* @param level the {@link LoggingHandler.Level}.
* @param category the logging category.
* @param logExpression the SpEL expression to evaluate logger message at runtime
* against the request {@link Message}.
* @return an {@link IntegrationFlow} instance based on this builder.
* @see #log()
* @see #bridge()
*/
public IntegrationFlow logAndReply(LoggingHandler.Level level, String category, String logExpression) {
Assert.hasText(logExpression, "'logExpression' must not be empty");
return logAndReply(level, category, PARSER.parseExpression(logExpression));
}
/**
* Populate a {@link WireTap} for the {@link #currentMessageChannel}
* with the {@link LoggingHandler} subscriber for the {@code INFO} logging level,
* the {@code org.springframework.integration.handler.LoggingHandler}
* as a default logging category and {@link Function} for the log message.
* <p> A {@link #bridge()} is added after this operator to make the flow reply-producing
* if the {@code replyChannel} header is present.
* <p> This operator can be used only in the end of flow.
* @param function the function to evaluate logger message at runtime
* @param <P> the expected payload type.
* against the request {@link Message}.
* @return an {@link IntegrationFlow} instance based on this builder.
* @see #log()
* @see #bridge()
*/
public <P> IntegrationFlow logAndReply(Function<Message<P>, Object> function) {
Assert.notNull(function, "'function' must not be null");
return logAndReply(new FunctionExpression<>(function));
}
/**
* Populate a {@link WireTap} for the {@link #currentMessageChannel}
* with the {@link LoggingHandler} subscriber for the {@code INFO} logging level,
* the {@code org.springframework.integration.handler.LoggingHandler}
* as a default logging category and SpEL expression to evaluate
* logger message at runtime against the request {@link Message}.
* <p> A {@link #bridge()} is added after this operator to make the flow reply-producing
* if the {@code replyChannel} header is present.
* <p> This operator can be used only in the end of flow.
* @param logExpression the {@link Expression} to evaluate logger message at runtime
* against the request {@link Message}.
* @return an {@link IntegrationFlow} instance based on this builder.
* @see #log()
* @see #bridge()
*/
public IntegrationFlow logAndReply(Expression logExpression) {
return logAndReply(LoggingHandler.Level.INFO, logExpression);
}
/**
* Populate a {@link WireTap} for the {@link #currentMessageChannel}
* with the {@link LoggingHandler} subscriber for the provided
* {@link LoggingHandler.Level} logging level,
* the {@code org.springframework.integration.handler.LoggingHandler}
* as a default logging category and SpEL expression to evaluate
* logger message at runtime against the request {@link Message}.
* <p> A {@link #bridge()} is added after this operator to make the flow reply-producing
* if the {@code replyChannel} header is present.
* <p> This operator can be used only in the end of flow.
* @param level the {@link LoggingHandler.Level}.
* @param logExpression the {@link Expression} to evaluate logger message at runtime
* against the request {@link Message}.
* @return an {@link IntegrationFlow} instance based on this builder.
* @see #log()
* @see #bridge()
*/
public IntegrationFlow logAndReply(LoggingHandler.Level level, Expression logExpression) {
return logAndReply(level, null, logExpression);
}
/**
* Populate a {@link WireTap} for the {@link #currentMessageChannel}
* with the {@link LoggingHandler} subscriber for the {@code INFO}
* {@link LoggingHandler.Level} logging level,
* the provided logging category and SpEL expression to evaluate
* logger message at runtime against the request {@link Message}.
* <p> A {@link #bridge()} is added after this operator to make the flow reply-producing
* if the {@code replyChannel} header is present.
* <p> This operator can be used only in the end of flow.
* @param category the logging category.
* @param logExpression the {@link Expression} to evaluate logger message at runtime
* against the request {@link Message}.
* @return an {@link IntegrationFlow} instance based on this builder.
* @see #log()
* @see #bridge()
*/
public IntegrationFlow logAndReply(String category, Expression logExpression) {
return logAndReply(LoggingHandler.Level.INFO, category, logExpression);
}
/**
* Populate a {@link WireTap} for the {@link #currentMessageChannel}
* with the {@link LoggingHandler} subscriber for the provided
* {@link LoggingHandler.Level} logging level,
* the {@code org.springframework.integration.handler.LoggingHandler}
* as a default logging category and {@link Function} for the log message.
* <p> A {@link #bridge()} is added after this operator to make the flow reply-producing
* if the {@code replyChannel} header is present.
* <p> This operator can be used only in the end of flow.
* @param level the {@link LoggingHandler.Level}.
* @param function the function to evaluate logger message at runtime
* @param <P> the expected payload type.
* against the request {@link Message}.
* @return an {@link IntegrationFlow} instance based on this builder.
* @see #log()
* @see #bridge()
*/
public <P> IntegrationFlow logAndReply(LoggingHandler.Level level, Function<Message<P>, Object> function) {
return logAndReply(level, null, function);
}
/**
* Populate a {@link WireTap} for the {@link #currentMessageChannel}
* with the {@link LoggingHandler} subscriber for the provided
* {@link LoggingHandler.Level} logging level,
* the provided logging category and {@link Function} for the log message.
* <p> A {@link #bridge()} is added after this operator to make the flow reply-producing
* if the {@code replyChannel} header is present.
* <p> This operator can be used only in the end of flow.
* @param category the logging category.
* @param function the function to evaluate logger message at runtime
* @param <P> the expected payload type.
* against the request {@link Message}.
* @return an {@link IntegrationFlow} instance based on this builder.
* @see #log()
* @see #bridge()
*/
public <P> IntegrationFlow logAndReply(String category, Function<Message<P>, Object> function) {
return logAndReply(LoggingHandler.Level.INFO, category, function);
}
/**
* Populate a {@link WireTap} for the {@link #currentMessageChannel}
* with the {@link LoggingHandler} subscriber for the provided
* {@link LoggingHandler.Level} logging level, logging category
* and {@link Function} for the log message.
* <p> A {@link #bridge()} is added after this operator to make the flow reply-producing
* if the {@code replyChannel} header is present.
* <p> This operator can be used only in the end of flow.
* @param level the {@link LoggingHandler.Level}.
* @param category the logging category.
* @param function the function to evaluate logger message at runtime
* @param <P> the expected payload type.
* against the request {@link Message}.
* @return an {@link IntegrationFlow} instance based on this builder.
* @see #log()
* @see #bridge()
*/
public <P> IntegrationFlow logAndReply(LoggingHandler.Level level, String category,
Function<Message<P>, Object> function) {
Assert.notNull(function, "'function' must not be null");
return logAndReply(level, category, new FunctionExpression<>(function));
}
/**
* Populate a {@link WireTap} for the {@link #currentMessageChannel}
* with the {@link LoggingHandler} subscriber for the provided
* {@link LoggingHandler.Level} logging level, logging category
* and SpEL expression for the log message.
* <p> A {@link #bridge()} is added after this operator to make the flow reply-producing
* if the {@code replyChannel} header is present.
* <p> This operator can be used only in the end of flow.
* @param level the {@link LoggingHandler.Level}.
* @param category the logging category.
* @param logExpression the {@link Expression} to evaluate logger message at runtime
* against the request {@link Message}.
* @return an {@link IntegrationFlow} instance based on this builder.
* @see #log()
* @see #bridge()
*/
public IntegrationFlow logAndReply(LoggingHandler.Level level, String category, Expression logExpression) {
return log(level, category, logExpression)
.bridge()
.get();
}
/**
* Populate a {@link ScatterGatherHandler} to the current integration flow position
* based on the provided {@link MessageChannel} for scattering function
@@ -2603,6 +2898,7 @@ public abstract class IntegrationFlowDefinition<B extends IntegrationFlowDefinit
@SuppressWarnings("unchecked")
private <S extends ConsumerEndpointSpec<S, ? extends MessageHandler>> B register(S endpointSpec,
Consumer<S> endpointConfigurer) {
if (endpointConfigurer != null) {
endpointConfigurer.accept(endpointSpec);
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2017 the original author or authors.
* Copyright 2002-2018 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.
@@ -29,11 +29,11 @@ import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.integration.context.IntegrationObjectSupport;
import org.springframework.integration.handler.MessageProcessor;
import org.springframework.integration.support.AbstractIntegrationMessageBuilder;
import org.springframework.integration.support.DefaultMessageBuilderFactory;
import org.springframework.integration.transformer.support.HeaderValueMessageProcessor;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageHeaders;
import org.springframework.messaging.MessagingException;
/**
* A Transformer that adds statically configured header values to a Message.
@@ -64,12 +64,13 @@ public class HeaderEnricher extends IntegrationObjectSupport implements Transfor
/**
* Create a HeaderEnricher with the given map of headers.
*
* @param headersToAdd The headers to add.
*/
public HeaderEnricher(Map<String, ? extends HeaderValueMessageProcessor<?>> headersToAdd) {
this.headersToAdd = (headersToAdd != null) ? headersToAdd
: new HashMap<String, HeaderValueMessageProcessor<Object>>();
this.headersToAdd =
headersToAdd != null
? headersToAdd
: new HashMap<String, HeaderValueMessageProcessor<Object>>();
}
public <T> void setMessageProcessor(MessageProcessor<T> messageProcessor) {
@@ -86,7 +87,6 @@ public class HeaderEnricher extends IntegrationObjectSupport implements Transfor
* <code>true</code>. Set this to <code>false</code> if a
* <code>null</code> value should trigger <i>removal</i> of the
* corresponding header instead.
*
* @param shouldSkipNulls true when null values should be skipped.
*/
public void setShouldSkipNulls(boolean shouldSkipNulls) {
@@ -96,52 +96,56 @@ public class HeaderEnricher extends IntegrationObjectSupport implements Transfor
@Override
public String getComponentType() {
return "transformer"; // backwards compatibility
return "header-enricher";
}
@Override
public Message<?> transform(Message<?> message) {
try {
Map<String, Object> headerMap = new HashMap<String, Object>(message.getHeaders());
this.addHeadersFromMessageProcessor(message, headerMap);
for (Map.Entry<String, ? extends HeaderValueMessageProcessor<?>> entry : this.headersToAdd.entrySet()) {
String key = entry.getKey();
HeaderValueMessageProcessor<?> valueProcessor = entry.getValue();
MessageHeaders messageHeaders = message.getHeaders();
Boolean shouldOverwrite = valueProcessor.isOverwrite();
if (shouldOverwrite == null) {
shouldOverwrite = this.defaultOverwrite;
}
AbstractIntegrationMessageBuilder<?> messageBuilder =
getMessageBuilderFactory()
.fromMessage(message);
boolean headerDoesNotExist = headerMap.get(key) == null;
addHeadersFromMessageProcessor(message, messageBuilder);
for (Map.Entry<String, ? extends HeaderValueMessageProcessor<?>> entry : this.headersToAdd.entrySet()) {
String key = entry.getKey();
HeaderValueMessageProcessor<?> valueProcessor = entry.getValue();
/*
* Only evaluate value expression if necessary
*/
if (headerDoesNotExist || shouldOverwrite) {
Object value = valueProcessor.processMessage(message);
if (value != null || !this.shouldSkipNulls) {
headerMap.put(key, value);
}
Boolean shouldOverwrite = valueProcessor.isOverwrite();
if (shouldOverwrite == null) {
shouldOverwrite = this.defaultOverwrite;
}
boolean headerDoesNotExist = messageHeaders.get(key) == null;
/*
* Only evaluate value expression if necessary
*/
if (headerDoesNotExist || shouldOverwrite) {
Object value = valueProcessor.processMessage(message);
if (value != null || !this.shouldSkipNulls) {
messageBuilder.setHeader(key, value);
}
}
return this.getMessageBuilderFactory().withPayload(message.getPayload()).copyHeaders(headerMap).build();
}
catch (Exception e) {
throw new MessagingException(message, "failed to transform message headers", e);
}
return messageBuilder.build();
}
private void addHeadersFromMessageProcessor(Message<?> message, Map<String, Object> headerMap) {
private void addHeadersFromMessageProcessor(Message<?> message,
AbstractIntegrationMessageBuilder<?> messageBuilder) {
if (this.messageProcessor != null) {
Object result = this.messageProcessor.processMessage(message);
if (result instanceof Map) {
MessageHeaders messageHeaders = message.getHeaders();
Map<?, ?> resultMap = (Map<?, ?>) result;
for (Entry<?, ?> entry : resultMap.entrySet()) {
Object key = entry.getKey();
if (key instanceof String) {
if (this.defaultOverwrite || headerMap.get(key) == null) {
headerMap.put((String) key, entry.getValue());
if (this.defaultOverwrite || messageHeaders.get(key) == null) {
messageBuilder.setHeader((String) key, entry.getValue());
}
}
else if (logger.isDebugEnabled()) {