INT-1130 Added support for 'ref' and 'method' (for Map-returning methods) on the top level <header-enricher/> element.
This commit is contained in:
@@ -66,6 +66,7 @@ public abstract class HeaderEnricherParserSupport extends AbstractTransformerPar
|
||||
this.processHeaders(element, headers, parserContext);
|
||||
builder.addConstructorArgValue(headers);
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "default-overwrite");
|
||||
this.postProcessHeaderEnricher(builder, element, parserContext);
|
||||
}
|
||||
|
||||
protected void processHeaders(Element element, ManagedMap<String, Object> headers, ParserContext parserContext) {
|
||||
@@ -168,4 +169,10 @@ public abstract class HeaderEnricherParserSupport extends AbstractTransformerPar
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Subclasses may override this method to provide any additional processing.
|
||||
*/
|
||||
protected void postProcessHeaderEnricher(BeanDefinitionBuilder builder, Element element, ParserContext parserContext) {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2009 the original author or authors.
|
||||
* Copyright 2002-2010 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.
|
||||
@@ -16,8 +16,13 @@
|
||||
|
||||
package org.springframework.integration.config.xml;
|
||||
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.integration.core.MessageHeaders;
|
||||
import org.springframework.integration.core.MessagePriority;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Parser for the <header-enricher> element within the core integration
|
||||
@@ -38,4 +43,23 @@ public class StandardHeaderEnricherParser extends HeaderEnricherParserSupport {
|
||||
this.addElementToHeaderMapping("priority", MessageHeaders.PRIORITY, MessagePriority.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void postProcessHeaderEnricher(BeanDefinitionBuilder builder, Element element, ParserContext parserContext) {
|
||||
String ref = element.getAttribute("ref");
|
||||
String method = element.getAttribute("method");
|
||||
if (StringUtils.hasText(ref) || StringUtils.hasText(method)) {
|
||||
if (!StringUtils.hasText(ref) || !StringUtils.hasText(method)) {
|
||||
parserContext.getReaderContext().error(
|
||||
"If either 'ref' or 'method' is provided, then they are both required.",
|
||||
parserContext.extractSource(element));
|
||||
return;
|
||||
}
|
||||
BeanDefinitionBuilder processorBuilder = BeanDefinitionBuilder.genericBeanDefinition(
|
||||
IntegrationNamespaceUtils.BASE_PACKAGE + ".handler.MethodInvokingMessageProcessor");
|
||||
processorBuilder.addConstructorArgReference(ref);
|
||||
processorBuilder.addConstructorArgValue(method);
|
||||
builder.addPropertyValue("messageProcessor", processorBuilder.getBeanDefinition());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -19,6 +19,9 @@ package org.springframework.integration.transformer;
|
||||
import java.util.HashMap;
|
||||
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;
|
||||
@@ -29,9 +32,9 @@ 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.MessageProcessor;
|
||||
import org.springframework.integration.handler.MethodInvokingMessageProcessor;
|
||||
import org.springframework.integration.message.MessageBuilder;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* A Transformer that adds statically configured header values to a Message.
|
||||
@@ -43,20 +46,32 @@ import org.springframework.util.Assert;
|
||||
*/
|
||||
public class HeaderEnricher implements Transformer {
|
||||
|
||||
private static final Log logger = LogFactory.getLog(HeaderEnricher.class);
|
||||
|
||||
|
||||
private final Map<String, ValueHolder> headersToAdd;
|
||||
|
||||
private volatile MessageProcessor messageProcessor;
|
||||
|
||||
private volatile boolean defaultOverwrite = false;
|
||||
|
||||
|
||||
public HeaderEnricher() {
|
||||
this(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a HeaderEnricher with the given map of headers.
|
||||
*/
|
||||
public HeaderEnricher(Map<String, ValueHolder> headersToAdd) {
|
||||
Assert.notNull(headersToAdd, "headersToAdd must not be null");
|
||||
this.headersToAdd = headersToAdd;
|
||||
this.headersToAdd = (headersToAdd != null) ? headersToAdd : new HashMap<String, ValueHolder>();
|
||||
}
|
||||
|
||||
|
||||
public void setMessageProcessor(MessageProcessor messageProcessor) {
|
||||
this.messageProcessor = messageProcessor;
|
||||
}
|
||||
|
||||
public void setDefaultOverwrite(boolean defaultOverwrite) {
|
||||
this.defaultOverwrite = defaultOverwrite;
|
||||
}
|
||||
@@ -64,6 +79,7 @@ public class HeaderEnricher implements Transformer {
|
||||
public Message<?> transform(Message<?> message) {
|
||||
try {
|
||||
Map<String, Object> headerMap = new HashMap<String, Object>(message.getHeaders());
|
||||
this.addHeadersFromMessageProcessor(message, headerMap);
|
||||
for (Map.Entry<String, ValueHolder> entry : this.headersToAdd.entrySet()) {
|
||||
String key = entry.getKey();
|
||||
ValueHolder valueHolder = entry.getValue();
|
||||
@@ -82,6 +98,28 @@ public class HeaderEnricher implements Transformer {
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private void addHeadersFromMessageProcessor(Message<?> message, Map<String, Object> headerMap) {
|
||||
if (this.messageProcessor != null) {
|
||||
Object result = this.messageProcessor.processMessage(message);
|
||||
if (result instanceof Map) {
|
||||
Map resultMap = (Map) result;
|
||||
for (Object key : resultMap.keySet()) {
|
||||
if (key instanceof String) {
|
||||
if (this.defaultOverwrite || headerMap.get(key) == null) {
|
||||
headerMap.put((String) key, resultMap.get(key));
|
||||
}
|
||||
}
|
||||
else if (logger.isDebugEnabled()) {
|
||||
logger.debug("ignoring value for non-String key: " + key);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (logger.isDebugEnabled()) {
|
||||
logger.debug("expected a Map result from processor, but received: " + result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static interface ValueHolder {
|
||||
|
||||
|
||||
@@ -1261,6 +1261,28 @@
|
||||
<xsd:union memberTypes="xsd:boolean xsd:string" />
|
||||
</xsd:simpleType>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="ref" type="xsd:string">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
Reference to an Object to be invoked for header values.
|
||||
The 'method' attribute is required along with this.
|
||||
</xsd:documentation>
|
||||
<xsd:appinfo>
|
||||
<tool:annotation kind="ref"/>
|
||||
</xsd:appinfo>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="method" type="xsd:string">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
Method to be invoked on the referenced Object as specified by the
|
||||
'ref' attribute. The method should return a Map with String-typed keys.
|
||||
</xsd:documentation>
|
||||
<xsd:appinfo>
|
||||
<tool:annotation kind="ref"/>
|
||||
</xsd:appinfo>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
</xsd:extension>
|
||||
</xsd:complexContent>
|
||||
</xsd:complexType>
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans:beans xmlns="http://www.springframework.org/schema/integration"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:beans="http://www.springframework.org/schema/beans"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans
|
||||
http://www.springframework.org/schema/beans/spring-beans.xsd
|
||||
http://www.springframework.org/schema/integration
|
||||
http://www.springframework.org/schema/integration/spring-integration.xsd">
|
||||
|
||||
<header-enricher input-channel="input" ref="testBean" method="enrich">
|
||||
<header name="other" value="zzz"/>
|
||||
</header-enricher>
|
||||
|
||||
<beans:bean id="testBean" class="org.springframework.integration.config.xml.HeaderEnricherMethodInvokingTests$TestBean"/>
|
||||
|
||||
</beans:beans>
|
||||
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Copyright 2002-2010 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.integration.config.xml;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.integration.channel.QueueChannel;
|
||||
import org.springframework.integration.core.Message;
|
||||
import org.springframework.integration.core.MessageChannel;
|
||||
import org.springframework.integration.message.MessageBuilder;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
|
||||
/**
|
||||
* @author Mark Fisher
|
||||
* @since 2.0
|
||||
*/
|
||||
@ContextConfiguration
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
public class HeaderEnricherMethodInvokingTests {
|
||||
|
||||
@Autowired
|
||||
private ApplicationContext context;
|
||||
|
||||
|
||||
@Test
|
||||
public void replyChannelExplicitOverwriteTrue() {
|
||||
MessageChannel inputChannel = context.getBean("input", MessageChannel.class);
|
||||
QueueChannel replyChannel = new QueueChannel();
|
||||
Message<?> message = MessageBuilder.withPayload("test").setReplyChannel(replyChannel).build();
|
||||
inputChannel.send(message);
|
||||
Message<?> result = replyChannel.receive(0);
|
||||
assertNotNull(result);
|
||||
assertEquals("test", result.getPayload());
|
||||
assertEquals(replyChannel, result.getHeaders().getReplyChannel());
|
||||
assertEquals(123, result.getHeaders().get("foo"));
|
||||
assertEquals("ABC", result.getHeaders().get("bar"));
|
||||
assertEquals("zzz", result.getHeaders().get("other"));
|
||||
}
|
||||
|
||||
|
||||
public static class TestBean {
|
||||
|
||||
public String echo(String text) {
|
||||
return text.toUpperCase();
|
||||
}
|
||||
|
||||
public Map<String, Object> enrich() {
|
||||
Map<String, Object> headers = new HashMap<String, Object>();
|
||||
headers.put("foo", 123);
|
||||
headers.put("bar", "ABC");
|
||||
return headers;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
* Copyright 2002-2010 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.integration.handler;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.integration.annotation.Payload;
|
||||
import org.springframework.integration.core.Message;
|
||||
import org.springframework.integration.message.MessageBuilder;
|
||||
import org.springframework.integration.transformer.HeaderEnricher;
|
||||
|
||||
/**
|
||||
* @author Mark Fisher
|
||||
* @since 2.0
|
||||
*/
|
||||
public class MethodInvokingHeaderEnricherTests {
|
||||
|
||||
@Test
|
||||
public void emptyHeadersOnRequest() {
|
||||
TestBean testBean = new TestBean();
|
||||
MethodInvokingMessageProcessor processor = new MethodInvokingMessageProcessor(testBean, "process");
|
||||
HeaderEnricher enricher = new HeaderEnricher();
|
||||
enricher.setMessageProcessor(processor);
|
||||
enricher.setDefaultOverwrite(true);
|
||||
Message<?> message = MessageBuilder.withPayload("test").build();
|
||||
Message<?> result = enricher.transform(message);
|
||||
assertEquals("TEST", result.getHeaders().get("foo"));
|
||||
assertEquals("ABC", result.getHeaders().get("bar"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void overwriteFalseByDefault() {
|
||||
TestBean testBean = new TestBean();
|
||||
MethodInvokingMessageProcessor processor = new MethodInvokingMessageProcessor(testBean, "process");
|
||||
HeaderEnricher enricher = new HeaderEnricher();
|
||||
enricher.setMessageProcessor(processor);
|
||||
Message<?> message = MessageBuilder.withPayload("test").setHeader("bar", "XYZ").build();
|
||||
Message<?> result = enricher.transform(message);
|
||||
assertEquals("TEST", result.getHeaders().get("foo"));
|
||||
assertEquals("XYZ", result.getHeaders().get("bar"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void overwriteFalseExplicit() {
|
||||
TestBean testBean = new TestBean();
|
||||
MethodInvokingMessageProcessor processor = new MethodInvokingMessageProcessor(testBean, "process");
|
||||
HeaderEnricher enricher = new HeaderEnricher();
|
||||
enricher.setMessageProcessor(processor);
|
||||
enricher.setDefaultOverwrite(false);
|
||||
Message<?> message = MessageBuilder.withPayload("test").setHeader("bar", "XYZ").build();
|
||||
Message<?> result = enricher.transform(message);
|
||||
assertEquals("TEST", result.getHeaders().get("foo"));
|
||||
assertEquals("XYZ", result.getHeaders().get("bar"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void overwriteTrue() {
|
||||
TestBean testBean = new TestBean();
|
||||
MethodInvokingMessageProcessor processor = new MethodInvokingMessageProcessor(testBean, "process");
|
||||
HeaderEnricher enricher = new HeaderEnricher();
|
||||
enricher.setMessageProcessor(processor);
|
||||
enricher.setDefaultOverwrite(true);
|
||||
Message<?> message = MessageBuilder.withPayload("test").setHeader("bar", "XYZ").build();
|
||||
Message<?> result = enricher.transform(message);
|
||||
assertEquals("TEST", result.getHeaders().get("foo"));
|
||||
assertEquals("ABC", result.getHeaders().get("bar"));
|
||||
}
|
||||
|
||||
|
||||
public static class TestBean {
|
||||
|
||||
public Map<String, Object> process(@Payload("toUpperCase()") String s) {
|
||||
Map<String, Object> map = new HashMap<String, Object>();
|
||||
map.put("foo", s);
|
||||
map.put("bar", "ABC");
|
||||
return map;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user