Gert Vanthienen's blog

Tuesday, January 13, 2009

A better CBR

Implementing a content based router in Camel is very simple. However, this also means that the routing rules are hard-coded in the Camel RouteBuilder.

Building a more dynamic solution is equally simple with the new @RecipientList annotation. You just create bean with a method that returns a (collection of) endpoints. You can off course use other annotations (like the @XPath annotation) to make your work easier.

public class RecipientListService {
@RecipientList
public List getTargets(@XPath("/po/supplier/@id") String id) {
// lookup endpoint(s) in db or config file
}
}

When using Camel inside ServiceMix, you then register this bean in your camel-context.xml file.

<beans>
<camelContext>...

<bean id="RecipientListService" class="be.anova.camel.RecipientListService">
<!-- this is plain Spring so you can inject any db, webservice, ... you need -->
</bean>
</beans>

By using plain Java and a Spring configuration file, we can write any kind of Java code or access any resource (e.g. a database or external config file) to determine the next routing step. This way, we can build a SA that can be reconfigured without redeployment.

An example use case? You can now build a generic PO handling SA. Every time a new supplier wants to receive their PO electronically, you just create a SA with the supplier-specific endpoints and add some config and you're done! You can even keep the config and the endpoints together in a single bundle if you're using ServiceMix 4 and leverage the OSGi registry to hold your configuration data.

And if you wonder what the Camel route itself looks like, it is a simple as it gets:

from("jbi:service:urn:my:service").beanRef("RecipientListService", "getTargets");

Labels: ,

Thursday, October 30, 2008

Releases, releases, ....

The latest ServiceMix release news:

  • ServiceMix 3.2.3 is a bugfix release for the 3.2.x series

  • ServiceMix 3.3 is the new release of our container, using new versions of ActiveMQ, Camel, CXF, Drools, Jetty, Saxon, ...

  • there also is new milestone release of the ServiceMix 4 NMR

  • a whole set of OSGi bundles was released: we now have over 60 OSGi-fied artifacts available -- you can find the full list here

Labels:

Tuesday, September 23, 2008

ServiceMix Kernel and Camel

Guillaume already announced the release of ServiceMix Kernel 1.0.0 on his blog. We use it as the base for building SMX 4, but you can add any behavior to it by just installing a few bundles.

An example: to convert ServiceMix Kernel into an Apache Camel route container, we just type these three commands in the kernel's console:

osgi install -s mvn:org.springframework/spring-tx/2.5.5
osgi install -s mvn:org.apache.camel/camel-core/1.4.0
osgi install -s mvn:org.apache.camel/camel-spring/1.4.0

This will get the bundles from a local or remote Maven repository, install and start them. Once this is done, you can just create a simple XML file containing the route definitions in the deploy and kernel's file monitor will install and deploy them. You can check the log file with the log d command to see the route in action.

<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://activemq.apache.org/camel/schema/spring
http://activemq.apache.org/camel/schema/spring/camel-spring.xsd">

<camelContext xmlns="http://activemq.apache.org/camel/schema/spring">
<route>
<from uri="timer://myTimer?fixedRate=true&period=2000"/>
<to uri="log:demo?showBodyType=false"/>
</route>
</camelContext>

</beans>

Labels: , ,

Friday, August 1, 2008

ServiceMix 3.2.2 released


We just released ServiceMix 3.2.2 this morning. A lot of bugs were fixed, but it also contains major improvements on the Camel and CXF compents. We also improved the Maven archetypes to include the necessary information for an IDE to use the XSD to provide you with code completion when editing xbean.xml files.

Check out the release notes for all the details!

Labels:

Thursday, June 5, 2008

Unit testing Camel routes for ServiceMix

ServiceMix allows you to write integration tests using the Spring framework. In addition to this, there is a little technique that allows you to write unit tests for the Camel routes you'll use inside ServiceMix as well. Write the core routing logic (in this example: a content based router) in an abstract RouteBuilder class ...

public abstract class AbstractRouteBuilder extends RouteBuilder {

protected static final String DIRECT_ROUTER = "direct:router";
protected static final String DIRECT_SUPPLIER1 = "direct:supplier1";
protected static final String DIRECT_SUPPLIER2 = "direct:supplier2";

public void configure() {
from(DIRECT_ROUTER)
.choice()
.when(xpath("/po/supplier/@id = '3125'"))
.to(DIRECT_SUPPLIER1)
.otherwise()
.to(DIRECT_SUPPLIER2);
}
}

... and add the JBI endpoint bindings in a separate class, extending the abstract base routing rules.

public class JbiRouteBuilder extends AbstractRouteBuilder {

@Override
public void configure() {
super.configure();

//adding the JBI bindings
from(DIRECT_SUPPLIER1).to("jbi:service:urn:be:anova:po:supplier1");
from(DIRECT_SUPPLIER2).to("jbi:service:urn:be:anova:po:supplier2");
from("jbi:service:urn:be:anova:po:router).to(DIRECT_ROUTER);
}

}

This will allow you to write your unit tests using Camel mock endpoints by extending the same abstract base class. In the example below, we put one sample XML document for every supplier in a test resources folder and we have a file: endpoint to send both of them through our RouteBuilder for testing.

public class RouteBuilderTest extends ContextTestSupport {

public void testContentBasedRouter() throws Exception {
getMockEndpoint("mock:supplier1").expectedMessageCount(1);
getMockEndpoint("mock:supplier2").expectedMessageCount(1);
assertMockEndpointsSatisifed();
}

@Override
protected RouteBuilder createRouteBuilder() throws Exception {
return new AbstractRouteBuilder() {
@Override
public void configure() {
super.configure();
from(AbstractRouteBuilder.DIRECT_SUPPLIER1).to("mock:supplier1");
from(AbstractRouteBuilder.DIRECT_SUPPLIER2).to("mock:supplier2");
from("file:src/test/resources/be/anova/smx/purchase?noop=true")
.to(DIRECT_ROUTER);
}
};
}
}

Labels: ,