Enterprise Integration Zone is brought to you in partnership with:

Java architect with UST Global Biju has posted 5 posts at DZone. View Full User Profile

Spring Integration and Apache Camel

12.31.2009
| 65460 views |
  • submit to reddit

 

Solution using Apache Camel:

Apache Camel allows the route to be defined using multiple DSL implementations – Java DSL, Scala DSL and an XML based DSL. The recommended approach is to use Spring CamelContext as a runtime and the Java DSL for route development. The following is to build the Spring Camel Context:

<camelContext id="camel" xmlns="http://camel.apache.org/schema/spring">
<template id="camelTemplate" />
<routeBuilder ref="routeBuilder"/>
</camelContext>


The route is configured by the Java based DSL:
public class CamelRouteBuilder extends RouteBuilder {
private String serviceURL;

@Override
public void configure() throws Exception {

from("direct:start")
.split().method("sectionRequestSplitterBean", "split")
.aggregationStrategy(new ReportAggregationStrategy())
.transform().method("sectionRequestToXMLBean", "transform")
.to(serviceURL)
.transform().method("sectionResponseXMLToSectionBean", "transform");
}

public void setServiceURL(String serviceURL) {
this.serviceURL = serviceURL;
}
}

Apache Camel does not provide an out of the box Message Gateway feature, however it is fairly easy to create a wrapper component that can hide the underlying details in the following way:

Reader davsclaus has provided references to two mechanisms with Apache Camel to provide an out of the box Messaging Gateway - Messaging Gateway EIP and Camel Proxy which allows a POJO to be used as a Mesaging Gateway. 

Camel Proxy will be used with the article, and can be configured in the Camel Configuration files in the following way:

	<camelContext id="camel" xmlns="http://camel.apache.org/schema/spring">

		<proxy id="consumerMessageGateway" serviceInterface="org.bk.report.ReportGenerator"
			serviceUrl="direct:start" />

		<template id="camelTemplate" />
		<routeBuilder ref="routeBuilder" />
	</camelContext>

Per davsclaus, there is a bug in Apache Camel(2.1 or older) when invoking a bean later in the route(the splitter bean), which is to be fixed in Apache Camel 2.2. To work around this bug, a convertBody step will be introduced in the route:

        from("direct:start")
.convertBodyTo(ReportRequest.class)
.split(bean("sectionRequestSplitterBean", "split"), new ReportAggregationStrategy())
.transform().method("sectionRequestToXMLBean", "transform")
.to(serviceURL)
.transform().method("sectionResponseXMLToSectionBean", "transform");

 

The component to Split the Input Report Request to Section Request is exactly same as Spring Integration component:

public class SectionRequestSplitter {

public List<SectionRequest> split(ReportRequest reportRequest){
return reportRequest.getSectionRequests();
}

}
To hook the component with Apache Camel:
<bean id="sectionRequestSplitterBean" class="org.bk.report.si.SectionRequestSplitter" />

from("direct:start")
.split().method("sectionRequestSplitterBean", "split")
....
Next to transform the Section Request to an XML format, again this is exactly same as the implementation for Spring Integration, with hook being provided in the following manner:
......
.transform().method("sectionRequestToXMLBean", "transform")
......
To send an XML over http request using the Section Request XML to a section Service:
......
.transform().method("sectionRequestToXMLBean", "transform")
.to(serviceURL)
.........
To transform the Section Response XML to a Section object, the component is exactly same as the one used with Spring Integration, with the following highlighted hook in the Camel route:
......
.transform().method("sectionResponseXMLToSectionBean", "transform");

To aggregate the Section responses together into a report, the component is a bit more complicated than Spring Integration. Apache Camel supports a Scatter/Gather pattern using a route of the following type:
......
.split().method("sectionRequestSplitterBean", "split")
.aggregationStrategy(new ReportAggregationStrategy())
with an aggregation strategy being passed on to the Splitter, the aggregation strategy implementation is the following:
public class ReportAggregationStrategy implements AggregationStrategy {
@Override
public Exchange aggregate(Exchange oldExchange, Exchange newExchange) {
if (oldExchange == null) {
Section section = newExchange.getIn().getBody(Section.class);
Report report = new Report();
report.addSection(section);
newExchange.getIn().setBody(report);
return newExchange;
}

Report report = oldExchange.getIn().getBody(Report.class);
Section section = newExchange.getIn().getBody(Section.class);
report.addSection(section);
oldExchange.getIn().setBody(report);
return oldExchange;

}
}
This completes the Apache Camel based implementation. A working sample for Camel is provided with the article - just download, extract and run "mvn test".


Conclusion:

Spring Integration and Apache Camel provide a simple and clean approach for the Integration problems in a typical enterprise. They are lightweight frameworks – Spring Integration builds on top of Spring portfolio and extends the familiar programming model for the Integration domain and is easy to pick up, Apache camel provides a good Java based DSL and integrates well with Spring Core, with a fairly gentle learning curve. The article does not recommend one product over the other but encourages the reader to evaluate and learn from both these frameworks.


