fredag 6 november 2015

JetBrains shot themselves in the foot with their new pricing model

I've been an avid Intellij user since ~5 years back when I finally took the dive and walked away from Eclipse. Suffice to say I've been very impressed with the tooling and consider myself as a better developer when I'm armed with it.

The IDE has also been instrumental in showing me the "right way" to develop with it's hints, auto completion etc. I can therefore probably say that it has helped me shape the type of developer I am today and how I like to get stuff done.
Jetbrains domination over the JVM IDE tooling market has been all but complete as nowadays you hardly see any other IDE's being used, especially not if you look at what conference speakers and other types of influencers use.

This type of monopoly is always dangerous as it is really easy to get locked up with one vendor which is seldom a very good thing. Recently Jetbrains announced their new pricing model (latest update) which will mean that it becomes quite a lot more expensive for the typical Intellij Ultimate user. The backlash was not late to be seen in their forums and on blogs as users were anxious about how a "rent-your-IDE" model would hurt them in the end.

I can only speak for myself, but the first thing I did after I read the announcment was to give Netbeans a second (or perhaps tenth?) chance at winning me over. What I saw was a fairly complete IDE that except for some styling warts nowadays seems to work pretty well. We're all still waiting for the ES6 support, but once that is in place I think that I definitely could use it during my day to day work.

Just this day another thought crossed my mind though:

Intellij IDEA comes in two flavors, a community edition as well as the Ultimate edition.
If you look at the comparison matrix you'll see that the biggest missing features of the free community edition are:

  • HTML / Javascript support
  • Server support (Run Tomcat / JBoss / Websphere et al.)
  • Framework support (Spring beans / xml context, Java EE etc..)

Now I don't know about you, but these features are stuff that I'm more than willing to give up as the typical software stack of a JVM developer has changed quite radically lately.

  • As we're all building runnable JAR types of applications you really do not have the need to manage the typical Tomcat / Java EE servers anymore.
  • Frameworks are loosing their significance as well as more of the open source world is moving towards a library mindset rather than heavy frameworks to adapt to. Take Spark, Ratpack, RxNetty, Spring boot etc as examples.
  • HTML / Javascript is a bummer to loose, but personally I've been using Sublime coupled with some favourite plugins for that kind of environment. Sublime is mature, fast and has a lot of momentum going for it. It's a perfect solution to HTML/JS development with its abundance of linters, language and framework plugins etc.

It just strikes me that a feature complete IDE's is not as relevant in the modern JVM developer toolbox and it will be interesting to see how adoption of the new pricing model will turn out.

I'm predicting that the outcome of the pricing change is that modern JVM developers will probably do one of the following:

  • Switch to Netbeans one it's Javascript support is up to par
  • Use Intellij Community coupled with Sublime text for the front end development
  • Toss the JVM, drink the cool-aid and join the Node team

And no Eclipse, we will not let you fool us to coming back again. Don't even consider yourself as an alternative.

What's your take?

tisdag 14 april 2015

Ok, ok I get it... So this Node thingy IS actually quite cool...

I consider myself a polyglot developer who typically uses the best tools for the particular task at hand. Nevertheless when it comes to actually building production ready applications my main language has historically been within the JVM, more times than not relying on the always trusty Java ecosystem with it's abundance of libraries and frameworks.

Today I really got one of those OMGOD moments when you realize just how easy alternative technologies makes your life comparing to what you usually have to keep up with.

At my current customer project we unfortunately have to deal with a remote external SOAP service, which in my and most developers opinion is a protocol born out of hell and is the perfect example of an over engineered solution to something that should be pretty simple.

After dealing with a botched release due to threading problems and bugs within the SOAP framework we used I intended to switch to CXF, which is probably the most popular JAX-WS implementation in Java land.

Many hours later I had a working client after tearing my hair out fighting questions such as:

  • How do we authenticate using WS-Security
  • Which JAR's to include in the Maven build? (CXF has a lot of modules)
  • How to make the JAXB code generation behave well and produce the types of classes we need
  • How to intercept and log relevant request / responses over the wire
  • How to cope with threading, JAX-WS is not thread safe while CXF as an implementation claims to be
  • How to configure CXF to use our logging framework of choice
  • etc...

You get the idea, a lot of ceremony just to create something that could send structured data over the wire and parse responses into something that we can work with.

Just out of curiosity I went ahead and started investigating how you would create a soap client in Node.js land as I have previously built a couple of lightweight internal Node apps for testing, service bridging etc. My first thought was that the cool JS kids would probably never even poke a stick at something like SOAP, so I did not expect to find any good NPM modules for it.

Turns out that even JS developers aren't immune to the protocol madness of SOAP and someone actually went ahead and wrote a very clean and simple client and service module. After reading the example (https://github.com/vpulim/node-soap) and about 5 minutes of experimenting I was up and running. This was what it took to create the same thing I fought for hours with CXF.
  
npm install soap

  
  var soap = require('soap');
  var url = 'gateway.wsdl'; //local file, could also be a remote http url
  var args = {};

  soap.createClient(url, function(err, client) {
    //WS-Security UserNameToken out of the box
    client.setSecurity(new soap.WSSecurity('myUser', 'myPassword'));
    
    //GetProducts is an operation in the wsdl
    client.GetProducts(args, function(err, result) {
      if (!err) {
        //Do something valuable with the response, for now just log.
        //Each XML element in the response would become a corresponding field on the result object
        console.log(JSON.stringify(result, null, 2));
      }
      else {
        console.log(err);
      }
    });
  });

So, I guess Java and CXF lost this one. And for Node... well it's something you probably should consider learning ASAP. Even if you're a grumpy old-school JVM developer like yours truly.

tisdag 12 november 2013

Love is in the details. Or when I really fell in love with Dropwizard

So Dropwizard seems to be the rage around Java / Scala developers today as an extremely clean and minimalistic framework for DTRS ("Doing The Right Stuff") when it comes to serving up thick clients with REST-ful data. If you haven't checked it out yet, I urge you to.
It is really one of those few frameworks that looks so shiny and sexy that you immediately start thinking about in which of your projects you could introduce it. The last time I was this enthustiastic about a new library was when I first laid my eyes on Camel, which shares the same minimalistic mindset.

Now, a lot has been said about it's excellent choice of best-of-breeds libraries, the YAML configuration, server-less environment and the ability to quickly assemble healtchecks. But the tiny one thing that made me realize that the folks at Yammer really put in a lot of thought into the package was not as profound as the above points. It was a really small feature that simply tells you that these guys has been in the trenches and know what they're doing. Now, which of all features could that be?

