-
Notifications
You must be signed in to change notification settings - Fork 2
Home
Apache Camel is a routing engine written in Java, offering an intuitive and comparatively simple programming model based on custom annotations and a nice fluent API. Implementing most of the Enterprise Integration Patterns made popular in the seminal homonymous book it positions itself as a lightweight alternative to full-grown ESBs. In complex integration scenarios, Apache Camel aids in routing, splitting and aggregating incoming and outgoing messages.
CDI - Contexts and Dependency Injection - is an official standard specified in JSR 299 defining a modern DI container that builds on experience gained in e.g. Spring and especially Guice. It offers users type-safe dependency injection where type-safety is achieved by using annotations instead of string identifiers - which often tend to render refactorings unsafe and error-prone - to control which dependencies get injected into which injection points. Being part of the JEE 6 specification - though certainly usable outside a JEE context - it is fully interoperable with most JEE defined resources: session beans, servlets, servlet filters, JAX-WS endpoints, JAX-WS handlers and so forth may be injected into CDI beans and vice versa. A long-term goal of CDI is to offer a basis for unifying the JEE component model, envisaging a future where services like declarative transaction demarcation currently available exclusively to EJB components will be extended to CDI beans.
In a recent personal project I found use for both technologies, and having grown accustomed to CDI's simplicity I set out to lift Apache Camel into the world of CDI. My goal was and still is to make the services offered by Camel available in a CDI-friendly way. This overarching goal may be stated more precisely as:
- Make an application's
CamelContext
- Apache Camel's central runtime component - configurable via CDI. - Delegate discovery, instantiation and configuration of selected Camel resources -
RouteBuilders
,TypeConverters
and so forth - to the CDI container.
Luckily, CDI's Portable Extension mechanism aids in achieving these goals. Implementing a portable extension third parties may integrate deeply with a CDI container, observing and potentially modifying its lifecycle events as for instance CDI bean discovered
. And that's what CamelPE is at its heart: a Camel Portable Extension.
Today, CamelPE is still in a pre-release state, lacking mainly documentation and test coverage to be considered ready for primetime. Still, I have used it successfully in personal projects where admittedly I have utilized only a fraction of what Camel has to offer. Yet bear in mind that CamelPE plays no role in Camel's runtime behaviour, i.e. it does not alter its semantics in any way. CamelPE offers merely an alternative configuration mechanism, much in the same way Camel itself uses primarily Spring for this purpose. Consequently, once a CamelContext
is up and running, CamelPE's job is done.
Currently, CamelPE supports three major use cases:
Apache Camel was designed to be usable in a vast array of diverse environments, each of which may have special requirements that need to be fulfilled by Camel's runtime. For instance, auto-discovery of TypeConverters
and RouteBuilders
rests on Camel's ability to scan the classpath. By default, this capability is provided by DefaultPackageScanClassResolver
, the default implementation of the interface - you guessed it - PackageScanClassResolver
. Some application server environments, however, have special classloading needs that cause this default implementation to fail. CamelPE, therefore, defines an SPI - Service Provider Interface - that allows users to swap out default implementations of many core classes for custom ones tailored to the target environment.
CamelPE partially exposes this SPI to the CDI container. It achieves this by introducing a custom Qualifier net.camelpe.api.CamelContextInjectable
. A developer may annotate a custom implementation of one of Camel's SPI's as e.g. PackageScanClassResolver
and thus have it injected into the CamelContext
.
Currently, the list of supported SPIs comprises:
org.apache.camel.spi.ClassResolver
org.apache.camel.spi.DataFormatResolver
-
org.apache.camel.spi.ExecutorServiceStrategy
(No public link available) org.apache.camel.spi.FactoryFinderResolver
org.apache.camel.spi.InflightRepository
org.apache.camel.spi.ManagementStrategy
org.apache.camel.spi.PackageScanClassResolver
-
org.apache.camel.spi.ProcessorFactory
(No public link available) org.apache.camel.spi.ShutdownStrategy
For a brief usage example take a look here.
How can I have my Routes discovered, instantiated, configured and registered via our CDI container?
This is almost a no-brainer since CamelPE will scan each CDI-enabled module - those sporting a META-INF/beans.xml
file - for subclasses of Apache Camel's RouteBuilder
, instantiate and configure those like any other CDI bean, and will register the set of discovered RouteBuilders
in the CamelContext
immediately prior to starting it.
Maybe the only caveat you should be aware of is that you cannot make a RouteBuilder
@ApplicationScoped
since it does not declare a public no-args constructor and thus cannot be proxied. While this may seem conceptually dissatisfying - it certainly seemed so to me - in practice this should rarely if ever be a problem. Routes discovery and registration is a one-time process executed at system startup. So while not @ApplicationScoped
in the strict CDI sense, RouteBuilder
instances will nonetheless exist for the lifetime of the application.
For a brief usage example take a look here.
How can I have my Type Converters discovered, instantiated, configured and registered via our CDI container?
Easy. Just annotate your TypeConverters
with org.apache.camel.Converter
or org.apache.camel.FallbackConverter
and you are good to go. CamelPE will discover, instantiate and configure those just like any other CDI bean, and will take care of registering them in the CamelContext
.
You should, however, take care not to use Apache Camel's standard mechanism of listing packages containing TypeConverters
in META-INF/services/org/apache/camel/TypeConverter
. Otherwise, they will be registered twice in the CamelContext
, once by CamelPE and then again by Apache Camel's AnnotationTypeConverterLoader
. CamelPE does not disable the latter since it is required to load the set of built-in TypeConverters
which are essential to Apache Camel's working properly.
What may seem counterintuitive is that you have to apply org.apache.camel.Converter
twice, once on the class level and then again on the method level. While this is strictly speaking not necessary, it is in keeping with the restrictions imposed by Apache Camel itself, and I consciously chose not to relax this requirement.
For a brief usage example take a look here.
CamelPE's first release, CamelPE 0.1, will probably not offer any features beyond those already available. Instead, I will focus on
- adding more documentation, i.e. a user guide will probably prove helpful, and more and better javadocs are always an issue
- creating a distribution for those users that don't buy into Maven
- enabling the community to give feedback on bugs, feature requests and design considerations, as well as to send patches
- improving the test coverage
- cleaning up the code base and
- sorting out licensing issues.
Well, it largely depends on what the community deems desirable, to wit it depends on your needs. I hope for feedback from users to influence CamelPE's moving forward, especially since it already fully supports what little I need from Apache Camel.
That being said, I do have some ideas I would like to explore, namely:
- Support more and eventually all of Apache Camel's custom annotations as e.g.
@Consume
,@RecipientList
. Again, I would appreciate feedback on what you think would be the most useful additions in this area. - Support discovery, instantiation and configuration of
org.apache.camel.spi.DataFormats
. - Eventually I would like to support the whole range of Apache Camel's SPI, at least where it makes sense to provide integration with CDI.
- One of CDI's strong points is, in my view, its extensive support for event-based designs. Apache Camel defines a comprehensive set of lifecycle events observers may be informed about. It would be nice to have these automatically converted into CDI events.
Check out the source with
$ git clone git://github.com/obergner/camelpe.git
This will create a new subdirectory camelpe
in the current directory, containing the CamelPE multi-module project. In the toplevel module camelpe
you will find settings-sample.xml. Copy the profile net.camelpe.profile
into Maven's user-level settings.xml
, usually found in ~/.m2/settings.xml
. You need to do this because CamelPE does consciously not declare any repositories in its master pom. For an explanation for why this is usually (though not always) a bad idea look here.
Now, after
$ cd camelpe
you may build CamelPE with e.g.
$ mvn -Pnet.camelpe.profile clean install
and you're done. Note that building has been tested using Maven 3.0+. Older versions should work, yet YMMV.