INT-1270 added support for <header> sub-elements on the <scheduled-producer>
This commit is contained in:
@@ -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 <scheduled-producer> 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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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">
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user