Search code examples
javaspringspring-bootspring-integration

Is it possible to use <int:poller> inside <int:router> in spring-integration 5.5.18?


The app I am currently working on was using spring-integration 2.3.0.RELEASE. It has a router configuration that has a poller in it, like below. And it was working fine.

<int:router id="channelRouter" input-channel="exceptionChannel"
        expression="@system.getId(payload)">
    <int:mapping value="0" channel="exceptionChannel0" />
    <int:mapping value="1" channel="exceptionChannel1" />
    <int:poller fixed-rate="10" task-executor="sysExecutor" />
</int:router>

<task:executor id="sysExecutor"
        pool-size="1" queue-capacity="1" rejection-policy="DISCARD" />

But, after upgrading it to spring-integration 5.5.18 a parsing error similar to the following one occurs.

Exception in thread "main" org.springframework.beans.factory.xml.XmlBeanDefinitionStoreException: Line 29 in XML document from class path resource [META-INF/spring/integration/helloWorldDemo.xml] is invalid
    at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.doLoadBeanDefinitions(XmlBeanDefinitionReader.java:411)
    at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:347)
    at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:319)
    at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:184)
    at org.springframework.context.support.AbstractXmlApplicationContext.loadBeanDefinitions(AbstractXmlApplicationContext.java:126)
    at org.springframework.context.support.AbstractXmlApplicationContext.loadBeanDefinitions(AbstractXmlApplicationContext.java:95)
    at org.springframework.context.support.AbstractRefreshableApplicationContext.refreshBeanFactory(AbstractRefreshableApplicationContext.java:130)
    at org.springframework.context.support.AbstractApplicationContext.obtainFreshBeanFactory(AbstractApplicationContext.java:700)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:586)
    at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:202)
    at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:177)
    at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:163)
    at org.springframework.integration.samples.helloworld.HelloWorldApp.main(HelloWorldApp.java:48)
Caused by: org.xml.sax.SAXParseException; lineNumber: 29; columnNumber: 29; cvc-complex-type.2.4.a: Invalid content was found starting with element '{"http://www.springframework.org/schema/integration":poller}'. One of '{"http://www.springframework.org/schema/integration":mapping, WC[##other:"http://www.springframework.org/schema/integration"]}' is expected.
    at java.xml/com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.createSAXParseException(ErrorHandlerWrapper.java:204)
    at java.xml/com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.error(ErrorHandlerWrapper.java:135)
    at java.xml/com.sun.org.apache.xerces.internal.impl.XMLErrorReporter.reportError(XMLErrorReporter.java:396)
    at java.xml/com.sun.org.apache.xerces.internal.impl.XMLErrorReporter.reportError(XMLErrorReporter.java:327)
    at java.xml/com.sun.org.apache.xerces.internal.impl.XMLErrorReporter.reportError(XMLErrorReporter.java:284)
    at java.xml/com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaValidator$XSIErrorReporter.reportError(XMLSchemaValidator.java:512)
    at java.xml/com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaValidator.reportSchemaError(XMLSchemaValidator.java:3600)
    at java.xml/com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaValidator.handleStartElement(XMLSchemaValidator.java:1972)
    at java.xml/com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaValidator.emptyElement(XMLSchemaValidator.java:850)
    at java.xml/com.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl.scanStartElement(XMLNSDocumentScannerImpl.java:351)
    at java.xml/com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl$FragmentContentDriver.next(XMLDocumentFragmentScannerImpl.java:2726)
    at java.xml/com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl.next(XMLDocumentScannerImpl.java:605)
    at java.xml/com.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl.next(XMLNSDocumentScannerImpl.java:112)
    at java.xml/com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanDocument(XMLDocumentFragmentScannerImpl.java:542)
    at java.xml/com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:889)
    at java.xml/com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:825)
    at java.xml/com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(XMLParser.java:141)
    at java.xml/com.sun.org.apache.xerces.internal.parsers.DOMParser.parse(DOMParser.java:247)
    at java.xml/com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderImpl.parse(DocumentBuilderImpl.java:342)
    at org.springframework.beans.factory.xml.DefaultDocumentLoader.loadDocument(DefaultDocumentLoader.java:77)
    at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.doLoadDocument(XmlBeanDefinitionReader.java:441)
    at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.doLoadBeanDefinitions(XmlBeanDefinitionReader.java:399)
    ... 12 more

The log above is taken from a sample app. This error occurs while the app tries to load the XML file using ClassPathXmlApplicationContext.

AbstractApplicationContext context = new ClassPathXmlApplicationContext("/META-INF/spring/integration/helloWorldDemo.xml", HelloWorldApp.class);

Should <int:poller> be removed from <int:router>? If so, then how would the router poll input channel for messages without a poller?


Solution

  • According to current XSD the <poller> has to be declared as first sub-element:

    <xsd:complexType name="routerType">
        <xsd:complexContent>
            <xsd:extension base="commonRouterType">
                <xsd:sequence>
                    <xsd:element ref="poller" minOccurs="0" maxOccurs="1"/>
                    <xsd:group ref="routerCommonGroup"/>
                </xsd:sequence>
                <xsd:attributeGroup ref="topLevelRouterAttributeGroup"/>
            </xsd:extension>
        </xsd:complexContent>
    </xsd:complexType>
    

    Therefore your config should be like this:

    <int:router id="channelRouter" input-channel="exceptionChannel"
            expression="@system.getId(payload)">
        <int:poller fixed-rate="10" task-executor="sysExecutor" />
        <int:mapping value="0" channel="exceptionChannel0" />
        <int:mapping value="1" channel="exceptionChannel1" />
    </int:router>
    

    Note: the poller works only if your exceptionChannel is a QueueChannel.

    Yes, it still may work if you don't declare <poller> over here, but have one top-level which is a default: https://docs.spring.io/spring-integration/reference/endpoint.html#global-default-poller