pseudofish

powered by text files

programming

Learning Clojure with Google App Engine and Emacs

This is an overview to my attempts at getting Clojure with Emacs. Inspired by this post, I set out to learn three things simultaneously: emacs, clojure and Google App Engine.

For comparison, my current web prototyping combination is TextMate, Rails, and Heroku. Prior to that it was a mix of python, php or perl, with vim.

There are already number of articles on getting GAE and Clojure to work. Consider this me making notes for myself because I keep forgetting the Emacs shortcuts!

Emacs

I settled on Aquamacs to start out with emacs on the Mac. It seems to be more forgiving if I use normal Mac keyboard shortcuts while I learn emacs keys. Also makes it easy to switch between it and TextMate.

The other feature I love is full screen mode: ⌘-Shift-Return

To get command line access, you need to go to Tools->Install Command Line Tools. This gives you an “aquamacs” shortcut in the shell. I aliased it to “aq.

For some help on learning emacs, consider:

You may also want to setup Clojure to run with Emacs. This article assumes you are using lein.

Google App Engine (GAE)

The GAE distribution is available here: GAE Download.

I setup my shell to include a $GAE_BASE directory for where I unpacked it, and added $GAE_BASE/bin to my path.

Creating a Clojure Project

The first post I read assumed that you were starting with a manual layout of your project. I’m going to use lein, a build manager for clojure, similar to rake for ruby. Behind the scenes lein uses Java’s maven as a package management system (similar to gems).

To make things a bit more interesting, I plan to write a very basic CMS to explore the various APIs. I’m keeping everything on the githubs.

The steps to getting setup look something like:

$ lein new gaecms
$ mkdir -p war/WEB-INF

Then make some changes to your project.clj file:

(defproject gae-cms "1.0.0-SNAPSHOT"
  :description "A basic CMS built on Google App Engine (GAE)"
  :dependencies [[org.clojure/clojure "1.2.0"]
                 [org.clojure/clojure-contrib "1.2.0"]
                 [compojure "0.4.1"]
                 [ring/ring-servlet "0.2.1"]
                 [appengine "0.4-SNAPSHOT"]]
:dev-dependencies [[leiningen/lein-swank "1.2.0-SNAPSHOT"]]
:compile-path "war/WEB-INF/classes"
:library-path "war/WEB-INF/lib")

To save some typing, you can clone: git://github.com/gmwils/gaecms.git

To run the interpreter locally, try the following:

$ lein deps
$ lein swank

To test out that the interpreted mode is working, open up src/gae_cms/core.clj in AQ.

Then connect to the server:

M-x slime-connect

From within the editor, you can now run either of the following:

C-x C-e    % evaluate current line
C-c C-k    % compile the current file

You also have an interactive clojure shell for typing commands into. Try adding the following into your source code and then pressing C-x C-e to evaluate:

(System/getProperty "java.class.path")

You should see your current CLASSPATH printed out.

Setup for GAE

In $HOME/war/WEB-INF/web.xml map the URLs that you want your custom servlet to handle. In this case, send everything into the servlet:

<?xml version="1.0" encoding="ISO-8859-1"?>
<web-app
  xmlns="http://java.sun.com/xml/ns/javaee"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
  version="2.5">
  <display-name>CMS on GAE</display-name>
  <servlet>
    <servlet-name>cms</servlet-name>
    <servlet-class>gae-cms.core</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>cms</servlet-name>
    <url-pattern>/</url-pattern>
  </servlet-mapping>
</web-app>

In $HOME/war/WEB-INF/appengine-web.xml add the following to setup Google App Engine to refer to your servlet above.

<appengine-web-app xmlns="http://appengine.google.com/ns/1.0">
  <application>cms-clj</application>  <!-- GAE app id for your app -->
  <version>v0-1</version>  <!-- Arbritrary Version Id -->
</appengine-web-app>

Next, update src/gaecms/core.clj with:

(ns gaecms.core
  (:gen-class :extends javax.servlet.http.HttpServlet)
  (:use
    compojure.core
    [ring.util.servlet :only [defservice]])
  (:require [compojure.route :as route]))

(defroutes cms-public
  (GET "/" []
    "<html><title>GAE CMS</title><body><h1>Hello World!</h1></body>")  )
(defroutes cms
  cms-public
  (route/not-found "Page not found")) ; 404 error page

(defservice cms)

To test this locally, try:

$ lein deps
$ lein compile
$ $GAESDK/bin/dev_appserver.sh war

Deploying to Google

First go to the GAE console and create an application. The following should then work:

$ lein deps
$ lein compile
$ $GAESDK/bin/appcfg.sh update war

I’m still playing with getting it working with Google App Engine. The above is enough to get hello world working.

For more details, I suggest you follow the Compojure on GAE blog. Specifically, the article on Deploying to App Engineis a good overview.

Next steps include getting interactive development working with GAE, and actually handling dynamic content.