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:
committed by
Gary Russell
parent
4a85849bcc
commit
055e9a40db
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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()) {
|
||||
|
||||
Reference in New Issue
Block a user