INT-836 refactored HeaderEnricher to delegate to MessageProcessor implementations

This commit is contained in:
Mark Fisher
2010-06-11 22:10:11 +00:00
parent bfd6c81673
commit b6974b712c
4 changed files with 73 additions and 86 deletions

View File

@@ -120,7 +120,7 @@ public abstract class HeaderEnricherParserSupport extends AbstractTransformerPar
"Exactly one of the 'ref', 'value', or 'expression' attributes is required.", element);
}
Object headerSource = parserContext.extractSource(headerElement);
BeanDefinitionBuilder valueHolderBuilder = null;
BeanDefinitionBuilder valueProcessorBuilder = null;
if (isValue) {
if (hasMethod) {
parserContext.getReaderContext().error(
@@ -128,19 +128,19 @@ public abstract class HeaderEnricherParserSupport extends AbstractTransformerPar
}
Object headerValue = (headerType != null) ?
new TypedStringValue(value, headerType) : value;
valueHolderBuilder = BeanDefinitionBuilder.genericBeanDefinition(
IntegrationNamespaceUtils.BASE_PACKAGE + ".transformer.HeaderEnricher$StaticValueHolder");
valueHolderBuilder.addConstructorArgValue(headerValue);
valueProcessorBuilder = BeanDefinitionBuilder.genericBeanDefinition(
IntegrationNamespaceUtils.BASE_PACKAGE + ".transformer.HeaderEnricher$StaticHeaderValueMessageProcessor");
valueProcessorBuilder.addConstructorArgValue(headerValue);
}
else if (isExpression) {
if (hasMethod) {
parserContext.getReaderContext().error(
"The 'method' attribute cannot be used with the 'expression' attribute.", element);
}
valueHolderBuilder = BeanDefinitionBuilder.genericBeanDefinition(
IntegrationNamespaceUtils.BASE_PACKAGE + ".transformer.HeaderEnricher$ExpressionHolder");
valueHolderBuilder.addConstructorArgValue(expression);
valueHolderBuilder.addConstructorArgValue(headerType);
valueProcessorBuilder = BeanDefinitionBuilder.genericBeanDefinition(
IntegrationNamespaceUtils.BASE_PACKAGE + ".transformer.HeaderEnricher$ExpressionEvaluatingHeaderValueMessageProcessor");
valueProcessorBuilder.addConstructorArgValue(expression);
valueProcessorBuilder.addConstructorArgValue(headerType);
}
else {
if (StringUtils.hasText(headerElement.getAttribute("type"))) {
@@ -148,22 +148,22 @@ public abstract class HeaderEnricherParserSupport extends AbstractTransformerPar
"The 'type' attribute cannot be used with the 'ref' attribute.", element);
}
if (hasMethod) {
valueHolderBuilder = BeanDefinitionBuilder.genericBeanDefinition(
IntegrationNamespaceUtils.BASE_PACKAGE + ".transformer.HeaderEnricher$MethodExpressionHolder");
valueHolderBuilder.addConstructorArgReference(ref);
valueHolderBuilder.addConstructorArgValue(method);
valueProcessorBuilder = BeanDefinitionBuilder.genericBeanDefinition(
IntegrationNamespaceUtils.BASE_PACKAGE + ".transformer.HeaderEnricher$MethodInvokingHeaderValueMessageProcessor");
valueProcessorBuilder.addConstructorArgReference(ref);
valueProcessorBuilder.addConstructorArgValue(method);
}
else {
valueHolderBuilder = BeanDefinitionBuilder.genericBeanDefinition(
IntegrationNamespaceUtils.BASE_PACKAGE + ".transformer.HeaderEnricher$StaticValueHolder");
valueHolderBuilder.addConstructorArgReference(ref);
valueProcessorBuilder = BeanDefinitionBuilder.genericBeanDefinition(
IntegrationNamespaceUtils.BASE_PACKAGE + ".transformer.HeaderEnricher$StaticHeaderValueMessageProcessor");
valueProcessorBuilder.addConstructorArgReference(ref);
}
}
if (valueHolderBuilder == null) {
if (valueProcessorBuilder == null) {
parserContext.getReaderContext().error("failed to parse header sub-element", headerSource);
}
IntegrationNamespaceUtils.setValueIfAttributeDefined(valueHolderBuilder, headerElement, "overwrite");
headers.put(headerName, valueHolderBuilder.getBeanDefinition());
IntegrationNamespaceUtils.setValueIfAttributeDefined(valueProcessorBuilder, headerElement, "overwrite");
headers.put(headerName, valueProcessorBuilder.getBeanDefinition());
}
}
}