Error logging...

As I started to play around with a small hello world hobby project and got my first 500 error back at me it said something like:

"There was an error processing your request. It has been logged (ID 2e7c06aac7bcf2aa)."

Looking into the server logs I see a stacktrace with the same ID appended:

 ERROR [2013-11-12 11:18:23,651] com.yammer.dropwizard.jersey.LoggingExceptionMapper: Error handling a request: 2e7c06aac7bcf2aa  
 ! java.lang.RuntimeException: My extremely PITA error  
 ! at se.com.eyc.employeecatalog.EmployeeCatalogue.allEmployees(EmployeeCatalogue.java:38) ~[dropwizard.jar:na]  
 ! at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.6.0_45]  
 ! at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) ~[na:1.6.0_45]  
 ! at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) ~[na:1.6.0_45]  
 ! at java.lang.reflect.Method.invoke(Method.java:597) ~[na:1.6.0_45]  
 ! at com.sun.jersey.spi.container.JavaMethodInvokerFactory$1.invoke(JavaMethodInvokerFactory.java:60) ~[jersey-server-1.17.1.jar:1.17.1]  
 ! at com.sun.jersey.server.impl.model.method.dispatch.AbstractResourceMethodDispatchProvider$TypeOutInvoker._dispatch(AbstractResourceMethodDispatchProvider.java:185) ~[jersey-server-1.17.1.jar:1.17.1] ! at com.sun.jersey.server.impl.model.method.dispatch.ResourceJavaMethodDispatcher.dispatch(ResourceJavaMethodDispatcher.java:75) ~[jersey-server-1.17.1.jar:1.17.1]  
 ! at com.yammer.dropwizard.jersey.OptionalResourceMethodDispatchAdapter$OptionalRequestDispatcher.dispatch(OptionalResourceMethodDispatchAdapter.java:37) ~[dropwizard-core-0.6.2.jar:na]  
 ! at com.sun.jersey.server.impl.uri.rules.HttpMethodRule.accept(HttpMethodRule.java:302) ~[jersey-server-1.17.1.jar:1.17.1]  
 ! at com.sun.jersey.server.impl.uri.rules.ResourceObjectRule.accept(ResourceObjectRule.java:100) ~[jersey-server-1.17.1.jar:1.17.1]  
 ! at com.sun.jersey.server.impl.uri.rules.RightHandPathRule.accept(RightHandPathRule.java:147) ~[jersey-server-1.17.1.jar:1.17.1]  
 !etc....  

Now this is great handing out of the box for three reasons:
  • Your customer / client system has an ID they can refer to which you can find with a simple grep in the logs
  • The default behaviour in DW is to NOT hand your stacktrace to your clients (unlike say a plain Tomcat among others). I can not believe that you still today sometimes see customer facing sites with no configured error page. That actually happened to me just a couple of days ago when a pretty big web shop happily informed me that they had not tweaked their connection pool for the MySQL database in the backend. This is just sloppy and DW simply does the right thing for you out of the box.
  • The stacktrace actually contains the artifact id and version of the dependencies that was involved in the stack. This is pure genious as it helps tremendesly i.e. when you submit bugs since everyone can easily see which versions of what you were using.
So, just a small example why I think DW rocks and proves that the guys who built it knows what they're doing. It seems to be a stable foundation to build your next web app or service on. I sincerely hope that it can stay out of the typical OS feature creep and stay simple and lean.

Til next time!

torsdag 6 december 2012

Using Groovy and Camel for your scripting purposes

This topic has been displayed at other blogs, but it's such a great concept and served me very well quite recently so I think it warrants a revisit.

