Friday, April 20, 2012

Apache Camel first steps II

In the post Apache Camel first steps II you can see how to create a basic camel project using maven and define a simple route. The next step would be using a powerful component the Properties component that allows to use a properties file as its name suggests when defining endpoints.

It is a very handy feature especially during testing or more in general if you want to define endpoint in a file and use its key in the actual route. Combined with the maven filters is even more effective. Let's say you have a route that leverages the jms component but at test time you want to use a simple direct:something endpoint. This is easy to achieve! Follow the few steps below:
  • create an src/filters directory 
  • create a test.properties under src/filters in your maven project
  • add filtering resources in your pom as shown below
 <build>

<!-- setting the filter location and variable -->

<filters>
<filter>src/filters/${filter.file}</filter>
</filters>

<!-- force the filtering of the resources -->
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
  ...
 <build>
  • add the file camel.properties under src/main/resources/META-INF
Let's now add some properties in the files listed above.

test.properties

in.route.param=file:src/foo?noop=true
out.others.route.param=file:target/messages/others
out.uk.route.param=file:target/messages/uk

camel.properties

in.route=${in.route.param}
out.route=${in.route.param}
out.uk.route=${out.uk.route.param}

Run the command mvn compile test-compile -Dfilter.file=test.properties from the command line in your project base dir and check the target/classes/camel.properties file. You should see that all the properties have been set using the filter value. As a matter of fact the -Dfilter.file=test.properties will tell maven to use that file when processing the resources.

So far we didn't do much in camel. Let's use the Properties component then. The first snippet shows the usual way for defining endpoints while the second uses the properties. As you can see the only difference is the usage of {{route}}. Pretty neath!

------ first snippet
        from("file:src/foo?noop=true").
            choice().
                when(xpath("/person/city = 'London'")).to("file:target/messages/uk").
                otherwise().to("file:target/messages/others");

------ second snippet
        from("{{in.route}}").
           choice().
               when(xpath("/person/city = 'London'")).to("{{out.uk.route}}").
               otherwise().to("{{out.route}}");

Now last step is telling camel to use the Properties component defining the location of the file we just created. This is easily done by adding the code below:

if (getContext().hasComponent("properties") == null) {
   PropertiesComponent pc = new PropertiesComponent();
   pc.setLocation("classpath:META-INF/camel.properties");
   getContext().addComponent("properties", pc);
}

When implementing a real world application it is a good idea to divide routes into classes according to some logic equivalence. For instance the PRoperties component and any other initial configuration should be set in one RouteBuilder class.

To use the properties in the test class override the AbstractApplicationContext method as follows:


   @Override
protected AbstractApplicationContext createApplicationContext() {
return new ClassPathXmlApplicationContext(
"classpath:META-INF/spring/camel-context.xml");
}

And override the postProcessTest method:

@Override
protected void postProcessTest() throws Exception {

PropertiesComponent pc = new PropertiesComponent();
pc.setLocation("classpath:META-INF/camel.properties");
context.removeComponent("properties");
context.addComponent("properties", pc);
context.getComponent("properties");
pc.start();
context.setTracing(true);
super.postProcessTest();
}

Last but not least the configuration of the maven bundle plugin: felix. In your pom you need to tell maven how to create the bundle. In this scenario is pretty simple:

<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<version>2.3.4</version>
<extensions>true</extensions>
<configuration>
<instructions>
<Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
<Require-Bundle>
<!-- no required bundle now -->
</Require-Bundle>
<Include-Resource>
META-INF/spring/camel-context.xml=${basedir}/target/classes/META-INF/spring/camel-context.xml,
META-INF/camel.properties=${basedir}/target/classes/META-INF/camel.properties
</Include-Resource>
<DynamicImport-Package>*</DynamicImport-Package>
</instructions>
</configuration>
</plugin>

Run your test and have fun.

No comments:

Post a Comment