For one of the projects that we have at Liip we use the Jackrabbit Content Repository server which is implemented in Java. As a way to gain a deep understanding of its APIs and functionality I decided to write a Clojure wrapper for it. The idea was to be able to work in the JVM without the need to use Java (the language) itself. Also since sometimes we need to debug the repository behavior it should be quite nice to use the Clojure REPL to interact with it in the same way you use mysql on the command line. Another colleague liked the idea and joined the hackday. We found that there was some work done already in this area so we forked this project https://github.com/jukka/cljcr and added more functionality to it.
The cljcr project only handled how to connect with an embedded Jackrabbit repository but we wanted to contact the repository using its RMI API. We fired up Emacs and Swank Clojure and started hacking in our project. One think we really liked about this approach was that by using Clojure's REPL we could really develop in small iterations. Once we got something worked in our REPL it was then just a mater of copy pasting that code inside a function declaration.
For example if we wanted to create an instance of the SimpleCredentials class we typed the following in the REPL:
user=> (import âjavax.jcr.SimpleCredentials)javax.jcr.SimpleCredentialsuser=> (SimpleCredentials. âusernameâ (.toCharArray âpasswordâ))#<SimpleCredentials javax.jcr.SimpleCredentials@50fa70a4>
Then it was a matter of adding this function to our cljcr.rmi namespace:
(defn get-credentials [username password]Â (SimpleCredentials. username (.toCharArray password)))
While this is a fairly simple example you can already see that Clojure is much less verbose than Java (something that's not so hard to achieve BTW). Also even if you don't know Clojure at all you may already see what's going on in that code. We define a function called get-credentials which gets two parameters username and password, and then uses them to get a new instance of SimpleCredentials. The dot character . at the end of SimpleCredentials is a shortcut from writing new SimpleCredentials (which you could do if you wanted). Another interesting bit of syntax that shows how simple is to interoperate with Java from Clojure is the code:
(.toCharArray password)
There password is a String and we invoke the method .toCharArray on it using syntax that just looks like normal function invocation in Clojure. As you may have guessed the return of that function call will be passed to the constructor of SimpleCredentials. as the second parameter.
In Jackrabbit once you have a repository instance then you may want to get access to what's called the session. To do that you will invoke the method login in the repository object passing the SimpleCredentials instance and an optional workspace string. Take a look at how by using a technique similar to method overloading we can have this nice syntax for the optional parameter:
(defn get-session ([repo creds]   (.login repo creds)) ([repo creds workspace]   (.login repo creds workspace)))
So our get-session wrapper has two cases: when it gets 2 parameters: repo & creds; and when it accepts 3 repo, creds & workspace. As you can see in that code we don't need to have messy if/then/else statements. We just handle both case by separate stating quite clear what we want to execute in each case. (In case you wonder, yes you can use if/then/else in Clojure).
Once we had the whole wrapper ready we proceeded to write a small CLI utility where we could pass a Jackrabbit SQL2 or XPath query and get the results pretty printed on screen. You can see the results of that experiment on github.
The main part of the code is our -main function:
(defn -main [& args] (ccl/with-command-line args  âCommand line demoâ  [[url âRepository URLâ âhttp://localhost:8080/rmiâ]   [username u âUser Nameâ âadminâ]   [password p âUser passwordâ, âadminâ]   [workspace w âJCR Workspaceâ]   [sql? âSets query as JCR_SQL2â true]   [xpath? âSets query as XPATHâ]   [query q âQuery to executeâ]]  (let [qtype (if sql? :sql :xpath)     nodes (utils/run-query url username password workspace qtype query)     ]   (pprint/pprint (utils/node-properties nodes)))))There we use the âwith-command-lineâ macro that will handle the process of parsing CLI arguments for us. In that case we expect to get values for the url, username, password and so on. If the value is empty, then we assign some default values and even some help text for the user of our library. Once we got the arguments from the CLI we call the function ârun-queryâ using those parameters. From there we call Clojure's pretty print library using a helper function ânode-propertiesâ that we wrote to extract the properties of the node and them to a map. Again look at how short that function is:
(defn nodes-properties [nodes]Â (map #(jcr/get-property-map (jcr/properties %)) nodes))Here we just declared an anonymous function in place and passed it as the first argument of map. The second argument is the nodes sequence that we want to iterate on. Something we really liked during the workshop is how terse the resulting code is when using powerful languages like Clojure.
Once we got our CLI tool working we still had 50 minutes to go in our workshop so we decided to give a try to the Noir web framework http://webnoir.org/ and see how far we could reach into implementing the same CLI functionality but in the browser. We managed to get the basic Noir installation in place and from there be able to render a JCR node in the browser.Â
All in all we were quite happy with all we could achieve while learning new technologies like Clojure & Jackrabbit. A good selling point from Clojure is that by being hosted on the JVM you get immediate access to a whole set of libraries for nearly anything you may want to do. Another interesting point that basically part of every decent functional language is the use of a REPL where you can experiment directly while coding thus reducing time spent from conception to implementation. All in all it was very fun to work in this.