INT-1881 added support for nesting processing beans in the 'header' element of header-enricher (e.g., bean, script etc.)

This commit is contained in:
Oleg Zhurakousky
2011-04-29 11:38:22 -04:00
parent f10fcc2dd5
commit ccffab2d17
7 changed files with 159 additions and 8 deletions

View File

@@ -17,12 +17,14 @@
package org.springframework.integration.config.xml;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.TypedStringValue;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.ManagedMap;
@@ -35,6 +37,7 @@ import org.springframework.util.xml.DomUtils;
* Base support class for 'header-enricher' parsers.
*
* @author Mark Fisher
* @author Oleg Zhurakousky
* @since 2.0
*/
public abstract class HeaderEnricherParserSupport extends AbstractTransformerParser {
@@ -113,18 +116,36 @@ public abstract class HeaderEnricherParserSupport extends AbstractTransformerPar
String ref = headerElement.getAttribute("ref");
String method = headerElement.getAttribute("method");
String expression = headerElement.getAttribute("expression");
Element expressionElement = DomUtils.getChildElementByTagName(headerElement, "expression");
if (StringUtils.hasText(expression) && expressionElement != null) {
parserContext.getReaderContext().error("The 'expression' attribute and sub-element are mutually exclusive", element);
return;
List<Element> subElements = DomUtils.getChildElements(headerElement);
BeanDefinition innerComponentDefinition = null;
Element expressionElement = null;
if (subElements != null && subElements.size() == 1) {
Element beanElement = subElements.get(0);
if ("expression".equals(beanElement.getNodeName())){
expressionElement = beanElement;
if (StringUtils.hasText(expression) && expressionElement != null) {
parserContext.getReaderContext().error("The 'expression' attribute and sub-element are mutually exclusive", element);
return;
}
}
else if ("bean".equals(beanElement.getNodeName())){
innerComponentDefinition = parserContext.getDelegate().parseBeanDefinitionElement(beanElement).getBeanDefinition();
}
else {
innerComponentDefinition = parserContext.getDelegate().parseCustomElement(beanElement);
}
}
boolean isValue = StringUtils.hasText(value);
boolean isRef = StringUtils.hasText(ref);
boolean hasMethod = StringUtils.hasText(method);
boolean isExpression = StringUtils.hasText(expression) || expressionElement != null;
if (!(isValue ^ (isRef ^ isExpression))) {
boolean isCustomBean = innerComponentDefinition != null;
if (!(isValue ^ (isRef ^ (isExpression ^ isCustomBean)))) {
parserContext.getReaderContext().error(
"Exactly one of the 'ref', 'value', or 'expression' attributes is required.", element);
"Exactly one of the 'ref', 'value', 'expression' or inner bean is required.", element);
}
BeanDefinitionBuilder valueProcessorBuilder = null;
if (isValue) {
@@ -157,6 +178,18 @@ public abstract class HeaderEnricherParserSupport extends AbstractTransformerPar
}
valueProcessorBuilder.addConstructorArgValue(headerType);
}
else if (isCustomBean){
valueProcessorBuilder = BeanDefinitionBuilder.genericBeanDefinition(
IntegrationNamespaceUtils.BASE_PACKAGE + ".transformer.HeaderEnricher$MethodInvokingHeaderValueMessageProcessor");
valueProcessorBuilder.addConstructorArgValue(innerComponentDefinition);
if (hasMethod){
valueProcessorBuilder.addConstructorArgValue(method);
}
else {
valueProcessorBuilder.addConstructorArgValue(null);
}
headers.put(headerName, valueProcessorBuilder.getBeanDefinition());
}
else {
if (StringUtils.hasText(headerElement.getAttribute("type"))) {
parserContext.getReaderContext().error(

View File

@@ -59,6 +59,17 @@ public class HeaderEnricher implements Transformer {
public HeaderEnricher() {
this(null);
}
// public HeaderEnricher(final MessageProcessor<?> messageProcessor) {
// HeaderValueMessageProcessor<?> hvProcessor = new AbstractHeaderValueMessageProcessor<Object>() {
//
// public Object processMessage(Message<?> message) {
// // TODO Auto-generated method stub
// return messageProcessor.processMessage(message);
// }
// };
// //this(hvProcessor);
// }
/**
* Create a HeaderEnricher with the given map of headers.

View File

@@ -1557,9 +1557,10 @@ endpoint itself is a Polling Consumer for a channel with a queue.
</xsd:annotation>
<xsd:complexContent>
<xsd:extension base="referenceHeaderType">
<xsd:sequence minOccurs="0" maxOccurs="1">
<xsd:choice minOccurs="0" maxOccurs="1">
<xsd:any processContents="strict" namespace="##other"/>
<xsd:element name="expression" type="innerExpressionType" />
</xsd:sequence>
</xsd:choice>
<xsd:attribute name="value" type="xsd:string">
<xsd:annotation>
<xsd:documentation>

View File

@@ -49,6 +49,10 @@ public class GroovyScriptParser extends AbstractSingleBeanDefinitionParser {
protected String getBeanClassName(Element element) {
return "org.springframework.integration.groovy.GroovyScriptExecutingMessageProcessor";
}
protected boolean shouldGenerateIdAsFallback() {
return true;
}
@Override
protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {

View File

@@ -0,0 +1,39 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:int="http://www.springframework.org/schema/integration"
xmlns:int-groovy="http://www.springframework.org/schema/integration/groovy"
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
http://www.springframework.org/schema/integration/groovy http://www.springframework.org/schema/integration/groovy/spring-integration-groovy-2.0.xsd">
<int:channel id="inputA"/>
<int:header-enricher input-channel="inputA" output-channel="outputA">
<int:header name="TEST_HEADER">
<int-groovy:script location="org/springframework/integration/groovy/config/GroovyHeaderEnricherTests.groovy"/>
</int:header>
</int:header-enricher>
<int:channel id="outputA">
<int:queue/>
</int:channel>
<int:channel id="inputB"/>
<int:header-enricher input-channel="inputB" output-channel="outputB">
<int:header name="TEST_HEADER">
<int-groovy:script>
<![CDATA[
return "groovy"
]]>
</int-groovy:script>
</int:header>
</int:header-enricher>
<int:channel id="outputB">
<int:queue/>
</int:channel>
</beans>

View File

@@ -0,0 +1,62 @@
/*
* Copyright 2002-2011 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.groovy.config;
import static junit.framework.Assert.assertEquals;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.integration.MessageChannel;
import org.springframework.integration.channel.QueueChannel;
import org.springframework.integration.message.GenericMessage;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
/**
* @author Oleg Zhurakousky
* @since 2.0
*/
@ContextConfiguration
@RunWith(SpringJUnit4ClassRunner.class)
public class GroovyHeaderEnricherTests {
@Autowired
private MessageChannel inputA;
@Autowired
private QueueChannel outputA;
@Autowired
private MessageChannel inputB;
@Autowired
private QueueChannel outputB;
@Test
public void referencedScript() throws Exception{
inputA.send(new GenericMessage<String>("Hello"));
assertEquals("groovy", outputA.receive(1000).getHeaders().get("TEST_HEADER"));
}
@Test
public void inlineScript() throws Exception{
inputB.send(new GenericMessage<String>("Hello"));
assertEquals("groovy", outputB.receive(1000).getHeaders().get("TEST_HEADER"));
}
}