Added the 'header-enricher' element to the core namespace (INT-489).
This commit is contained in:
@@ -105,6 +105,7 @@ public class IntegrationNamespaceHandler implements NamespaceHandler {
|
||||
registerBeanDefinitionParser("splitter", new SplitterParser());
|
||||
registerBeanDefinitionParser("aggregator", new AggregatorParser());
|
||||
registerBeanDefinitionParser("resequencer", new ResequencerParser());
|
||||
registerBeanDefinitionParser("header-enricher", new StandardHeaderEnricherParser());
|
||||
registerBeanDefinitionParser("inbound-channel-adapter", new MethodInvokingInboundChannelAdapterParser());
|
||||
registerBeanDefinitionParser("outbound-channel-adapter", new MethodInvokingOutboundChannelAdapterParser());
|
||||
registerBeanDefinitionParser("gateway", new GatewayParser());
|
||||
|
||||
@@ -84,20 +84,18 @@ public class SimpleHeaderEnricherParser extends AbstractTransformerParser {
|
||||
Node node = attributes.item(i);
|
||||
String name = node.getNodeName();
|
||||
if (this.isEligibleHeaderName(name)) {
|
||||
if (this.referenceAttributes.contains(name)) {
|
||||
headers.put(name, new RuntimeBeanReference(node.getNodeValue()));
|
||||
}
|
||||
else {
|
||||
headers.put(name, node.getNodeValue());
|
||||
Object value = (this.referenceAttributes.contains(name))
|
||||
? new RuntimeBeanReference(node.getNodeValue())
|
||||
: node.getNodeValue();
|
||||
if (this.prefix != null) {
|
||||
name = this.prefix + name;
|
||||
}
|
||||
headers.put(name, value);
|
||||
}
|
||||
}
|
||||
this.postProcessHeaders(element, headers);
|
||||
builder.addConstructorArgValue(headers);
|
||||
builder.addPropertyValue("overwrite", this.shouldOverwrite(element));
|
||||
if (this.prefix != null) {
|
||||
builder.addPropertyValue("prefix", this.prefix);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright 2002-2008 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 org.w3c.dom.Element;
|
||||
import org.w3c.dom.Node;
|
||||
import org.w3c.dom.NodeList;
|
||||
|
||||
import org.springframework.beans.factory.config.RuntimeBeanReference;
|
||||
import org.springframework.beans.factory.support.ManagedMap;
|
||||
import org.springframework.integration.core.MessageHeaders;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Parser for the <header-enricher> element within the core integration
|
||||
* namespace. This is used for setting the <em>standard</em>, out-of-the-box
|
||||
* configurable {@link MessageHeaders}, such as 'reply-channel', 'priority',
|
||||
* and 'correlation-id'. It will also accept custom header values (or bean
|
||||
* references) if provided as 'header' sub-elements.
|
||||
*
|
||||
* @author Mark Fisher
|
||||
*/
|
||||
public class StandardHeaderEnricherParser extends SimpleHeaderEnricherParser {
|
||||
|
||||
private static final String[] REFERENCE_ATTRIBUTES = new String[] {
|
||||
"reply-channel", "error-channel"
|
||||
};
|
||||
|
||||
|
||||
public StandardHeaderEnricherParser() {
|
||||
super(MessageHeaders.PREFIX, REFERENCE_ATTRIBUTES);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
protected void postProcessHeaders(Element element, ManagedMap headers) {
|
||||
NodeList childNodes = element.getChildNodes();
|
||||
for (int i = 0; i < childNodes.getLength(); i++) {
|
||||
Node node = childNodes.item(i);
|
||||
if (node.getNodeType() == Node.ELEMENT_NODE && node.getLocalName().equals("header")) {
|
||||
Element headerElement = (Element) node;
|
||||
String name = headerElement.getAttribute("name");
|
||||
String value = headerElement.getAttribute("value");
|
||||
String ref = headerElement.getAttribute("ref");
|
||||
boolean isValue = StringUtils.hasText(value);
|
||||
boolean isRef = StringUtils.hasText(ref);
|
||||
Assert.isTrue(isValue ^ isRef, "Exactly one of the 'value' or 'ref' attributes is required.");
|
||||
if (isValue) {
|
||||
headers.put(name, value);
|
||||
}
|
||||
else {
|
||||
headers.put(name, new RuntimeBeanReference(ref));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -266,6 +266,14 @@
|
||||
</xsd:complexContent>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="header-enricher">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="header" type="headerElementType" minOccurs="0" maxOccurs="unbounded"/>
|
||||
</xsd:sequence>
|
||||
<xsd:attributeGroup ref="headerEnricherAttributes"/>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="transformer" type="handlerType"/>
|
||||
<xsd:element name="service-activator" type="handlerType"/>
|
||||
<xsd:element name="splitter" type="handlerType"/>
|
||||
@@ -387,6 +395,48 @@
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
|
||||
<xsd:element name="header-enricher">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
Defines a HeaderEnricher endpoint for values defined in the MessageHeaders.
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
<xsd:complexType>
|
||||
<xsd:complexContent>
|
||||
<xsd:extension base="inputOutputEndpointType">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="header" type="headerElementType" minOccurs="0" maxOccurs="unbounded"/>
|
||||
</xsd:sequence>
|
||||
<xsd:attributeGroup ref="headerEnricherAttributes"/>
|
||||
</xsd:extension>
|
||||
</xsd:complexContent>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
|
||||
<xsd:complexType name="headerElementType">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
Defines a Message Header value or ref.
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required"/>
|
||||
<xsd:attribute name="ref" type="xsd:string"/>
|
||||
<xsd:attribute name="value" type="xsd:string"/>
|
||||
</xsd:complexType>
|
||||
|
||||
<xsd:attributeGroup name="headerEnricherAttributes">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
Provides the names of the standard configurable MessageHeaders.
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
<xsd:attribute name="reply-channel" type="xsd:string"/>
|
||||
<xsd:attribute name="error-channel" type="xsd:string"/>
|
||||
<xsd:attribute name="correlation-id" type="xsd:string"/>
|
||||
<xsd:attribute name="expiration-date" type="xsd:string"/>
|
||||
<xsd:attribute name="priority" type="xsd:string"/>
|
||||
</xsd:attributeGroup>
|
||||
|
||||
<xsd:element name="thread-pool-task-executor">
|
||||
<xsd:complexType>
|
||||
<xsd:annotation>
|
||||
|
||||
@@ -22,8 +22,8 @@ import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* A Transformer that adds statically configured header values to a Message.
|
||||
* Accepts an optional 'prefix' String and a boolean that specifies whether
|
||||
* values should be overwritten. By default, any existing header values for
|
||||
* Accepts the boolean 'overwrite' property that specifies whether values
|
||||
* should be overwritten. By default, any existing header values for
|
||||
* a given key, will <em>not</em> be replaced.
|
||||
*
|
||||
* @author Mark Fisher
|
||||
@@ -34,8 +34,6 @@ public class HeaderEnricher extends AbstractHeaderTransformer {
|
||||
|
||||
private volatile boolean overwrite;
|
||||
|
||||
private volatile String prefix;
|
||||
|
||||
|
||||
/**
|
||||
* Create a HeaderEnricher with the given map of headers.
|
||||
@@ -50,17 +48,10 @@ public class HeaderEnricher extends AbstractHeaderTransformer {
|
||||
this.overwrite = overwrite;
|
||||
}
|
||||
|
||||
public void setPrefix(String prefix) {
|
||||
this.prefix = prefix;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected final void transformHeaders(Map<String, Object> headers) {
|
||||
for (Map.Entry<String, Object> entry : this.headersToAdd.entrySet()) {
|
||||
String key = entry.getKey();
|
||||
if (this.prefix != null) {
|
||||
key = this.prefix + key;
|
||||
}
|
||||
if (this.overwrite || headers.get(key) == null) {
|
||||
headers.put(key, entry.getValue());
|
||||
}
|
||||
|
||||
@@ -7,17 +7,33 @@
|
||||
http://www.springframework.org/schema/integration
|
||||
http://www.springframework.org/schema/integration/spring-integration-1.0.xsd">
|
||||
|
||||
<channel id="input"/>
|
||||
<channel id="filterInput"/>
|
||||
|
||||
<channel id="output">
|
||||
<queue/>
|
||||
</channel>
|
||||
|
||||
<chain input-channel="input" output-channel="output">
|
||||
<channel id="replyOutput">
|
||||
<queue/>
|
||||
</channel>
|
||||
|
||||
<chain input-channel="filterInput" output-channel="output">
|
||||
<filter ref="typeSelector"/>
|
||||
<service-activator ref="testHandler"/>
|
||||
</chain>
|
||||
|
||||
<chain input-channel="headerEnricherInput">
|
||||
<header-enricher reply-channel="replyOutput" correlation-id="ABC">
|
||||
<header name="testValue" value="XYZ"/>
|
||||
<header name="testRef" ref="testHeaderValue"/>
|
||||
</header-enricher>
|
||||
<service-activator ref="testHandler"/>
|
||||
</chain>
|
||||
|
||||
<beans:bean id="testHeaderValue" class="java.lang.Integer">
|
||||
<beans:constructor-arg value="123"/>
|
||||
</beans:bean>
|
||||
|
||||
<beans:bean id="typeSelector" class="org.springframework.integration.selector.PayloadTypeSelector">
|
||||
<beans:constructor-arg value="java.lang.String"/>
|
||||
</beans:bean>
|
||||
|
||||
@@ -38,19 +38,27 @@ import org.springframework.test.context.junit4.AbstractJUnit4SpringContextTests;
|
||||
public class ChainParserTests extends AbstractJUnit4SpringContextTests {
|
||||
|
||||
@Autowired
|
||||
@Qualifier("input")
|
||||
private MessageChannel inputChannel;
|
||||
@Qualifier("filterInput")
|
||||
private MessageChannel filterInput;
|
||||
|
||||
@Autowired
|
||||
@Qualifier("headerEnricherInput")
|
||||
private MessageChannel headerEnricherInput;
|
||||
|
||||
@Autowired
|
||||
@Qualifier("output")
|
||||
private PollableChannel outputChannel;
|
||||
private PollableChannel output;
|
||||
|
||||
@Autowired
|
||||
@Qualifier("replyOutput")
|
||||
private PollableChannel replyOutput;
|
||||
|
||||
|
||||
@Test
|
||||
public void testChainWithAcceptingFilter() {
|
||||
public void chainWithAcceptingFilter() {
|
||||
Message<?> message = MessageBuilder.withPayload("test").build();
|
||||
this.inputChannel.send(message);
|
||||
Message<?> reply = this.outputChannel.receive(0);
|
||||
this.filterInput.send(message);
|
||||
Message<?> reply = this.output.receive(0);
|
||||
assertNotNull(reply);
|
||||
assertEquals("foo", reply.getPayload());
|
||||
}
|
||||
@@ -58,9 +66,21 @@ public class ChainParserTests extends AbstractJUnit4SpringContextTests {
|
||||
@Test
|
||||
public void chainWithRejectingFilter() {
|
||||
Message<?> message = MessageBuilder.withPayload(123).build();
|
||||
this.inputChannel.send(message);
|
||||
Message<?> reply = this.outputChannel.receive(0);
|
||||
this.filterInput.send(message);
|
||||
Message<?> reply = this.output.receive(0);
|
||||
assertNull(reply);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void chainWithHeaderEnricher() {
|
||||
Message<?> message = MessageBuilder.withPayload(123).build();
|
||||
this.headerEnricherInput.send(message);
|
||||
Message<?> reply = this.replyOutput.receive(0);
|
||||
assertNotNull(reply);
|
||||
assertEquals("foo", reply.getPayload());
|
||||
assertEquals("ABC", reply.getHeaders().getCorrelationId());
|
||||
assertEquals("XYZ", reply.getHeaders().get("testValue"));
|
||||
assertEquals(123, reply.getHeaders().get("testRef"));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user