As a JVM developer (isn't that what we ought to call us nowaday when Scala/Groovy/Clojure is all the hype?) you're often sidelined by your scripting wiz fellows when it comes to writing quick "one-off" scripts for testing purposes and what-not.

I've personally gone as far as learning a bit of Python for this purpose, but I tend to miss my favorite java libraries and the ecosystem, although I must give the deepest respect to Python which is a really nice and powerful language. I must also confess that I've yet to find the time needed to become really proficient with it.

On our current project we had a requirement for a one-way http multicast solution in one of our test environments, as the backend system we were mediating requests to had more test environments than the rest of the chain. In EIP patterns you'd call this a fanout, multicast proxy or something similar.

Well... I thought this would be a really good fit for Camel, so I started setting up a standard Maven project. After a while it became quite obvious that while the Camel route itself was extremely small and simple, the project consisted of more Maven ceremony than actual code.

As this was an application for a test environment I was really not that interested in having a full build process for it. I'd rather just have something up and running in as few lines as possible.

Well, groovy scripts + grape to the rescue...

As any of you who've dealt with Groovy programming know, it is a great language for creating standalone scripts which are compiled and executed at runtime. Although Scala is my personal #1 choice when it comes to the JVM languages and offers scripting support as well, Groovy has one up in the Grape ecosystem which I've not yet seen in the Scala world.

So after moving the essential part of my application (the route) to it's own groovy script and adding a few Grape annotations to download the external Camel dependencies the solution was basically finished and executable by running "groovy Multicaster.groovy". Mind you, this is an extremely simple route and the dependencies will be downloaded at runtime which would be totally forbidden in a production environment. But for this purpose it fit the bill perfectly.

 @Grab('org.apache.camel:camel-core:2.10.0')  
 @Grab('org.slf4j:slf4j-api:1.6.6')  
 @Grab('org.slf4j:slf4j-log4j12:1.6.6')  
 @Grab('log4j:log4j:1.2.16')  
 @Grab('org.apache.camel:camel-jetty:2.10.0')  
 import org.apache.camel.*  
 import org.apache.camel.impl.*  
 import org.apache.camel.builder.*  
   
 def camelContext = new DefaultCamelContext()  
   
 camelContext.addRoutes(new RouteBuilder() {  
   def void configure() {  
     from('jetty:http://0.0.0.0:6080/?chunked=false')  
       .convertBodyTo(byte[].class) //To read multiple times, default is InputStream which is only readable once  
       .removeHeader(Exchange.HTTP_PATH) //So as not to forward URI to next call...  
       .wireTap("seda:multicaster")  
       .setBody().constant(STATIC_RESPONSE);  
       
     //Using SEDA here as it implies async handoff  
     from("seda:multicaster")  
          .multicast().parallelProcessing().to(  
   
         //bridgeEndpoint is used to indicate that http headers (SOAPAction etc) should be copied  
         'http://testserver1:6060/myService?bridgeEndpoint=true&throwExceptionOnFailure=false', //consumer1  
         'http://testserver2:6060/myService?bridgeEndpoint=true&throwExceptionOnFailure=false', //consumer2  
         'http://testserver3:6060/myService?bridgeEndpoint=true&throwExceptionOnFailure=false', //etc...  
         'http://testserver4:6060/myService?bridgeEndpoint=true&throwExceptionOnFailure=false',  
         'http://testserver5:6060/myService?bridgeEndpoint=true&throwExceptionOnFailure=false'  
       );  
   }  
   
   final String STATIC_RESPONSE = '''\  
             <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ipl="http://www.acme.se/ipl">  
               <soapenv:Body>  
                <ipl:ipl>OK</ipl:ipl>  
               </soapenv:Body>  
             </soapenv:Envelope>'''.stripIndent()  
 })  
   
 camelContext.start()  
   
 addShutdownHook{ camelContext.stop() }  
 synchronized(this){ this.wait() }  

The combination of Camel in a scripting environment is extremely powerful. Just imagine the possibilities for statistic gathering utilities etc.. Now off to some more Groovying..


fredag 1 juni 2012

Free integration breakfast seminar in Stockholm, Oslo and Copenhagen

I'd just like to inform you that we at Redpill Linpro will be hosting a series of breakfast seminars about the FuseSource line of products, meaning Camel, CXF, ActiveMQ and ServiceMix.

The seminars will give you a technical quickstart to using Camel and ServiceMix in your projects and is intended for developers and architects. So there will be no fluffy slides or sales pitches but rather a more "down to the core" type of seminar with lots of coding and examples of why Camel is such an awesome integration framework to work with.

If you are interested and either in the Stockholm, Oslo or Copenhagen areas, just register at the specific event. The seminar is of course free. Hope to see you there!

Stockholm (12/6)
Oslo (13/6)
Copenhagen (14/6)

Until next time!


UPDATE

I'd like to update you with the links to the presentations as well as the source code. Many thanks to all of you who attended. Especially to Claus Ibsen (the Camel project lead) who took the time to show up in the audience at the Copenhagen session.

Slides at slideshare:
http://www.slideshare.net/RedpillLinpro

Code at github:
https://github.com/billybong/stockGwDemo

torsdag 8 mars 2012

Bridging between JMS and RabbitMQ (AMQP) using Spring Integration

An old customer recently asked me if I had a solution for how to integrate between their existing JMS infrastructure on Websphere MQ with RabbitMQ.

Although I know that RabbitMQ has the shovel plugin which can bridge between Rabbit instances I've yet not found a good plugin for JMS <-> AMQP forwarding.
The first thing that came to my mind was to utilize a Spring Integration mediation as SI has excellent support for both JMS and Rabbit.

Curious as I am I started a PoC and this is the result. It takes messages of a JMS queue and forwards to an AMQP exchange that is bound to a queue the consumer application is supposed to listen to. I used an external HornetQ instance in JBoss 6.1 as the JMS Provider, but I am 100% secure that the same setup would work for Websphere MQ as they both implement JMS.

Be aware that I've done no performance tweaking or QoS setup yet as this is just a proof-of-concept. For a real setup you'd probably have to think about delivery guarantees versus performance and etc...

The code will be available at a GitHub repository near you soon..

SpringContext in XML:

<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/integration"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:int-amqp="http://www.springframework.org/schema/integration/amqp"
xmlns:rabbit="http://www.springframework.org/schema/rabbit"
xmlns:int-jms="http://www.springframework.org/schema/integration/jms"
xmlns:int="http://www.springframework.org/schema/integration"
xsi:schemaLocation="http://www.springframework.org/schema/integration/amqp http://www.springframework.org/schema/integration/amqp/spring-integration-amqp-2.1.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration-2.0.xsd
http://www.springframework.org/schema/integration/jms http://www.springframework.org/schema/integration/jms/spring-integration-jms-2.1.xsd
http://www.springframework.org/schema/rabbit http://www.springframework.org/schema/rabbit/spring-rabbit-1.0.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

<beans:bean id="jndiTemplate" class="org.springframework.jndi.JndiTemplate">
<beans:property name="environment">
<beans:props>
<beans:prop key="java.naming.factory.initial">org.jnp.interfaces.NamingContextFactory</beans:prop>
<beans:prop key="java.naming.provider.url">jnp://localhost:1099</beans:prop>
<beans:prop key="java.naming.factory.url.pkgs">org.jnp.interfaces:org.jboss.naming</beans:prop>
</beans:props>
</beans:property>
</beans:bean>

<beans:bean id="jmsQueueConnectionFactory"
class="org.springframework.jndi.JndiObjectFactoryBean">
<beans:property name="jndiTemplate">
<beans:ref bean="jndiTemplate"/>
</beans:property>
<beans:property name="jndiName">
<beans:value>ConnectionFactory</beans:value>
</beans:property>
</beans:bean>

<!-- Channels and adapters for SI -->
<int-jms:message-driven-channel-adapter connection-factory="jmsQueueConnectionFactory" destination-name="myJmsQueue" channel="rabbitChannel"/>
<channel id="rabbitChannel"/>
<int-amqp:outbound-channel-adapter channel="rabbitChannel" exchange-name="fromJmsExchange" amqp-template="rabbitTemplate"/>

<!-- Connectivity to Rabbit -->
<rabbit:template id="rabbitTemplate" connection-factory="cf"/>
<rabbit:connection-factory id="cf" host="localhost"/>

<!-- Rabbit entities, to be created at context startup -->
<rabbit:admin connection-factory="cf"/>
<rabbit:queue name="fromJMS"/>
<rabbit:direct-exchange name="fromJmsExchange">
<rabbit:bindings>
<rabbit:binding queue="fromJMS"/>
</rabbit:bindings>
</rabbit:direct-exchange>
</beans:beans>


Maven POM:


<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>org.rl</groupId>
<artifactId>si.jmstorabbit</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>

<name>si.jmstorabbit</name>
<url>http://maven.apache.org</url>

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<hornet.version>2.2.5.Final</hornet.version>
<spring.integration.version>2.1.0.RELEASE</spring.integration.version>
</properties>

<repositories>
<repository>
<id>springsource-release</id>
<url>http://repository.springsource.com/maven/bundles/release</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
<repository>
<id>springsource-external</id>
<url>http://repository.springsource.com/maven/bundles/external</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>

<dependencies>
<dependency>
<groupId>org.springframework.integration</groupId>
<artifactId>spring-integration-core</artifactId>
<version>${spring.integration.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.integration</groupId>
<artifactId>spring-integration-file</artifactId>
<version>${spring.integration.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.integration</groupId>
<artifactId>spring-integration-amqp</artifactId>
<version>${spring.integration.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.integration</groupId>
<artifactId>spring-integration-jms</artifactId>
<version>${spring.integration.version}</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>3.0.7.RELEASE</version>
</dependency>

<dependency>
<groupId>jboss</groupId>
<artifactId>jnp-client</artifactId>
<version>4.2.2.GA</version>
</dependency>


<dependency>
<groupId>org.hornetq</groupId>
<artifactId>hornetq-core-client</artifactId>
<version>${hornet.version}</version>
</dependency>
<dependency>
<groupId>org.hornetq</groupId>
<artifactId>hornetq-jms-client</artifactId>
<version>${hornet.version}</version>
</dependency>
<dependency>
<groupId>org.hornetq</groupId>
<artifactId>hornetq-jms</artifactId>
<version>${hornet.version}</version>
</dependency>
<dependency>
<groupId>jboss</groupId>
<artifactId>jboss-common-client</artifactId>
<version>3.2.3</version>
</dependency>
<dependency>
<groupId>org.jboss.netty</groupId>
<artifactId>netty</artifactId>
<version>3.2.7.Final</version>
</dependency>
<dependency>
<groupId>javax.jms</groupId>
<artifactId>jms</artifactId>
<version>1.1</version>
</dependency>
</dependencies>

</project>

torsdag 1 december 2011

Gotcha when using camel-servlet

In my current project I'm using Apache Camel for the integration, and I bumped into a significant "oups"-moment while using the camel-servlet component.

I found that while I had multiple applications (WAR's) deployed I often started the wrong routes, even though I was hitting the correct endpoint url.

Say i.e. that you have two application, A and B. Both of these has the same endpoint addresses, i.e. servlet:/myservice

The logical thing would be that you could reach application A through:
http://localhost/A/myservice

and B through:
http://localhost/B/myservice

Now imagine my surprise when requests for the A application would up in the route for B. It took me a while to figure this out, but here's the reason for this...

When you expose your routes through servlet's you are using the CamelHttpTransportServlet class. An example web.xml could be something like this:

<!-- Camel servlet -->
<servlet>
<servlet-name>CamelServlet</servlet-name>
<servlet-class>org.apache.camel.component.servlet.CamelHttpTransportServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>

<!-- Camel servlet mapping -->
<servlet-mapping>
<servlet-name>CamelServlet</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>


Now, if you name your servlet the same for both applications you're actually only publishing one common servlet class. The camel servlet component does not take your context-root into account, which means that you hit the same endpoint irregardless whether you go to /A/myservice or /B/myservice. The one that gets hit is the one that was last deployed (or started).

Ok, easily fixed I thought... Just rename the servlet-name to something more unique for each application...
After that my routes where no longer reachable and I was just left with 404's each time I tried to hit the endpoints.
After some trial and error as well as googling I found out that if you rename your servlet from the default "CamelServlet" you *have* to specify the servlet name in your endpoint uri as well.
That is, the endpoint in application A would be i.e.:

servlet:/myService?servletName=AServlet

and B:

servlet:/myservice?servletName=BServlet

So, the lesson is:

- Always rename the camel servlet name, you never know which other applications will be deployed together on the same server. Your endpoints might clash with these and you'll have a mess figuring out why.

- Always include the servletName in your endpoint uri.

These tips should definitely be added to the documentation page to help others avoid making the same mistake.

'til next time!

torsdag 1 september 2011

Implementing your own "SOA" registry, the maven way

Saw a very interesting article on InfoQ by Ben Wilcock where he described a dead simple SOA R&R using a very pragmatic approach with Maven combined with a simple HTML app.
http://www.infoq.com/articles/SimpleServiceRepository

As an integration consultant I've worked with registries ranging from overly complex offerings (IBM Websphere Registry and Repository) to time-consuming simple wikis, but I have to say that his solution is arguably the most elegant yet.

The best part is that you both get the visibility as your schemas and contracts are available to all your stakeholders, while keeping your co-developers happy by just pointing them to a Maven project to include in their dependencies.

I'm definately hijacking this concept to my current project, and I find it very interesting that this solution has been under my nose all this time without reflecting on it.

tisdag 26 juli 2011

Camel and HornetQ as JMS provider

In my current project we're utilizing JBoss HornetQ as the messaging bus, and I wanted to try out how Camel could connect to it. My intention was to have the HornetQ instance running externally from the Camel application and connect to it. There are a bunch of examples on how to embedd HornetQ 2.2.5 (the release I'm dealing with) inside Spring, but I could'nt find a single one for how to connect to an external instance.

For my own reference I post the working solution here which uses HornetQ's JNDI to lookup the ConnectionFactory as well as a Spring JNDI template.

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

<bean id="jndiTemplate" class="org.springframework.jndi.JndiTemplate">
<property name="environment">
<props>
<prop key="java.naming.factory.initial">org.jnp.interfaces.NamingContextFactory</prop>
<prop key="java.naming.provider.url">jnp://localhost:1099</prop>
<prop key="java.naming.factory.url.pkgs">org.jnp.interfaces:org.jboss.naming</prop>
</props>
</property>
</bean>

<bean id="jmsQueueConnectionFactory"
class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiTemplate">
<ref bean="jndiTemplate"/>
</property>
<property name="jndiName">
<value>ConnectionFactory</value>
</property>
</bean>

<bean name="jms" class="org.apache.camel.component.jms.JmsComponent">
<property name="connectionFactory" ref="jmsQueueConnectionFactory"/>
</bean>

<camel:camelContext id="context1">
<camel:route id="FirstRoute">
<camel:from uri="jms:queue:inputqueue"/>
<camel:log logName="jmsLog" message="Got message from JMS queue:"/>
<camel:to uri="jms:topic:helloworld"/>
</camel:route>
</camel:camelContext>
</beans>


And the Maven POM:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>camelHornet</groupId>
<artifactId>camelHornet</artifactId>
<version>1.0-SNAPSHOT</version>

<properties>
<camel.version>2.8.0</camel.version>
<hornet.version>2.2.5.Final</hornet.version>
</properties>
<dependencies>
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-core</artifactId>
<version>${camel.version}</version>
</dependency>
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-spring</artifactId>
<version>${camel.version}</version>
</dependency>
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-jms</artifactId>
<version>${camel.version}</version>
</dependency>
<dependency>
<groupId>org.hornetq</groupId>
<artifactId>hornetq-core-client</artifactId>
<version>${hornet.version}</version>
</dependency>
<dependency>
<groupId>org.hornetq</groupId>
<artifactId>hornetq-jms-client</artifactId>
<version>${hornet.version}</version>
</dependency>
<dependency>
<groupId>org.hornetq</groupId>
<artifactId>hornetq-jms</artifactId>
<version>${hornet.version}</version>
</dependency>

<dependency>
<groupId>javax.jms</groupId>
<artifactId>jms</artifactId>
<version>1.1</version>
<type>jar</type>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.hornetq</groupId>
<artifactId>hornetq-logging</artifactId>
<version>${hornet.version}</version>
</dependency>
<dependency>
<groupId>org.jboss.netty</groupId>
<artifactId>netty</artifactId>
<version>3.2.3.Final</version>
</dependency>
<dependency>
<groupId>jboss</groupId>
<artifactId>jnp-client</artifactId>
<version>4.0.2</version>
</dependency>
<dependency>
<groupId>org.jboss.logging</groupId>
<artifactId>jboss-logging</artifactId>
<version>3.0.0.CR1</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.camel</groupId>
<artifactId>camel-maven-plugin</artifactId>
<version>${camel.version}</version>
<configuration>
<applicationContextUri>META-INF/context.xml</applicationContextUri>
</configuration>
</plugin>
</plugins>
</build>
</project>

tisdag 19 april 2011

Three mindblowing days of filling my brain with new stuff

This week we at Redpill-Linpro had the great fortune to be instructed by Charles Moulliard (FuseSource) on advanced topics covering ServiceMix and Camel.

Talking from my own experience I already had quite a good grasp of Camel, but ServiceMix was probably the eye-opener for me. Until now I've previously rolled my eyes each time SM was mentioned, thinking "why do we need yet another application platform when we have web servers, Spring, JEE servers etc already?".
What I did not understand until now is the flexibility you gain when deploying your integrations to a pure OSGI stack such as Karaf (which is the layer on top of your OSGI runtime) instead of using classic hierarchical class-loading servers.

One thing that also was clear is that ServiceMix, although labeled as an ESB, is actually sort of an application server in the sense that it is not only used for integration applications. Sure, you have a lot of Camel/CXF/ActiveMQ bundles already prebuilt and ready to be utilized, but looking at the architecture it is plain to see that any type of OSGI applications could benefit by being deployed into Karaf.

I can safely say that I've bought the hype of OSGI now after finally understanding what it actually gives you. I just hope for some better tooling when it comes to declaring your package exports and imports as that seems to be an area where you'll need to perform a lot of trial and error to get correct.

We also had some good discussions concerning the fact that a lot of supplementary (Activiti, JAMES etc..) and even competing frameworks already bundle Camel to expose transport options that are not already implemented by the framework itself. JBoss ESB i.e. comes with a Camel Gateway which could be used to handle messages originating from all types of transports available in Camel that the native ESB does not have adapters for.
It will be very interesting to see how long it takes for the big players (IBM and Oracle, I'm looking at you) to bundle Camel as part of their connector strategy. I can easily fantasize about i.e. a future Camel node in the Websphere Message Broker product as a way to extend the possible transport that it could provide.

'til next time!

tisdag 5 april 2011

New career, new opportunities

Today marked my first day as an employer at the open source consultant firm Redpill-Linpro. As you readers might have noticed, my interest in OS offerings in the integration space has recently risen up to the level where I'd like to make it into a career. Therefore I chose to switch my focus and work fulltime with the projects that has so far mostly been an interesting hobby at my spare time.

Personally I think that change is a good thing and you should always try to give yourself new insights, challenges and other perspectives on your knowledge. Therefore I am leaving the trusty IBM stacks I've known to love for the last 6 years or so and head out into the unknown, starting with JBoss SOA products and the FuseSource projects (Camel, ServiceMix etc..).

With that said, I am absolutely sure that I will miss all of my colleagues at Connecta since we've had some great moments and fond memories of assignments and projects (as well as some less strict endeavours in between).

Best of luck to you all, and hope we will see each other again soon!

tisdag 22 mars 2011

Templating webservices with Velocity using Camel

When creating webservices a lot of people has objections against using JAXB for binding XML to objects. This may be because of performance reasons, allergy to generated code or simply a philosophical belief that you should not mix document centric services with an object oriented model. Whatever the reasons for not using JAXB you have I'll try to describe a possible other solution using Camel.

I created this laboration after viewing Adrian Trenamans excellent talk about CXF usage in camel, so I can and will not take credit for anything you'll see. In that talk he showed a little trick were you could use Velocity as the templating engine for generating your soap responses, without ever doing any marshalling or parsing of the XML documents.

His complete session could be found here, but do note that you need a registration at fusesource.com to see it. It is free, so if you're interested I urge you to check it out.


Defining our contract


As mostly all SOA architects would tell you should always try to start by defining a wsdl, creating the service top-down. Our intended service in this sample is going to be a very simple credit check service that accepts a customer and provides a credit score and a detailed description about the reasoning behind the score.

Our service only has one operation for now, called PerformCreditCheck:



The response is a simple message containing the Score as well as a Details field:



The Camel context


I've chosen to implement the route using the Java DSL, so after setting up the CXF endpoint in the camel context I point the package scan to the java package where my route is. The complete camel-context.xml is as follows:
<?xml version="1.0" encoding="UTF-8"?>

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

<import resource="classpath:META-INF/cxf/cxf.xml"/>
<import resource="classpath:META-INF/cxf/cxf-extension-soap.xml"/>
<import resource="classpath:META-INF/cxf/cxf-extension-http-jetty.xml"/>

<cxf:cxfEndpoint xmlns:c="http://billy.laborations/CreditCheckService/" id="creditCheckEndpoint"
address="http://localhost:9000/creditcheck"
wsdlURL="META-INF/wsdl/CreditCheckService.wsdl"
serviceName="c:CreditCheckService"
endpointName="c:CreditCheckServiceSOAP"
serviceClass="billy.laborations.creditcheck.DummyService">
<cxf:properties>
<entry key="schema-validation-enabled" value="true" />
</cxf:properties>
</cxf:cxfEndpoint>

<camelContext xmlns="http://camel.apache.org/schema/spring">
<package>billy.laborations.creditcheck</package>
</camelContext>

</beans>



As you can see I'm providing the wsdl for the service, its endpoint address as well as an implementation class.

The JAX-WS Endpoint


Looking at this class is where things are starting to get interesting. Since I don't want to deal with JAXB I chose the JAX-WS Provider type of service which accepts arbitrary messages. Any type of message that hits this service will kick of the invoke() method, leaving XML parsing etc up to the developer. If you look at the method however, you'll notice that it is set up to always throw an exception, how could it possibly work? Well, it seems that Camel hijacks this method and kicks of the route instead, but this class still needs to be existing in order for the CXF runtime to initialize.


package billy.laborations.creditcheck;

import javax.xml.transform.stream.StreamSource;
import javax.xml.ws.Provider;
import javax.xml.ws.Service.Mode;
import javax.xml.ws.ServiceMode;
import javax.xml.ws.WebServiceProvider;

@WebServiceProvider(portName="CreditCheckPort", serviceName="CreditCheckService", targetNamespace="http://billy.laborations/CreditCheckService/")
@ServiceMode(Mode.PAYLOAD)
public class DummyService implements Provider<StreamSource> {

public StreamSource invoke(StreamSource request) {
throw new UnsupportedOperationException("Not implemented yet.");
}
}



Routing


The route is implemented as:


package billy.laborations.creditcheck;

import javax.xml.transform.stream.StreamSource;

import org.apache.camel.Exchange;
import org.apache.camel.Processor;
import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.builder.xml.Namespaces;
import org.apache.cxf.message.MessageContentsList;


public class CreditCheckRoute extends RouteBuilder {

public void configure() {
// lets define the namespaces we'll need in our filters
Namespaces ns = new Namespaces("c", "http://billy.laborations/CreditCheckService/");

from("cxf:bean:creditCheckEndpoint").routeId("CreditCheckRoute")
.process(new Processor(){
public void process(Exchange exchange) throws Exception {

//Cxf stores requests in a MessageContentList. The actual message is the first entry
MessageContentsList messageList = (MessageContentsList)exchange.getIn().getBody();
exchange.getIn().setBody(messageList.get(0), String.class);
}
})
.wireTap("seda:audit")
.setHeader("FirstName", xpath("/c:Customer/FirstName").resultType(String.class).namespaces(ns))
.setHeader("LastName", xpath("/c:Customer/LastName").resultType(String.class).namespaces(ns))
.setHeader("SocialNr", xpath("/c:Customer/SocialNr").resultType(Integer.class).namespaces(ns))
.process(new CreditCheckCalculator())
.to("velocity:META-INF/velocity/creditCheckResponse.vm")
.convertBodyTo(StreamSource.class)
;


from("seda:audit")
.inOnly()
.to("log:audit")
.to("file:target/audit/?fileName=${date:now:yyyyMMdd}.txt&fileExist=Append");
}
}



As you can see the route uses XPath to set some headers based on the incoming values. This is done so that our service (CreditCheckCalculator) has easy access to them.

The business service


I've kept the service simple in this case, but the interesting part is that it's using the camel headers for getting and setting the data. You don't have to implement the service as a camel Processor, there are a lot of ways to call i.e. an existing POJO using bean referencing, but I'll leave that for now.


package billy.laborations.creditcheck;

import org.apache.camel.Exchange;

public class CreditCheckCalculator implements org.apache.camel.Processor{

public void process(Exchange exchange) throws Exception {
String firstName = (String)exchange.getIn().getHeader("FirstName");
String lastName = (String)exchange.getIn().getHeader("LastName");
int socialNr = (Integer)exchange.getIn().getHeader("SocialNr");

int creditScore;
String details;

if(firstName.equalsIgnoreCase("Billy")){
creditScore = 99;
details = firstName + " is a really good customer!";
}else{
creditScore = 1;
details = firstName + " should not be trusted!";
}

exchange.getIn().setHeader("CreditScore", creditScore);
exchange.getIn().setHeader("Details", details);
}
}



Generating the response


Why are the headers a good place to store the result then? Well, in our case it's because we have easy access to them from the velocity template:


<CreditScore xmlns="http://billy.laborations/CreditCheckService/">
<Score>$headers.CreditScore</Score>
<Details>$headers.Details</Details>
</CreditScore>


The trick here is that we're templating our response without touching any XML API's. The velocity template will simply return a String object which we can then transform to a StreamSource before handing it back to the JAX-WS endpoint.

Final thoughts


Well, that sums up my experiment. It might look like a complex setup for a very simple service, but the benefits of using templating are:

* Performance - No need to parse the request or response messages
* WS stack - Exposing the route as an CXF endpoints gives us all the power of soap handlers and CXF injectors for i.e. adding security etc.
* Adding functionality to the route - The route can easily be extended to support other EIP patterns, such as custom auditing implemented by the wiretap in our example.

If you are interested in the code, I'll make sure to upload it. Otherwise thank you for this time!

fredag 11 mars 2011

Mule joins the GUI group

As open-source integration stacks are becoming more and more mature the final push to convince the market about their usability seems to be to provide some sort of GUI for developing your solutions.

I recently blogged about FuseSource's release of the Camel IDE, and now it seems that Mule is joining the fray by recently releasing the beta of the Mule Studio Eclipse plugin.

Read more at: http://blogs.mulesoft.org/mule-studio-beta/

So now the major OS integraiton players (Camel, Mule, JBoss ESB, Spring Integration) all have visual support for developers. I guess only time will tell how these tools will be able to keep up with the quick feature changes in the frameworks.

måndag 7 februari 2011

First Scala book in Swedish is out! Congrats guys!

On a personal note I'd like to congratulate my professional acquaintance Örjan Lundberg and his fellows Olle Kullberg and Viktor Klang for finalizing the Scala introductory book "Ett första steg i Scala". It's to my knowledge the first Swedish book to explain the concept of the Scala language.

You can find it at: http://www.studentlitteratur.se/o.o.i.s?id=2474&artnr=33847-01&csid=66&mp=4918

Congratulations guys! Hope I get the chance to read it soon!

söndag 30 januari 2011

Camel goes visual

So it seems that the Camel guys over at FuseSource has finally released the preview of the Camel development IDE. Basically an eclipse plugin that helps you author the spring xml files for your routes visually. I haven't tried it yet, but its an interesting tool which hopefully can help attract integrators into this nice framework.

There's already a short introduction up on their site, so head on to http://fusesource.com/ and have a look.

According to FuseSource they're also working on a runtime web version which you could use to inspect and author your flows directly against an executing ServiceMix/Karaf JVM.

So with Spring Integration having visual IDE support in their latest release of the STS tooling and Camel joining now it will be interesting to see what the Mule guys will bring to the table when it comes to IDE's. A sneak peak last year showed something similar (http://blogs.mulesoft.org/new-mule-ide-coming/) and you can also have a look at Saddle IDE which seems to target Mule developers as well (http://www.saddle-integration.org/).

Seems like all of them are going the XML-authoring way where your IDE generates XML configs in the background.

2011 already looks like a promising year for integration developers!

torsdag 9 december 2010

Eclipse XML autocompletion patch for Mule users

Earlier I wrote about my problems finding a good XML editor which works with Mule configuration files, as the one included in Eclipse WTP does not support XSD schema substitution groups.

That time I simply gave up and registered for a trial of the Oxygen XML eclipse plugin editor since that was the only one that I found that could give me autocompletion while modeling flows.
Well, it seems that the MuleSoft guys has figured out a way to patch this issue with Eclipse, which is very good news for the myriad of Mule users out there. This patch may also be worth downloading even if you're not intending to use Mule and regularly deal with schema substitutions in eclipse.

I have not yet tested the patch since I've been quite busy lately on my free time, but I'm sure it will be a welcome fix for many integrators.

Bye bye Oxygen, been nice to know you!

onsdag 1 december 2010

Soap through JMS support for WCF

One of the classic problems you face when dealing with webservices is how to assure a guaranteed delivery of your messages. Since http by its definition cannot guarantee that your messages are never lost a lot of initiatives has tried to solve this problem.

Currently this is typically handled in one of the following ways:

WS-Transaction
Not primary used as a means of guaranteed delivery, WS-Transaction still in some sense tries to solve the same problem with a consistency angle. I'll not dwell into the architectural reasons for WS-Transaction but simply note that it introduces a tight coupling between the service consumer and provider and is not preferable in i.e. a B2B solution. It is my firm belief that http/xml should not be used as a transaction medium since it was just not defined with that in mind in the first place. It also has performance implications as well as introduces complex call-chains and possible deadlocks.

WS-Reliable Messaging
Typically your provider and consumer would store outbound messages in some kind of message store and delete these first when they've been acknowledged by the other part through a conversation mechanism. Messaging platforms are often used as the persistent store, but regular databases could also be included, either as part of the messaging provider or by the WS stack.

Retry mechanisms and idempotent provider services
Clients simply retry the calls until a successful invocation is acheived. This puts a requirement on the provider to be idempotent either through the nature of the service, or by utilizing some framework for blocking resent requests based on a uniqueness in the message.

Soap through JMS
Most, if not all Java WS runtimes now support sending soap messages through a JMS provider. Soap/JMS is not yet a standard, but several providers have in fact agreed on a set of JMS properties that maps to a soap world, so it is actually quite interoperable.

This works fine for most Java implementations, but the .NET world has (to my knowledge) been left out on this option for a while.
Well, today I noticed an interesting thing in the Websphere MQ 7 documentation which apparently has support for hooking in WCF services/consumers to the Soap/JMS space. IBM has implemented transport interceptors that could be configured on WCF components. These are bundled with the MQ7 client and as far as I can see does not change either the MQ setup or your .NET code.

http://publib.boulder.ibm.com/infocenter/wmqv7/v7r0/topic/com.ibm.mq.csqzav.doc/un12000_.htm

To me this is very good news as that makes Soap through JMS a valid alternative to the quite complicated stacks above even when you're looking for Java-WCF interoperability and guaranteed deliveries, given that IBM WMQ is already a part of your infrastructure.

Once again messaging comes to the rescue! Either as the actual transport layer or as a building block for enabling WS-Reliable Messaging.

Now I just have to bribe some .NET programmer to hook up with for a lab since my .NET skills are, lets say.. nonexistent at the moment

fredag 19 november 2010

Comparing OSS offerings, like comparing apples to oranges

Rounding up the OSS integration frameworks described earlier is not easy and by no means a task of selecting an overall "winner". I've only scratched the surface on them, and most of the experience comes from testing simple samples, reading forums and blogs and in some cases implementing small solutions. There are also a bunch of frameworks that I haven't had time to test yet, so I'll focus on Mule, WSO2 and Apache Camel. Note that these are my personal reflections and experiences, so if you disagree completely, feel free to post so and call me a moron (maybe you're right :-)

Mule ESB
Marketed as the "most popular" open source ESB this was a good alternative to start with.
Mule is quoted as a stand-alone ESB and offers a wealth of connectivity options. The Mulesoft company behind it are very commited to the product and posts regular updates to the documentation as well as blogs.
However, the configurations are all designed by editing a quite cumbersome XML files which might offput some users wishing for less "bracket coding". Editing these files is only more constrained by the amount of schemas that needs to be included, i.e. each transport has its own schema and restrictions.
It supports a stand-alone runtime, hot deployments and extra functions such as registries and management consoles if you opt for the Enterprise license.
Mule was not created with EIP in mind from the startup, but updates in the most recent version made it easier to design flows through the "flow" construct even though I've already found some bugs while using it.

WSO2 ESB
Out of the three, wso2 is the only one that requires sort of an application server to run in the form of the Carbon server.
However, the management console is outstanding with its included support for statistics and registry. You also have the option to graphically design your integrations which is always good for beginners.
There are three things that bother me with WSO2 at the moment though:

- Big focus on the WS-stack, which is not surprising given the WSO2 team background. If you're after a webservice framework, this product is perhaps the most promising of the three, but as far as I see it might not be perfectly suited for other integration scenarios.

- Synapse. WSO2 is built upon Apache Synapse, a project that doesn't have as much community activity as the other two alternatives. Only the future will tell if it will grow in the same pace as the other ones, but I'm at least a bit concerned about its future.

- The need for an application server
This might be a political issue, but I'd think it will be more difficult to sell in a new application server to your management than a simple API runtime. Other might see this as a strength, but when you're already sitting on a stack of servers you'll undoubtley will get the question why you'll need another one.

Apache Camel
The most lightweight alternative of the three I've tested and probably the most flexible as well.
Since Camel is built as an implementation of the EIP patterns it fits right in to creating integration flows, which is the logical way of implementing integration.
With Camel you get alternatives wherever you go. Do you wish to develop your flows through XML? Or maybe java? Or perhaps Scala or Groovy? Would you like to execute it in a spring environemnt? Or as a routing component inside the ServiceMix OSGi runtime? Or inside a web application? Options everywhere... Which is acutally a good thing! Hopefully your team and organisation can settle with one and develop best practices using the one you prefer. Otherwise you could end up with a mess of implementations, but this holds true for all types of development environments, so its not a problem per se.

The only downside I could possibly think of when using camel is that since it's so easy to use you might start putting integration logic all over your projects instead of at a central ICC team of integrators and designers. Integration is a very complex area and should be handled by dedicated staff with end-to-end focus in mind. Camel with it flexibility and pragmatic approach might lead you to solving integration tasks as part of application projects, but as you can see I'm only nitpicking for a possible future problem here.

I especially like the fact that they've started to experiment with Scala as a a first-class citizen as I personally see a great future in Scala. Having this support from the start gives me hope that this component will have a long future even after Java has been declared as "dead" or legacy.

As noted these are just my first impressions of the frameworks and I might be proven wrong or have missunderstood some parts of them, so take these words with a grain of salt.
There are also a lot of alternatives that I haven't been able to try out extensively yet, for example JBoss ESB, ServiceMix and Spring Integration 2.0 which looks promising. So many toys, so little time...

See you soon!

onsdag 17 november 2010

Climbing the Camel


I remember my first ride with a live camel during one of our family vacations half a lifetime ago. It was a quite challenging task just to get up on the beast, and even hairier when this huge animal started to move. Rocketing back and forth it eventually managed to instill some sense of trust as it started to swaggle on with me sitting high atop on its back. After the first terror waned, the experience was actually simply a blast!



Well, recently I had the chance to climb up to the camel's back again, but now in another context. This camel was maybe even more scarier as I had never seen something quite like it and I was first startled by its complexity. But again, once it started moving I understood the pure beauty of the beast and felt safe and secure again.

I'm of course talking about Apache Camel, the lightweight OSS framework for designing and executing integration flows. It takes a pragmatic aproach to integration and has a very clean and efficient way of defining your integration logic between separate endpoints.
Camel is all about lightweight integration, and even though it does not qualify as a complete ESB since it misses some important parts such as manageability and hot deployments of your solutions, it certainly has some features which puts it right into the Enterprise integration space.

First of all one has to understand that camel is not an integration product per se, but rather an API for defining integration patterns. It does not execute by itself but should preferably be bundled together with some existing hosting environment i.e. JBI, Spring applications, your messaging engine, an application server or what not.

Setting up a Camel project is easy, since you could start out from Maven archetypes found on the Camel website. These will help you download all dependencies and create your Spring context. Camel does not force you to use either Maven or Spring, but much of the samples and tutorials on the net (and the documentation) assumes that you're already an experienced Maven/Spring user. After passing these first hurdles (which really had mostly to do with setting Maven up correctly) I was able to try out my first flows.

You have several options for choosing how to define your integration logic. The two major ones are through either Spring xml files similar to i.e. Mule ESB or a fluid Java API. There are also options for Scala and Groovy if that's your fashion. No matter which, the flow executes the same way as the design languages are only a means to model your integrations.

This separation is quite brilliant as it allows you to select the technology you are most proficient with, and the runtime will adapt. It also means that cross-functions such as automatic documentation is supported no matter which language you choose.

Our first flow


So, enough babbling. Lets have a look at an example:


public class ExampleRouteBuilder extends RouteBuilder {

/**
* A main() so we can easily run these routing rules in our IDE
*/
public static void main(String... args) throws Exception {
Main.main(args);
}

/**
* Lets configure the Camel routing rules using Java code...
*/
public void configure() {
from("jms:queue:purchaseOrder?concurrentConsumers=5")
.to("log:fromJms")
.split().xpath("//lineItem")
.choice()
.when(body().contains("Pen"))
.to("jms:queue:Pencils")
.when(body().contains("Paper"))
.to("jms:queue:Papers")
.otherwise()
.to("file:target/messages/invalid");
}
}

So, what is going on here?
Well, the first thing you'll notice is that we're extending the RouteBuilder abstract class and overide its configure() method. RouteBuilders are classes that configure your integration flows, or "routes" in camel language. The route itself starts with the from() method call and is described by chaining methods together.

Regular code completion assist then shows you which types of "Processors" you can apply to the route. A processor is basically some part that does something with a message exchange in a pipe and filter architecture. Apache comes bundled with processors for most of the EIP patterns such as the split defined in the example above, but you can of course add extra processors by just implementing the org.apache.camel.Processor interface or by sending the message to a spring bean method.

As you can see we've managed to include at least 4 EIP patterns in just a couple of lines (tecnically just one line of java, but you get the idea...) of code, namely the competing consumers, wiretap (the log endpoint), splitter and content-based router patterns. Now that's impressive!

The same flow could as stated above be modeled using XML in a Spring-like fashion by just including the Camel namespace and using content-assist in your favourite XML editor with the exact same outcome, so it's up to you to decide which method that suits you best.

Transports

Camel has the concept of adressing endpoints as URI's with the endpoint type first followed by the address and optional parameters on a query format. In our example we're instructing the route to use 5 concurrent threads to get the messages from the purchaseOrder jms queue.

The API relies on third party providers to implement the endpoint factories called components, so for our jms provider we could bind the jms transport to a component realised by i.e. Websphere MQ. This could either be performed by declaring the component through code, or as below as a spring bean in your context configuration.

<bean id="jms" class="org.apache.camel.component.jms.JmsComponent">
<property name="connectionFactory">
<bean class="com.ibm.mq.jms.MQXAQueueConnectionFactory">
<property name="hostName" value="localhost"/>
<property name="queueManager" value="QM_ESB"/>
</bean>
</property>
</bean>

This snippet declares that the MQXAQueueConnectionFactory should be the queueconnectionfactory for our jms endpoints. Just make sure that the application user has access rights to the queue manager by including the user either in the mqm group or some other group with connect/read access.

You could also define your endpoints as beans in the Spring XML file and just reference them by name, making the actual endpoints changeable depending on i.e. your different test environments setup.

So you could define your endpoints in a Camel context xml as:

<camel:endpoint id="PurchaseOrders.IN" uri="jms:queue:purchaseOrder?concurrentusers=5"/>

.. and then just reference this endpoint in your route as:

from("PurchaseOrders.IN")

This gives you a very good flexibility for choosing the actual endpoint location and even transport outside the actual flow.

Other cool features that Camel brings are for example

- Automatic type conversion:
Note how we could just use an Xpath expression even though we did not know the exact inbound object format? Camel automatically type converts between a bunch of different standard formats so you dont need to know whether the data is delivered as i.e. a bytearray, string, jaxb objects, xml stream etc.
If you don't find support for your particular format you can always write your own converters and easily plug these in to the runtime.

- A bunch of transport components out of the box:
We only saw two very common components in the example, but have a look at the http://camel.apache.org/components.html and you'll find that even the most obscure transport options are available.

- Bean support for i.e. defining a Spring bean as a service.

So, this was just a quick intro on the capabilities of Camel. I advise you to take a look at the number of articles written about it and get a feeling for this awesome framework at http://camel.apache.org/articles.html

'til next time,

Over and out!