as usual when you change company, you change also the technology stack. Starting from April 10th I start working in BBC and, after the first week, I start working with Apache Camel, and even if I am new to this technology, it is quite simple to learn and enough powerful. So, after few weeks, I am kind of reference for it and I decided to write this post to speak about it. Of course I am still noob, so the post may be incorrect in some details, but eventually users with experience can leave comments.
What is Apache Camel? You can find several definitions, like here, but I want to give you mine. Camel is a grandson of BPEL, it is addressing the same problem: describe a business process and wire it to external services. For doing so, Camel has a DSL (Scala like) that describes how your request is processed in terms of constructs like when, filter, process, split, log and others and it let’s you define your wiring points in term of two constructs, from and to. You can basically wire lot of technologies (full list here) as source or destination to your process: from simple files to AWS sqs, Cassandra, Kafka, FTP but also more specific vendor technologies like Splunk, ElasticSearch, GMail, Facebook API…
And this is one of the several magic that makes this library very very nice, because by just switching the input URI for an endpoint, you can change the technology from (or to) which you are exchanging messages. This is not only very very good for changing the technologies whenever you need to, but it is also wonderful for testing, because by just changing the property file you can go from sending messages to a queue to send them to a file. For the most curious readers of this post, Camel is implementing most of the Enterprise Integration Patterns (EIPs) described in the Bible of this topic, that is Enterprise Integration Patterns: Designing, Building, and Deploying Messaging Solutions.
How does it work? It is simple: you create a CamelContext, the runtime system for Camel, you add Endpoints and Components (components here are somehow endpoints factories), you add routes to connect the endpoints (a route in Camel is the definition of your business process, the definition that you can write in the scala-like DSL with process and filter elements as discussed above), you invoke the start() method and that’s it! For helping you doing all of this, Camel has integration with the most used frameworks for IoC and Dependency Injection (Spring, Guice…).
When a message arrives in the from endpoint, Camel encapsulates it in an Exchange object that is intended to keep an incoming message, its final reply or the eventual Exception that represents a fault message. There is an implementation of the Message interface specific for any technology from (or to) which you can exchange messages, and there is an implementation of Exchange interface for such messages. The Exchange message is passed through the whole state machine, so, for example, you can add properties to it to store information related the whole computation, like metrics or other.
Last but not least, most of the interfaces related to the composing blocks of a route (like the process or the filter blocks already mentioned) are Functional Interfaces, so if you are using Java8 you can implement them as lambdas.
Did I spot any drawbacks? Honestly, if I was in my previous company, I would have suggested to use this library immediately: we had lot of problems, or better, lot of code for integrating with the different technologies (like kafka, kinesis or other endpoints). But yes, there is a drawback that I already found in these few weeks, and it is the same drawback that is present in all the business definition/state machine libraries: it is difficult to balance how much description goes into the route and how much goes in the single block of the process. As you can imagine the route blocks are encapsulating the usual blocks, like loops and filters, so you can basically write all your program in terms of those blocks, but this ends up being a huge route, probably full of lambdas. On the other side you could write very small routes like from(endpointA).process(myProcessorImplementation).to(endpointB) but like that you are using Camel only as a wiring framework, and you are losing the possibility to understand what is happening from the route.
To keep a good balance (and to agree with colleagues about that) is not totally straightforward. But I would say this is not a big issue to avoid using the library.
As an introduction, that’s all. Stay tuned!