clojure, emacs, and javadocs

In the course of my recent work, integrating various java libraries with clojure, I spent a lot of time going back and forth between emacs and firefox, just to read java api documentation. I even tried loading up the "All Classes" index from the java api docs in an emacs/w3m buffer and isearch-ing through it. It was a far from optimal experience, and I decided to hack something using clojure and slime.

Bill Clementson had posted a great intro to javadoc and clojure/slime, but I was looking for something that wouldnt' require me to leave emacs just to read documentation, and that too java api docs.

Ideally, I wanted to be able able to put the cursor on any java class symbol in a clojure-mode buffer in emacs, execute M-x slime-javadoc, and have the api documentation popup in an adjacent emacs window.

Turns out the hardest part of implementing this was in resolving an unqualified class name to its fully qualified form, before looking up its documentation path. For example,

(ns example
  (:import (java.util UUID)))

(defn uuid []  (.toString (UUID/randomUUID)))

Looking up the javadoc on UUID should really be on java.util.UUID, which clojure knows. So, the core of the hack is a clojure function, which takes the symbol at point ("UUID" in this case), and the current namespace ("example") and returns a fully qualified class name "java.util.UUID". That function, implemented as a slime command looks like the following:

(swank.commands/defslimefn resolve-symbol [sym ns-name]
  (when-let [the-class (ns-resolve (find-ns (symbol ns-name))
                                   (symbol sym))]
    (.getName the-class)))

Now all we need is emacs to clean up the symbol at point, and call this function via slime.

(defun slime-javadoc (symbol-name)
  "Get JavaDoc documentation on Java class at point."
  (interactive (list (slime-read-symbol-name "JavaDoc info for: ")))
  (or symbol-name (error "No symbol given"))
  (let ((class-name (slime-eval
                     (list 'resolve-symbol
                           (first
                            (split-string (trim-trailing-dot symbol-name)
                                          "/"))
                           (slime-current-package)))))
    (if class-name
        (browse-url
         (concat (javadoc-root class-name)
                 (subst-char-in-string ?$
                                       ?.
                                       (subst-char-in-string ?.
                                                             ?/
                                                             class-name))
                 ".html"))
      (message "No javadoc found for %s" symbol-name))))

The javadoc-root function is just a way to dispatch to different javadoc paths (local or online), based on the package names. For example, by defining:

(setq javadoc-alist
      '(("^\\(java[x]?\.\\|org\.ietf\.\\|org\.omg\.\\|org\.w3c\.\\|org\.xml\.\\)" .
         "file://opt/java/docs/api/")
        ("^org\.jets3t" . "file://opt/java/jets3t-0.7.0/api-docs/")
        ("^com\.xerox\.amazonws" . "file://opt/java/typica-1.5.2a/apidocs/")
        ("^org\.mortbay" . "http://www.mortbay.org/apidocs/")))

Now, emacs/w3m will load the right documentation, based on the class package prefix.

The code is available on github.

Unity.

cynojure.aws -- amazon web services from clojure

I've been using Amazon EC2, S3, and SQS services in various projects at work. For one project, I needed to build a little tool that integrated SQS and S3 services, and I decided to build it in Clojure. In the course of building the tool, I learned a bit about the various open source Java libraries for working with Amazon AWS, and the issues with integrating them with Clojure.

The libraries I used are:

Having been away from Java development for some time now, I'd forgotten about the convoluted mess of Classpaths and Class loaders. I had a "crash" refresher course in the last week. And, it's all still a bloody mess. I did come across one-jar, which made it pretty easy to package up the various jar dependencies into a single deliverable jar file.

In the end, the tool worked out well and served its purpose. Plus, it was rewarding to be able to write code like this:

(defun process-loop [:key
                     aws-access-key
                     aws-secret-key
                     geo-db-path
                     [message-count 5]
                     [sleep 5000]
                     sqs-queue]
  (with-geo-service (geo-get-service :path geo-db-path)
    (with-sqs-queue (sqs-get-queue aws-access-key aws-secret-key sqs-queue)
      (with-connection *db*
        (let [process (fn [msgs]
                        (if (empty? msgs)
                          (Thread/sleep sleep)
                          (try
                            (transaction
                             (doseq [msg msgs] (process-message msg)))
                            (doseq [msg msgs] (sqs-delete-message msg))
                            (catch java.sql.BatchUpdateException ex
                              (println "* process error:"
                                       (.getNextException ex))))))]
          (while true
            (try
              (process (sqs-receive-messages message-count))
              (catch Exception ex
                (println "* error:" ex)))))))))

and know it's running on the JVM.

I've committed some of the code for the Amazon integration into the cynojure git repository, in case anyone else finds it useful.

Harmony.

cynojure - clojure library on github

I finally got around to creating a repository for some of the Clojure code I'm developing on github. It's quite spare right now; just the Common Lisp like defun macro, a few odd helper functions, and the SQL query syntax I'd written about before.

The repository is online at http://github.com/kriyative/cynojure/tree/master.

I'm not all that happy with the SQL macros, but haven't had a whole lot of time to play with it. I've been too distracted with real work.