Monday, June 7, 2010

Using Apache Camel from Clojure

I've been looking at Apache Camel for a project at work, and had a bit of trouble getting it working from Clojure, so I wrote this up in case anyone has the same issues.

The first example in Camel in Action watches a directory for new files, and copies them to an output directory. Here are the steps to get that running in Clojure, using leiningen.

  • Create your input and output directories
  • Create a new leiningen project
  • Add the following to the project.clj


(defproject camelFileCopy "0.1.0"
:description "Apache Camel File Copy example in clojure."
:main org.whitlark.fc
:dependencies [[org.clojure/clojure "1.1.0"]
[org.clojure/clojure-contrib "1.1.0"]
[org.apache.camel/camel-core "2.3.0"]
[org.springframework/spring "2.5"]
])
view raw project.clj hosted with ❤ by GitHub


  • run lein deps
  • Add the following to your src/org/whitlark/fc.clj (or whatever your last name is ;-)


(ns org.whitlark.fc
(:import [org.apache.camel.impl DefaultCamelContext])
(:import [org.apache.camel.builder RouteBuilder])
(:gen-class))
(defn -main [& args]
(let [context (DefaultCamelContext.)]
(.addRoutes context (proxy [RouteBuilder] []
(configure []
(.. this (from "file:/home/jw/scratch/inbox?noop=true")
(to "file:/home/jw/scratch/outbox")))))
(.start context)))


Part of what screwed me up was the fact that you need to include spring in the project in order to get camel to work properly.

You can also use a macro to make the code even cleaner, like this:

(defmacro defroute [context & body]
`(.addRoutes ~context (proxy [RouteBuilder] []
(configure []
(.. ~'this ~@body)))))
(defn -main [& args]
(let [context (DefaultCamelContext.)]
(defroute context
(from "file:/home/jw/scratch/inbox?noop=true")
(to "file:/home/jw/scratch/outbox"))
(.start context)))


Which I think compares nicely to the original Java:

public class FileCopierWithCamel {
public static void main(String args[]) throws Exception {
CamelContext context = new DefaultCamelContext();
context.addRoutes(new RouteBuilder() {
public void configure() {
from("file:data/inbox?noop=true")
.to("file:data/outbox");
}
});
context.start();
}
}


I'm sure there are more improvements possible, but this got me started.