3
votes

I'm trying to reuse Camel routes within the same camelContext using routeContext but I see that there are limitations with the use of onException, intercept, dataFormats as it's stated at How do I import routes from other XML files

The other option is to use many camelContext and vm-direct endpoints for communication between them but there is a limitation of only one camelContext with Spring Boot. On this alternative I have found this article How to configure multiple Camel Contexts in the Spring Boot application.

Is there any other alternative to be able to share routes without having any limitations?

Question related to with Multiple camel context not accepted in Spring Boot Came single configl xml model ?

Added more info:

I want build a full processing workflow in one big route with many small routes where every route has a specific task to do. I prefer XML DSL instead of Java to be able to use the graphic editor.

The main processing workflow will be automatically generated (unmodifiable) and then a development team have to implement only the small routes with specifics tasks. One requisite is I must use Spring Boot.

First try: One Camel context and import routes by routeContext. Using direct endpoint to comunicate routes.

File mainWorkFlow.xml

<!-- Import routerContexts-->
<import resource="tranformationIN_route.xml"/>
<import resource="tranformationOUT_route.xml"/>
<camelContext id="mainWorkFlow">        
    <!-- refer to custom routes -->
    <routeContextRef ref="tranformationIN"/>
    <routeContextRef ref="tranformationOUT"/>
    <route id="main">
        <from id="_inRequest" uri="cxf:bean:exposedWS"/>
        <to id="_validation" uri="inputData.xsd"/>
        <!-- Call route in another context for transformation data received to a backend service data model -->
        <to id="_toTransformationInRoute" uri="direct:appTransformationInRoute"/> 
        <!-- Call backend service -->
        <to id="_wsBE" uri="cxf:bean:backendWS"/>
        <!-- Call route in another context for transformation data from backend service response to exposed service data model -->
        <to id="_toTransformationOutRoute" uri="direct:appTransformationOutRoute"/>
    </route>
</camelContext>

File tranformationIN_route.xml

<routeContext ...>  
    <endpoint id="reqTrans" uri="dozer:...req_transformation.xml"/>
    <!--
        Declare dataFormats used by dozer           
    -->
    <dataFormats>
        <jaxb contextPath="some.package" id="someID"/>
    </dataFormats>
    <route id="tranformationIN">
        <from uri="direct:appTransformationInRoute"/>
        <to id="_to1" uri="ref:reqTrans"/>
    </route>
</routeContext>

File tranformationOUT_route.xml

<routeContext ...>  
    <endpoint id="reqTrans" uri="dozer:...resp_transformation.xml"/>
    <!--
        Declare dataFormats used by dozer           
    -->
    <dataFormats>
        <jaxb contextPath="some.package" id="someID"/>
    </dataFormats>
    <route id="tranformationOUT">
        <from uri="direct:appTransformationOutRoute"/>
        <to id="_to1" uri="ref:respTrans"/>
    </route>
</routeContext>

Look like we can't use dataFormats within routeContext:

    Caused by: org.springframework.beans.factory.xml.XmlBeanDefinitionStoreException: 
    Line 6 in XML document from class path resource [spring/custom-routes.xml] is invalid; 
    nested exception is org.xml.sax.SAXParseException; lineNumber: 6; columnNumber: 22; cvc-complex-type.2.4.a: Se ha encontrado contenido no válido a partir del elemento 'dataFormats'. 
    Se esperaba uno de '{"http://camel.apache.org/schema/spring":route}'...

Second try: Many CamelContext. Using direct-vm endpoint to comunicate routes.

File mainWorkFlow.xml

<camelContext id="mainWorkFlow">
    <route id="main">
        <from id="_inRequest" uri="cxf:bean:exposedWS"/>
        <to id="_validation" uri="inputData.xsd"/>
        <!-- Call route in another context for transformation data received to a backend service data model -->
        <to id="_toTransformationInRoute" uri="direct-vm:appTransformationInRoute"/> 
        <!-- Call backend service -->
        <to id="_wsBE" uri="cxf:bean:backendWS"/>
        <!-- Call route in another context for transformation data from backend service response to exposed service data model -->
        <to id="_toTransformationOutRoute" uri="direct-vm:appTransformationOutRoute"/>
    </route>