View File

@@ -22,16 +22,9 @@ import java.util.Map;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.context.expression.MapAccessor;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.EvaluationException;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.ParseException;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.integration.core.Message;
import org.springframework.integration.core.MessagingException;
import org.springframework.integration.handler.ExpressionEvaluatingMessageProcessor;
import org.springframework.integration.handler.MessageProcessor;
import org.springframework.integration.handler.MethodInvokingMessageProcessor;
import org.springframework.integration.message.MessageBuilder;
@@ -49,7 +42,7 @@ public class HeaderEnricher implements Transformer {
private static final Log logger = LogFactory.getLog(HeaderEnricher.class);
private final Map<String, ? extends ValueHolder> headersToAdd;
private final Map<String, ? extends HeaderValueMessageProcessor> headersToAdd;
private volatile MessageProcessor messageProcessor;
@@ -65,8 +58,8 @@ public class HeaderEnricher implements Transformer {
/**
* Create a HeaderEnricher with the given map of headers.
*/
public HeaderEnricher(Map<String, ? extends ValueHolder> headersToAdd) {
this.headersToAdd = (headersToAdd != null) ? headersToAdd : new HashMap<String, ValueHolder>();
public HeaderEnricher(Map<String, ? extends HeaderValueMessageProcessor> headersToAdd) {
this.headersToAdd = (headersToAdd != null) ? headersToAdd : new HashMap<String, HeaderValueMessageProcessor>();
}
@@ -91,14 +84,14 @@ public class HeaderEnricher implements Transformer {
try {
Map<String, Object> headerMap = new HashMap<String, Object>(message.getHeaders());
this.addHeadersFromMessageProcessor(message, headerMap);
for (Map.Entry<String, ? extends ValueHolder> entry : this.headersToAdd.entrySet()) {
for (Map.Entry<String, ? extends HeaderValueMessageProcessor> entry : this.headersToAdd.entrySet()) {
String key = entry.getKey();
ValueHolder valueHolder = entry.getValue();
Boolean shouldOverwrite = valueHolder.isOverwrite();
HeaderValueMessageProcessor valueProcessor = entry.getValue();
Boolean shouldOverwrite = valueProcessor.isOverwrite();
if (shouldOverwrite == null) {
shouldOverwrite = this.defaultOverwrite;
}
Object value = valueHolder.evaluate(message);
Object value = valueProcessor.processMessage(message);
if ((value != null && shouldOverwrite) || headerMap.get(key) == null || (value == null && !this.shouldSkipNulls)) {
headerMap.put(key, value);
}
@@ -133,16 +126,15 @@ public class HeaderEnricher implements Transformer {
}
}
public static interface ValueHolder {
Object evaluate(Message<?> message);
public static interface HeaderValueMessageProcessor extends MessageProcessor {
Boolean isOverwrite();
}
static abstract class AbstractValueHolder implements ValueHolder {
static abstract class AbstractHeaderValueMessageProcessor implements HeaderValueMessageProcessor {
// null indicates no explicit setting; use header-enricher's 'default-overwrite' value
private volatile Boolean overwrite = null;
@@ -158,63 +150,52 @@ public class HeaderEnricher implements Transformer {
}
static class StaticValueHolder extends AbstractValueHolder {
static class StaticHeaderValueMessageProcessor extends AbstractHeaderValueMessageProcessor {
private final Object value;
public StaticValueHolder(Object value) {
public StaticHeaderValueMessageProcessor(Object value) {
this.value = value;
}
public Object evaluate(Message<?> message) {
public Object processMessage(Message<?> message) {
return this.value;
}
}
static class ExpressionHolder extends AbstractValueHolder {
private static final ExpressionParser parser = new SpelExpressionParser();
private final Class<?> expectedType;
private final Expression expression;
private final EvaluationContext evaluationContext;
static class ExpressionEvaluatingHeaderValueMessageProcessor extends AbstractHeaderValueMessageProcessor {
private final ExpressionEvaluatingMessageProcessor targetProcessor;
/**
* Create a holder object for the given expression String and the expected type
* Create a header value processor for the given expression String and the expected type
* of the expression evaluation result. The expectedType may be null if unknown.
*/
public ExpressionHolder(String expressionString, Class<?> expectedType) {
this.expectedType = expectedType;
this.expression = parser.parseExpression(expressionString);
StandardEvaluationContext context = new StandardEvaluationContext();
context.addPropertyAccessor(new MapAccessor());
this.evaluationContext = context;
public ExpressionEvaluatingHeaderValueMessageProcessor(String expressionString, Class<?> expectedType) {
this.targetProcessor = new ExpressionEvaluatingMessageProcessor(expressionString);
this.targetProcessor.setExpectedType(expectedType);
}
public Object evaluate(Message<?> message) throws ParseException, EvaluationException {
return (this.expectedType != null)
? this.expression.getValue(this.evaluationContext, message, this.expectedType)
: this.expression.getValue(this.evaluationContext, message);
public Object processMessage(Message<?> message) {
return this.targetProcessor.processMessage(message);
}
}
static class MethodExpressionHolder extends AbstractValueHolder {
static class MethodInvokingHeaderValueMessageProcessor extends AbstractHeaderValueMessageProcessor {
private final MethodInvokingMessageProcessor processor;
private final MethodInvokingMessageProcessor targetProcessor;
public MethodExpressionHolder(Object targetObject, String method) {
this.processor = new MethodInvokingMessageProcessor(targetObject, method);
public MethodInvokingHeaderValueMessageProcessor(Object targetObject, String method) {
this.targetProcessor = new MethodInvokingMessageProcessor(targetObject, method);
}
public Object evaluate(Message<?> message) {
return this.processor.processMessage(message);
public Object processMessage(Message<?> message) {
return this.targetProcessor.processMessage(message);
}
}
}

View File

@@ -44,12 +44,12 @@ public class XPathHeaderEnricher extends HeaderEnricher {
* Create an instance of XPathHeaderEnricher using a map with header names as keys
* and XPathExpressionValueHolders to evaluate the values.
*/
public XPathHeaderEnricher(Map<String, XPathExpressionValueHolder> expressionMap) {
public XPathHeaderEnricher(Map<String, XPathExpressionEvaluatingHeaderValueMessageProcessor> expressionMap) {
super(expressionMap);
}
public static class XPathExpressionValueHolder implements ValueHolder {
public static class XPathExpressionEvaluatingHeaderValueMessageProcessor implements HeaderValueMessageProcessor {
private final XPathExpression expression;
@@ -60,12 +60,12 @@ public class XPathHeaderEnricher extends HeaderEnricher {
private volatile Boolean overwrite = null;
public XPathExpressionValueHolder(String expression) {
public XPathExpressionEvaluatingHeaderValueMessageProcessor(String expression) {
Assert.hasText(expression, "expression must have text");
this.expression = XPathExpressionFactory.createXPathExpression(expression);
}
public XPathExpressionValueHolder(XPathExpression expression) {
public XPathExpressionEvaluatingHeaderValueMessageProcessor(XPathExpression expression) {
Assert.notNull(expression, "expression must not be null");
this.expression = expression;
}
@@ -78,7 +78,11 @@ public class XPathHeaderEnricher extends HeaderEnricher {
this.overwrite = overwrite;
}
public Object evaluate(Message<?> message) {
public Boolean isOverwrite() {
return this.overwrite;
}
public Object processMessage(Message<?> message) {
Node node = converter.convertToNode(message.getPayload());
Object result = this.evaluationType.evaluateXPath(this.expression, node);
if (result instanceof String && ((String) result).length() == 0) {
@@ -86,10 +90,6 @@ public class XPathHeaderEnricher extends HeaderEnricher {
}
return result;
}
public Boolean isOverwrite() {
return this.overwrite;
}
}
}

View File

@@ -28,7 +28,7 @@ import org.junit.Test;
import org.springframework.integration.core.Message;
import org.springframework.integration.core.MessageHeaders;
import org.springframework.integration.message.MessageBuilder;
import org.springframework.integration.xml.enricher.XPathHeaderEnricher.XPathExpressionValueHolder;
import org.springframework.integration.xml.enricher.XPathHeaderEnricher.XPathExpressionEvaluatingHeaderValueMessageProcessor;
import org.springframework.integration.xml.xpath.XPathEvaluationType;
/**
@@ -39,9 +39,10 @@ public class XPathHeaderEnricherTests {
@Test
public void simpleStringEvaluation() {
Map<String, XPathExpressionValueHolder> expressionMap = new HashMap<String, XPathExpressionValueHolder>();
expressionMap.put("one", new XPathExpressionValueHolder("/root/elementOne"));
expressionMap.put("two", new XPathExpressionValueHolder("/root/elementTwo"));
Map<String, XPathExpressionEvaluatingHeaderValueMessageProcessor> expressionMap =
new HashMap<String, XPathExpressionEvaluatingHeaderValueMessageProcessor>();
expressionMap.put("one", new XPathExpressionEvaluatingHeaderValueMessageProcessor("/root/elementOne"));
expressionMap.put("two", new XPathExpressionEvaluatingHeaderValueMessageProcessor("/root/elementTwo"));
String docAsString = "<root><elementOne>1</elementOne><elementTwo>2</elementTwo></root>";
XPathHeaderEnricher enricher = new XPathHeaderEnricher(expressionMap);
Message<?> result = enricher.transform(MessageBuilder.withPayload(docAsString).build());
@@ -52,8 +53,9 @@ public class XPathHeaderEnricherTests {
@Test
public void nullValuesSkippedByDefault() {
Map<String, XPathExpressionValueHolder> expressionMap = new HashMap<String, XPathExpressionValueHolder>();
expressionMap.put("two", new XPathExpressionValueHolder("/root/elementTwo"));
Map<String, XPathExpressionEvaluatingHeaderValueMessageProcessor> expressionMap
= new HashMap<String, XPathExpressionEvaluatingHeaderValueMessageProcessor>();
expressionMap.put("two", new XPathExpressionEvaluatingHeaderValueMessageProcessor("/root/elementTwo"));
String docAsString = "<root><elementOne>1</elementOne></root>";
XPathHeaderEnricher enricher = new XPathHeaderEnricher(expressionMap);
Message<?> result = enricher.transform(MessageBuilder.withPayload(docAsString).build());
@@ -63,8 +65,9 @@ public class XPathHeaderEnricherTests {
@Test
public void notSkippingNullValues() {
Map<String, XPathExpressionValueHolder> expressionMap = new HashMap<String, XPathExpressionValueHolder>();
expressionMap.put("two", new XPathExpressionValueHolder("/root/elementTwo"));
Map<String, XPathExpressionEvaluatingHeaderValueMessageProcessor> expressionMap =
new HashMap<String, XPathExpressionEvaluatingHeaderValueMessageProcessor>();
expressionMap.put("two", new XPathExpressionEvaluatingHeaderValueMessageProcessor("/root/elementTwo"));
String docAsString = "<root><elementOne>1</elementOne></root>";
XPathHeaderEnricher enricher = new XPathHeaderEnricher(expressionMap);
enricher.setShouldSkipNulls(false);
@@ -76,9 +79,12 @@ public class XPathHeaderEnricherTests {
@Test
public void numberEvaluationResult() {
Map<String, XPathExpressionValueHolder> expressionMap = new HashMap<String, XPathExpressionValueHolder>();
XPathExpressionValueHolder expression1 = new XPathExpressionValueHolder("/root/elementOne");
XPathExpressionValueHolder expression2 = new XPathExpressionValueHolder("/root/elementTwo");
Map<String, XPathExpressionEvaluatingHeaderValueMessageProcessor> expressionMap =
new HashMap<String, XPathExpressionEvaluatingHeaderValueMessageProcessor>();
XPathExpressionEvaluatingHeaderValueMessageProcessor expression1 =
new XPathExpressionEvaluatingHeaderValueMessageProcessor("/root/elementOne");
XPathExpressionEvaluatingHeaderValueMessageProcessor expression2 =
new XPathExpressionEvaluatingHeaderValueMessageProcessor("/root/elementTwo");
expression2.setEvaluationType(XPathEvaluationType.NUMBER_RESULT);
expressionMap.put("one", expression1);
expressionMap.put("two", expression2);