References:

Spring Integration Website: http://www.springsource.org/spring-integration
Apache Camel Website: http://camel.apache.org/
Spring Integration Reference: http://static.springsource.org/spring-integration/reference/htmlsingle/spring-integration-reference.html
Apache Camel User Guide: http://camel.apache.org/user-guide.html
Plug for my blog: http://biju-allandsundry.blogspot.com/
Legacy
Published at DZone with permission of its author, Biju Kunjummen.

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)

Comments

Stefan Krause replied on Fri, 2010/01/01 - 1:11pm

Thanks for the nice article. Do you know if either of the aggregators supports persistent messages? Considering the much touted delivery guarantee for messaging systems this would look like a very basic requirement.

Claus Ibsen replied on Sun, 2010/01/03 - 7:46am

@Stefan Camel does currently not provide a persistent store for the Aggregator EIP. Its on the roadmap though, for Camel 2.3: CAMEL-217. We have planned an overhaul of the Aggregator EIP which should also make it easier to use out of the box. For example the need to use the low level AggregationStrategy with a POJO of some sort is also desired.

Some design ideas was sketched here: overhaul of Aggregator.

You can however currently create your own persistent capable implementation of org.apache.camel.processor.aggregate.AggregationCollection and use your implementation in the Aggregator EIP. Some end users have done that.

Claus Ibsen replied on Sun, 2010/01/03 - 8:02am

Comments for page 3:
Camel do support Messaging Gateway EIP which is documented here. The documentation do need to be improved with some better samples.

In your case you can for example use the @Produce annotation to inject a messaging gateway to easily send in the message to Camel.

This makes the code nice, simple and easy as shown below:

public class CamelReportGenerator implements ReportGenerator {

    @Produce(uri = "direct:start")
    private ReportGenerator generator;

    public Report generateReport(ReportRequest reportRequest) {
        return generator.generateReport(reportRequest);
    }

}


However there is an issue in Camel (v2.1 or older) when invoking a bean later in the route which you do when calling the bean method in the splitter EIP. To prevent this problem you need to add to use the convertBodyTo as shown below:

	@Override
	public void configure() throws Exception {
            from("direct:start")
            .convertBodyTo(ReportRequest.class)
            .split(bean("sectionRequestSplitterBean", "split"), new ReportAggregationStrategy())
    		    .transform().method("sectionRequestToXMLBean", "transform")
	    	    .to(serviceURL)
	            .transform().method("sectionResponseXMLToSectionBean", "transform")
            .end();
	}

This will be fixed in Camel 2.2 ticket CAMEL-2325.

Instead of using @Produce you can use the CamelProxy which allows you to proxy a POJO and use that POJO as the messaging gateway. You can define the proxy in the Spring XML directly as shown in the documentation.

Biju Kunjummen replied on Sun, 2010/01/03 - 9:01am in response to: Claus Ibsen

Thanks for your feedback davsclaus. CamelProxy is what I should have mentioned in the article. I will update the article shortly. One feedback on the the code that you have provided:
	@Override
	public void configure() throws Exception {
            from("direct:start")
            .convertBodyTo(ReportRequest.class)
            .split(bean("sectionRequestSplitterBean", "split"), new ReportAggregationStrategy())
    		    .transform().method("sectionRequestToXMLBean", "transform")
	    	    .to(serviceURL)
	            .transform().method("sectionResponseXMLToSectionBean", "transform")
            .end();
	}
The .end() is giving a compilation error. I am assuming that this is a bug with Apache Camel 2.1.0. It works without that, so for now I will include the code without the final .end().

Claus Ibsen replied on Sun, 2010/01/03 - 11:20am

Ah cool

The final *end()* is optional as the route ends anyway. Its only needed if you need to do some additional routing after all the messages has been aggregated again (eg. scatter-gather is done). But in this case the message should be returned to the original caller = the service gateway.

The compilation error. Yeah we have stretched as far we can do with regular Java. It certainly got its limitations when trying to mimic and build a DSL.

Kai Wähner replied on Wed, 2012/01/11 - 4:10am

I just wrote an article, which explains my experiences with Apache Camel and its alternatives Spring Integration and Mule ESB:

Spoilt for Choice: Which Integration Framework to use - Spring Integration, Mule ESB or Apache Camel?


Best regards,
Kai Wähner (Twitter: @KaiWaehner)

Oleg Zhurakousky replied on Wed, 2012/03/14 - 11:20am in response to: Claus Ibsen

@Stephan Spring Integration has always provided persistent storage option for both Aggregator and Resequencer via 'message-store' option. You can read more here: http://static.springsource.org/spring-integration/reference/htmlsingle/#aggregator

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.