</camelContext>

File appContextTranformationIn_context.xml

<camelContext id="appContextTranformationIn">
    <endpoint id="reqTrans" uri="dozer:...req_transformation.xml"/>
    <!--
        Data forman generated automatically by dozer
        If necessary, here I could use dataFormat, onException and interceptor
    -->
     <dataFormats>
        <jaxb contextPath="some.package" id="someID"/>
    </dataFormats>
    <!--  -->
    <route id="tranformationIN">
        <from uri="direct-vm:appTransformationInRoute"/>
        <to id="_to1" uri="ref:reqTrans"/>
    </route>
</camelContext> 

File appContextTranformationOut_context.xml

<camelContext id="appContextTranformationOut">
    <endpoint id="reqTrans" uri="dozer:...resp_transformation.xml"/>
    <!--
        Data forman generated automatically by dozer
        If necessary, here I could use dataFormat, onException and interceptor
    -->
    <dataFormats>
        <jaxb contextPath="some.package" id="someID"/>
    </dataFormats>
    <route id="tranformationOUT">
        <from uri="direct-vm:appTransformationOutRoute"/>
        <to id="_to1" uri="ref:respTrans"/>
    </route>
</camelContext> 

Problems Spring Bootk don't like more than one camelcontext running inside it :/ * Routes tranformationIN (appContextTranformationIn) and tranformationOUT (appContextTranformationOut) would be in one camelContext but the problem with Spring Boot it the same.

1
Do you really need to import these routes into a certain route class? Once they are registered via Spring/Camel you should be able to direct to them via .to(...) or receive via the consumer defined in your route (i.e. direct, seda, ...). Can you explain more why you need to import routes? Do you even use XML configured routes or routes configured via Java directly (recommended as of a couple of Camel versions)Roman Vottner
Thanks for reply!!. I added more info.Ángel

1 Answers

6
votes

You can reuse every route in the Camel Context from every other route. It is just a matter of how your routes are designed.

You can build a full processing workflow in one big route. But if you build a second workflow, it cannot use anything of the first route, it is not reusable at all.

But if you build the same workflow with many small routes where every route has a specific task to do, you can build a second workflow that can use almost every block of the first one.

Typically these small routes look like this:

from(direct:validation)
    .bean(...)
  • The have a direct endpoint to call them easily from every other route (synchronous)
  • They do just one task
  • They have no to() "exit" since they are request/reply and therefore they return to the caller when the route is finished

If you build reusable blocks like this you can call them from every "main" route.

from(...)
    .to("direct:validation")
    .to("direct:transform")
    .to("direct:enrich")
    ...

ADDITION due to more information in question

To your first try: You can't use dataFormat in routeContext. You would have to move it to the camelContext and just reference it from the routeContext.

Snippet from the Camel Docs:

Notice: When you use routeContext then they are separated, and cannot reuse existing onException, intercept, dataFormats and similar cross cutting functionality defined in the camelContext. In other words the routeContext is currently isolated.

To your second try: If you are using Spring Boot, why stick with XML routes? The graphical editor may be nice, but the whole problem you have does not exist with Java routes. Spring Boot is one of the main drivers to move away from Spring XML config to Java config.

And even if you stick with Spring XML config, but write your routes in Java, you would not have the problem. You could easily import all RouteBuilders into the Camel Context.

<camelContext id="camel" xmlns="http://camel.apache.org/schema/spring">
    <routeBuilder ref="myMainRoute" />    
    <routeBuilder ref="mySpecificRoute1" />    
    <routeBuilder ref="mySpecificRoute2" />    
</camelContext>