INT-1270 added support for <header> sub-elements on the <scheduled-producer>

This commit is contained in:
Mark Fisher
2010-08-17 17:32:18 +00:00
parent 035d0c01b0
commit 10704c94c5
6 changed files with 107 additions and 37 deletions

View File

@@ -16,13 +16,18 @@
package org.springframework.integration.config.xml;
import java.util.List;
import org.w3c.dom.Element;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.ManagedMap;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.util.xml.DomUtils;
/**
* Parser for the &lt;scheduled-producer&gt; element.
@@ -83,7 +88,35 @@ public class ScheduledProducerParser extends AbstractSingleBeanDefinitionParser
builder.addPropertyReference("outputChannel", element.getAttribute("channel"));
builder.addConstructorArgValue(element.getAttribute("payload-expression"));
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "auto-startup");
// TODO: add support for header expression sub-elements
List<Element> headerElements = DomUtils.getChildElementsByTagName(element, "header");
if (!CollectionUtils.isEmpty(headerElements)) {
ManagedMap<String, Object> headerExpressions = new ManagedMap<String, Object>();
for (Element headerElement : headerElements) {
String headerName = headerElement.getAttribute("name");
String headerValue = headerElement.getAttribute("value");
String headerExpression = headerElement.getAttribute("expression");
boolean hasValue = StringUtils.hasText(headerValue);
boolean hasExpression = StringUtils.hasText(headerExpression);
if (!(hasValue ^ hasExpression)) {
parserContext.getReaderContext().error("exactly one of 'value' or 'expression' is required on a header sub-element",
parserContext.extractSource(headerElement));
continue;
}
RootBeanDefinition expressionDef = null;
if (hasValue) {
expressionDef = new RootBeanDefinition("org.springframework.expression.common.LiteralExpression");
expressionDef.getConstructorArgumentValues().addGenericArgumentValue(headerValue);
}
else if (hasExpression) {
expressionDef = new RootBeanDefinition("org.springframework.integration.config.ExpressionFactoryBean");
expressionDef.getConstructorArgumentValues().addGenericArgumentValue(headerExpression);
}
if (expressionDef != null) {
headerExpressions.put(headerName, expressionDef);
}
}
builder.addPropertyValue("headerExpressions", headerExpressions);
}
}
}

View File

@@ -46,7 +46,7 @@ public class ScheduledMessageProducer extends MessageProducerSupport {
private volatile ScheduledFuture<?> future;
private volatile Map<String, Expression> headerExpressionMap;
private final Map<String, Expression> headerExpressions = new HashMap<String, Expression>();
private final StandardEvaluationContext context = new StandardEvaluationContext();
@@ -59,22 +59,19 @@ public class ScheduledMessageProducer extends MessageProducerSupport {
}
public void setHeaderExpressions(Map<String, String> headerExpressions) {
if (headerExpressions != null) {
Map<String, Expression> parsedExpressions = new HashMap<String, Expression>();
for (Map.Entry<String, String> entry : headerExpressions.entrySet()) {
parsedExpressions.put(entry.getKey(), PARSER.parseExpression(entry.getValue()));
public void setHeaderExpressions(Map<String, Expression> headerExpressions) {
synchronized (this.headerExpressions) {
this.headerExpressions.clear();
if (headerExpressions != null) {
this.headerExpressions.putAll(headerExpressions);
}
this.headerExpressionMap = parsedExpressions;
}
}
private Map<String, Object> evaluateHeaders() {
Map<String, Object> headers = new HashMap<String, Object>();
if (this.headerExpressionMap != null) {
for (Map.Entry<String, Expression> entry : this.headerExpressionMap.entrySet()) {
headers.put(entry.getKey(), entry.getValue().getValue(context));
}
for (Map.Entry<String, Expression> entry : this.headerExpressions.entrySet()) {
headers.put(entry.getKey(), entry.getValue().getValue(context));
}
return headers;
}
@@ -106,7 +103,7 @@ public class ScheduledMessageProducer extends MessageProducerSupport {
private final Expression payloadExpression;
private MessageProducingTask(Expression payloadExpression) {
private MessageProducingTask(Expression payloadExpression) {//, Map<String, Expression> headerExpressions) {
this.payloadExpression = payloadExpression;
}

View File

@@ -428,7 +428,7 @@
</xsd:annotation>
<xsd:complexType>
<xsd:sequence>
<xsd:element name="header" minOccurs="0" maxOccurs="unbounded">
<xsd:element name="header" minOccurs="0" maxOccurs="unbounded" type="headerSubElementType">
<xsd:annotation>
<xsd:documentation>
<![CDATA[
@@ -437,26 +437,6 @@
]]>
</xsd:documentation>
</xsd:annotation>
<xsd:complexType>
<xsd:attribute name="name" type="xsd:string" use="required">
<xsd:annotation>
<xsd:documentation>
<![CDATA[
The name of the header
]]>
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="value" type="xsd:string" use="required">
<xsd:annotation>
<xsd:documentation>
<![CDATA[
The value of the header
]]>
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
</xsd:complexType>
</xsd:element>
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string">
@@ -607,6 +587,37 @@
</xsd:complexType>
</xsd:element>
<xsd:complexType name="headerSubElementType">
<xsd:annotation>
<xsd:documentation> <![CDATA[
Provides mechanism to enrich content of the message with custom message headers. When this method is going to be invoked
the generated message will be enriched with these headers.
]]></xsd:documentation>
</xsd:annotation>
<xsd:attribute name="name" type="xsd:string" use="required">
<xsd:annotation>
<xsd:documentation><![CDATA[
The name of the header
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="value" type="xsd:string">
<xsd:annotation>
<xsd:documentation><![CDATA[
The value of the header. Either this or 'expression' must be provided.
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="expression" type="xsd:string">
<xsd:annotation>
<xsd:documentation><![CDATA[
Expression to be evaluated to produce a value for the header.
Either this or 'value' must be provided.
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
</xsd:complexType>
<xsd:complexType name="innerGatewayType">
<xsd:annotation>
<xsd:documentation>
@@ -2227,6 +2238,9 @@ Name of the header whose value to use.
</xsd:documentation>
</xsd:annotation>
<xsd:complexType>
<xsd:sequence>
<xsd:element name="header" type="headerSubElementType" minOccurs="0" maxOccurs="unbounded"/>
</xsd:sequence>
<xsd:attribute name="id" type="xsd:ID"/>
<xsd:attribute name="fixed-delay" type="xsd:string">
<xsd:annotation>

View File

@@ -13,6 +13,8 @@
<channel id="cronChannel"/>
<channel id="headerExpressionsChannel"/>
<channel id="triggerRefChannel">
<queue/>
</channel>
@@ -23,6 +25,11 @@
<scheduled-producer id="cronProducer" cron="7 6 5 4 3 ?" payload-expression="'cronTest'" channel="cronChannel" auto-startup="false"/>
<scheduled-producer id="headerExpressionsProducer" fixed-delay="99" payload-expression="'headerExpressionsTest'" channel="headerExpressionsChannel" auto-startup="false">
<header name="foo" expression="6 * 7"/>
<header name="bar" value="x"/>
</scheduled-producer>
<scheduled-producer id="triggerRefProducer" trigger="customTrigger" payload-expression="'triggerRefTest'" channel="triggerRefChannel"/>
<beans:bean id="customTrigger" class="org.springframework.scheduling.support.PeriodicTrigger">

View File

@@ -20,6 +20,8 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import java.util.Map;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -106,4 +108,18 @@ public class ScheduledProducerParserTests {
assertEquals("'triggerRefTest'", payloadExpression.getExpressionString());
}
@Test
@SuppressWarnings("unchecked")
public void headerExpressions() {
ScheduledMessageProducer producer = context.getBean("headerExpressionsProducer", ScheduledMessageProducer.class);
assertFalse(producer.isAutoStartup());
DirectFieldAccessor producerAccessor = new DirectFieldAccessor(producer);
Map<String, Expression> headerExpressions = (Map<String, Expression>) producerAccessor.getPropertyValue("headerExpressions");
assertEquals(2, headerExpressions.size());
assertEquals("6 * 7", headerExpressions.get("foo").getExpressionString());
assertEquals("x", headerExpressions.get("bar").getExpressionString());
assertEquals(42, headerExpressions.get("foo").getValue());
assertEquals("x", headerExpressions.get("bar").getValue());
}
}

View File

@@ -26,6 +26,9 @@ import java.util.concurrent.atomic.AtomicInteger;
import org.junit.Test;
import org.springframework.expression.Expression;
import org.springframework.expression.common.LiteralExpression;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.integration.Message;
import org.springframework.integration.channel.QueueChannel;
import org.springframework.scheduling.Trigger;
@@ -48,9 +51,9 @@ public class ScheduledMessageProducerTests {
String payloadExpression = "'test-' + T(org.springframework.integration.endpoint.ScheduledMessageProducerTests).next()";
ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
scheduler.afterPropertiesSet();
Map<String, String> headerExpressions = new HashMap<String, String>();
headerExpressions.put("foo", "'x'");
headerExpressions.put("bar", "7 * 6");
Map<String, Expression> headerExpressions = new HashMap<String, Expression>();
headerExpressions.put("foo", new LiteralExpression("x"));
headerExpressions.put("bar", new SpelExpressionParser().parseExpression("7 * 6"));
ScheduledMessageProducer producer = new ScheduledMessageProducer(trigger, payloadExpression);
producer.setHeaderExpressions(headerExpressions);
producer.setTaskScheduler(scheduler);