Both "source-endpoint" and "target-endpoint" elements are now configured as <channel-adapter/>. That element requires exactly one of "source" or "target" and optionally accepts a "method" attribute for creating either a MethodInvokingSource or a MethodInvokingTarget (INT-277).
This commit is contained in:
@@ -18,26 +18,38 @@ package org.springframework.integration.config;
|
||||
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.RuntimeBeanReference;
|
||||
import org.springframework.beans.factory.parsing.BeanComponentDefinition;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.support.ManagedList;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.beans.factory.xml.AbstractSimpleBeanDefinitionParser;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.integration.ConfigurationException;
|
||||
import org.springframework.integration.endpoint.SourceEndpoint;
|
||||
import org.springframework.integration.endpoint.TargetEndpoint;
|
||||
import org.springframework.integration.handler.MethodInvokingTarget;
|
||||
import org.springframework.integration.message.MethodInvokingSource;
|
||||
import org.springframework.integration.scheduling.PollingSchedule;
|
||||
import org.springframework.integration.scheduling.Schedule;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.util.xml.DomUtils;
|
||||
|
||||
/**
|
||||
* Parser for the <source-endpoint/> element.
|
||||
* Parser for the <channel-adapter/> element.
|
||||
*
|
||||
* @author Mark Fisher
|
||||
*/
|
||||
public class SourceEndpointParser extends AbstractSimpleBeanDefinitionParser {
|
||||
public class ChannelAdapterParser extends AbstractSimpleBeanDefinitionParser {
|
||||
|
||||
protected final Class<?> getBeanClass(Element element) {
|
||||
return SourceEndpoint.class;
|
||||
boolean hasSource = StringUtils.hasText(element.getAttribute("source"));
|
||||
boolean hasTarget = StringUtils.hasText(element.getAttribute("target"));
|
||||
if (!(hasSource ^ hasTarget)) {
|
||||
throw new ConfigurationException("exactly one of 'source' or 'target' is required");
|
||||
}
|
||||
return hasSource ? SourceEndpoint.class : TargetEndpoint.class;
|
||||
}
|
||||
|
||||
protected boolean shouldGenerateId() {
|
||||
@@ -49,21 +61,31 @@ public class SourceEndpointParser extends AbstractSimpleBeanDefinitionParser {
|
||||
}
|
||||
|
||||
protected boolean isEligibleAttribute(String name) {
|
||||
return (!"source".equals(name) && !"channel".equals(name) && super.isEligibleAttribute(name));
|
||||
return (!"source".equals(name)
|
||||
&& !"target".equals(name)
|
||||
&& !"channel".equals(name)
|
||||
&& super.isEligibleAttribute(name));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
|
||||
String source = element.getAttribute("source");
|
||||
if (!StringUtils.hasText(source)) {
|
||||
throw new ConfigurationException("'source' is required");
|
||||
}
|
||||
String output = element.getAttribute("channel");
|
||||
if (!StringUtils.hasText(output)) {
|
||||
String target = element.getAttribute("target");
|
||||
String channel = element.getAttribute("channel");
|
||||
if (!StringUtils.hasText(channel)) {
|
||||
throw new ConfigurationException("'channel' is required");
|
||||
}
|
||||
builder.addConstructorArgReference(source);
|
||||
builder.addPropertyValue("outputChannelName", output);
|
||||
boolean isSource = StringUtils.hasText(source);
|
||||
if (isSource) {
|
||||
builder.addConstructorArgReference(this.resolveConstructorArgument(
|
||||
source, MethodInvokingSource.class, element, parserContext));
|
||||
builder.addPropertyValue("outputChannelName", channel);
|
||||
}
|
||||
else {
|
||||
builder.addConstructorArgReference(this.resolveConstructorArgument(
|
||||
target, MethodInvokingTarget.class, element, parserContext));
|
||||
builder.addPropertyValue("inputChannelName", channel);
|
||||
}
|
||||
Element scheduleElement = DomUtils.getChildElementByTagName(element, "schedule");
|
||||
if (scheduleElement != null) {
|
||||
builder.addPropertyValue("schedule", this.parseSchedule(scheduleElement));
|
||||
@@ -76,6 +98,19 @@ public class SourceEndpointParser extends AbstractSimpleBeanDefinitionParser {
|
||||
}
|
||||
}
|
||||
|
||||
private String resolveConstructorArgument(String ref, Class<?> targetClass, Element element, ParserContext parserContext) {
|
||||
String method = element.getAttribute("method");
|
||||
if (StringUtils.hasText(method)) {
|
||||
BeanDefinition adapterDef = new RootBeanDefinition(targetClass);
|
||||
adapterDef.getPropertyValues().addPropertyValue("object", new RuntimeBeanReference(ref));
|
||||
adapterDef.getPropertyValues().addPropertyValue("methodName", method);
|
||||
String adapterBeanName = parserContext.getReaderContext().generateBeanName(adapterDef);
|
||||
parserContext.registerBeanComponent(new BeanComponentDefinition(adapterDef, adapterBeanName));
|
||||
return adapterBeanName;
|
||||
}
|
||||
return ref;
|
||||
}
|
||||
|
||||
/**
|
||||
* Subclasses may override this method to control the creation of the {@link Schedule}. The default
|
||||
* implementation creates a {@link PollingSchedule} instance based on the provided "period" attribute.
|
||||
@@ -64,11 +64,8 @@ public class IntegrationNamespaceHandler extends NamespaceHandlerSupport {
|
||||
registerBeanDefinitionParser("priority-channel", new PriorityChannelParser());
|
||||
registerBeanDefinitionParser("rendezvous-channel", new RendezvousChannelParser());
|
||||
registerBeanDefinitionParser("thread-local-channel", new ThreadLocalChannelParser());
|
||||
registerBeanDefinitionParser("source-adapter", new MethodInvokingAdapterParser());
|
||||
registerBeanDefinitionParser("target-adapter", new MethodInvokingAdapterParser());
|
||||
registerBeanDefinitionParser("source-endpoint", new SourceEndpointParser());
|
||||
registerBeanDefinitionParser("handler-endpoint", new HandlerEndpointParser());
|
||||
registerBeanDefinitionParser("target-endpoint", new TargetEndpointParser());
|
||||
registerBeanDefinitionParser("channel-adapter", new ChannelAdapterParser());
|
||||
registerBeanDefinitionParser("gateway", new GatewayParser());
|
||||
registerBeanDefinitionParser("handler", new HandlerParser());
|
||||
registerBeanDefinitionParser("handler-chain", new HandlerParser());
|
||||
|
||||
@@ -168,58 +168,30 @@
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
|
||||
<xsd:element name="source-endpoint">
|
||||
<xsd:element name="channel-adapter">
|
||||
<xsd:complexType>
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
Defines a source endpoint.
|
||||
Defines a Channel Adapter that is capable of either receiving from a MessageSource and sending
|
||||
the result to a MessageChannel or receiving from a MessageChannel and sending the result to a
|
||||
MessageTarget. Therefore, either "source" or "target" should be provided (but never both).
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
<xsd:complexContent>
|
||||
<xsd:extension base="beans:identifiedType">
|
||||
<xsd:sequence>
|
||||
<xsd:element ref="schedule" minOccurs="1" maxOccurs="1"/>
|
||||
<xsd:all>
|
||||
<xsd:element ref="schedule" minOccurs="0" maxOccurs="1"/>
|
||||
<xsd:element name="interceptors" type="interceptorsType" minOccurs="0" maxOccurs="1"/>
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="source" type="xsd:string" use="required"/>
|
||||
</xsd:all>
|
||||
<xsd:attribute name="source" type="xsd:string"/>
|
||||
<xsd:attribute name="target" type="xsd:string"/>
|
||||
<xsd:attribute name="method" type="xsd:string"/>
|
||||
<xsd:attribute name="channel" type="xsd:string" use="required"/>
|
||||
</xsd:extension>
|
||||
</xsd:complexContent>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
|
||||
<xsd:element name="source-adapter" type="methodInvokingAdapterType">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
Defines a MethodInvokingSource.
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:element>
|
||||
|
||||
<xsd:element name="target-endpoint">
|
||||
<xsd:complexType>
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
Defines a target endpoint.
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
<xsd:complexContent>
|
||||
<xsd:extension base="targetEndpointType">
|
||||
<xsd:attribute name="target" type="xsd:string" use="required"/>
|
||||
<xsd:attribute name="method" type="xsd:string"/>
|
||||
</xsd:extension>
|
||||
</xsd:complexContent>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
|
||||
<xsd:element name="target-adapter" type="methodInvokingAdapterType">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
Defines a MethodInvokingTarget.
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:element>
|
||||
|
||||
<xsd:element name="handler-endpoint">
|
||||
<xsd:complexType>
|
||||
<xsd:annotation>
|
||||
@@ -228,10 +200,16 @@
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
<xsd:complexContent>
|
||||
<xsd:extension base="targetEndpointType">
|
||||
<xsd:extension base="beans:identifiedType">
|
||||
<xsd:all>
|
||||
<xsd:element ref="schedule" minOccurs="0" maxOccurs="1"/>
|
||||
<xsd:element name="interceptors" type="interceptorsType" minOccurs="0" maxOccurs="1"/>
|
||||
</xsd:all>
|
||||
<xsd:attribute name="handler" type="xsd:string" use="required"/>
|
||||
<xsd:attribute name="method" type="xsd:string"/>
|
||||
<xsd:attribute name="input-channel" type="xsd:string" use="required"/>
|
||||
<xsd:attribute name="output-channel" type="xsd:string"/>
|
||||
<xsd:attribute name="selector" type="xsd:string"/>
|
||||
<xsd:attribute name="reply-handler" type="xsd:string"/>
|
||||
<xsd:attribute name="return-address-overrides" type="xsd:boolean" default="false"/>
|
||||
</xsd:extension>
|
||||
@@ -417,38 +395,6 @@
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
|
||||
<xsd:complexType name="targetEndpointType">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
Defines common configuration properties of target message endpoints.
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
<xsd:complexContent>
|
||||
<xsd:extension base="beans:identifiedType">
|
||||
<xsd:all>
|
||||
<xsd:element ref="schedule" minOccurs="0" maxOccurs="1"/>
|
||||
<xsd:element name="interceptors" type="interceptorsType" minOccurs="0" maxOccurs="1"/>
|
||||
</xsd:all>
|
||||
<xsd:attribute name="input-channel" type="xsd:string" use="required"/>
|
||||
<xsd:attribute name="selector" type="xsd:string"/>
|
||||
</xsd:extension>
|
||||
</xsd:complexContent>
|
||||
</xsd:complexType>
|
||||
|
||||
<xsd:complexType name="methodInvokingAdapterType">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
Base type for method-invoking adapters.
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
<xsd:complexContent>
|
||||
<xsd:extension base="beans:identifiedType">
|
||||
<xsd:attribute name="ref" type="xsd:string" use="required"/>
|
||||
<xsd:attribute name="method" type="xsd:string" use="required"/>
|
||||
</xsd:extension>
|
||||
</xsd:complexContent>
|
||||
</xsd:complexType>
|
||||
|
||||
<xsd:complexType name="interceptorsType">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
|
||||
@@ -16,20 +16,24 @@
|
||||
|
||||
package org.springframework.integration.channel.config;
|
||||
|
||||
import org.springframework.integration.message.Message;
|
||||
import org.springframework.integration.message.MessageSource;
|
||||
import org.springframework.integration.message.StringMessage;
|
||||
|
||||
/**
|
||||
* @author Mark Fisher
|
||||
*/
|
||||
public class TestSourceBean {
|
||||
public class TestSource implements MessageSource<String> {
|
||||
|
||||
private final String text;
|
||||
|
||||
|
||||
public TestSourceBean(String text) {
|
||||
public TestSource(String text) {
|
||||
this.text = text;
|
||||
}
|
||||
|
||||
public String getText() {
|
||||
return this.text;
|
||||
public Message<String> receive() {
|
||||
return new StringMessage(this.text);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -31,29 +31,29 @@
|
||||
</interceptors>
|
||||
</handler-endpoint>
|
||||
|
||||
<target-endpoint id="targetEndpointWithoutAdvice"
|
||||
input-channel="testChannel"
|
||||
target="testTarget">
|
||||
<channel-adapter id="targetEndpointWithoutAdvice"
|
||||
channel="testChannel"
|
||||
target="testTarget">
|
||||
<schedule period="100"/>
|
||||
</target-endpoint>
|
||||
</channel-adapter>
|
||||
|
||||
<target-endpoint id="targetEndpointWithAdvice"
|
||||
input-channel="testChannel"
|
||||
target="testTarget">
|
||||
<channel-adapter id="targetEndpointWithAdvice"
|
||||
channel="testChannel"
|
||||
target="testTarget">
|
||||
<schedule period="100"/>
|
||||
<interceptors>
|
||||
<ref bean="simpleAdvice"/>
|
||||
<ref bean="interceptor"/>
|
||||
</interceptors>
|
||||
</target-endpoint>
|
||||
</channel-adapter>
|
||||
|
||||
<source-endpoint id="sourceEndpointWithoutAdvice"
|
||||
<channel-adapter id="sourceEndpointWithoutAdvice"
|
||||
source="testSource"
|
||||
channel="replyChannel">
|
||||
<schedule period="100"/>
|
||||
</source-endpoint>
|
||||
</channel-adapter>
|
||||
|
||||
<source-endpoint id="sourceEndpointWithAdvice"
|
||||
<channel-adapter id="sourceEndpointWithAdvice"
|
||||
source="testSource"
|
||||
channel="testChannel">
|
||||
<schedule period="100"/>
|
||||
@@ -61,7 +61,7 @@
|
||||
<ref bean="simpleAdvice"/>
|
||||
<ref bean="interceptor"/>
|
||||
</interceptors>
|
||||
</source-endpoint>
|
||||
</channel-adapter>
|
||||
|
||||
<beans:bean id="testHandler" class="org.springframework.integration.config.TestHandler"/>
|
||||
|
||||
|
||||
@@ -9,11 +9,9 @@
|
||||
|
||||
<direct-channel id="channelWithoutSource"/>
|
||||
|
||||
<direct-channel id="channelWithSource" source="source"/>
|
||||
<direct-channel id="channelWithSource" source="testSource"/>
|
||||
|
||||
<source-adapter id="source" ref="testSourceBean" method="getText"/>
|
||||
|
||||
<beans:bean id="testSourceBean" class="org.springframework.integration.channel.config.TestSourceBean">
|
||||
<beans:bean id="testSource" class="org.springframework.integration.channel.config.TestSource">
|
||||
<beans:constructor-arg value="foo"/>
|
||||
</beans:bean>
|
||||
|
||||
|
||||
@@ -11,13 +11,11 @@
|
||||
|
||||
<si:channel id="channel"/>
|
||||
|
||||
<si:source-endpoint source="sourceAdapter" channel="channel">
|
||||
<si:channel-adapter source="source" method="foo" channel="channel">
|
||||
<si:schedule period="100"/>
|
||||
</si:source-endpoint>
|
||||
</si:channel-adapter>
|
||||
|
||||
<si:target-endpoint target="sink" method="store" input-channel="channel"/>
|
||||
|
||||
<si:source-adapter id="sourceAdapter" ref="source" method="foo"/>
|
||||
<si:channel-adapter target="sink" method="store" channel="channel"/>
|
||||
|
||||
<bean id="source" class="org.springframework.integration.handler.TestSource"/>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user