Posts Tagged ‘proxy’

Writing Spring MVC controllers in Clojure

December 4, 2009

Lately, I’m getting more and more absorbed by Clojure. The project I am working on, is a program that helps you solve Sudokus. Not that I like Sudokus, but it’s definitely fun reasoning about them. And reasoning about them in Clojure is even more fun. But that’s not the subject of todays post.

Today, I want to write about writing a web interface in Clojure. In the end, the Sudoku solver needs an interface. Let me first explain you my basic thoughts on web application development.

  1. Separating view and controller is a good thing. I don’t want controller logic in my view. I don’t want styling issues in my controller. Compojure seems like a good and straightforward library, but I do not get the impression that it makes separating view and controller very trivial.
  2. JSP is not evil. I’ve used JSP for many years. I know its ins and outs. As long as you do NOT use scriptless (does anyone still today?), it’s a plain language for defining a view. It has many tag libraries already available. Views in JSP and controllers in Clojure seems a perfect combination to me. Sorry, that makes me skip Conjure too, though it does look promising.
  3. Reinventing the wheel is a bad thing. You don’t write a web framework from scratch. There are many good web frameworks available. Spring MVC is a good web framework. It’s easy to use. It’s stable. I know how to use it.
  4. Clojure is Lisp plus Java. The whole point of using Clojure, is that it makes you access Java Code from Lisp. I want to use existing Java Code. Wasn’t that the whole purpose of Clojure? If not, why would you move from plain old Common Lisp to Clojure anyway?

So, we’ll use Spring MVC as a framework. The views are written in JSP, with Spring MVC tag libraries available. And we’ll write the controllers in Clojure. How do we combine them? Let’s find out.

Hooking into Spring MVC

We enable Spring MVC in a Java Web application, by including the Spring dispatcher servlet in our web.xml. Incoming http requests are then handled by the dispatcher servlet. The dispatcher servlet does basically the following:

  1. The dispatcher servlet sends the request to the proper controller. What request is sent to what controller, is defined in a UrlHandlerMapping.
  2. The dispatcher servlet retrieves a model and a view name from the controller. The servlet sends the model to the view specified by the view name.

The view is plain old JSP. For the second step, we can use a plain old InternalResourceViewResolver. Nothing clojurish there.

The exciting part comes in the first step. The code that returns the model and the view, is written in Clojure. So we must make sure, that the UrlHandlerMapping maps the request to a Clojure controller.

Spring MVC has a number of UrlHandlerMapping implementations readily available. My favourite one is the DefaultAnnotationHandlerMapping. It lets you annotate a method with a url pattern, and then it becomes a controller method. Like this:

@RequestMapping("/hello.html")
public ModelMap sayHello(@RequestParam("name") String name) {
    return new ModelAndView("hello", "model", name);
}

It’s something similar I want to do in Clojure. I want to define a clojure function, and annotate the url pattern and request parameters. Clojure allows us to define plain old Java Classes. So, what if we just create the equivalent of the above in Clojure? Then we’re done.

Unfortunately, Clojure has no support for annotations (yet). This is not a bad thing for programming in Clojure itself. You do not really need annotations in Clojure, since Clojure gives you much more powerful language constructs. But for programming Clojure, you don’t need Java classes either. The whole purpose of using Clojure instead of Common Lisp, was the availability of Java! So it is actually bad that annotations are not supported.

Of course, we could create controller classes in Clojure, and map them in the Spring configuration file. But that’s not what I want. I want to use the full power of Clojure not only for writing the controllers, but also for configuring them. So we have to make up a trick.

What if we write our own UrlHandlerMapping? We’ll let our implementation retrieve the mapping information from Clojure code, and let it forward the request to Clojure code. Of course, our UrlHandlerMapping implementation itself is written in Clojure.

Let’s write a prototype, to see that the approach indeed works.

Building a prototype

The UrlHandlerMapping we’ll build here, is just a simple prototype. It will map two hard coded paths to two hard coded views. The code is not elegant. But it does prove that we can easily plug Clojure into Spring MVC. And the prototype can be used as a starting point for something more general.

Each clojure file is compiled into a single class file. The top of a clojure file defines a namespace. The name of the clojure namespace is the Java fully qualified class name. To implement our own UrlHandlerMapping, we must extend the Spring MVC AbstractUrlHandlerMapping. We’ll also need some imports later on. So here’s the start:

(ns com.vxcompany.clojuremvc.UrlHandlerMappingPrototype
  (:gen-class
   :extends org.springframework.web.servlet.handler.AbstractUrlHandlerMapping)
  (:import
    [org.springframework.web.servlet ModelAndView]
    [org.springframework.web.servlet.handler AbstractUrlHandlerMapping]
    [org.springframework.web.servlet.mvc AbstractController]))

I know. Clojure code can be very short and elegant, but explicitly defining Java classes in Clojure is definitely not. Luckily, this is the only Java class that has to be explicitly available from outside our Clojure library.

To register controllers with the AbstractUrlHandlerMapping, we have to call the registerHandler()-method. The method takes two arguments: a url pattern and a controller. The url handler is a String. The controller is a subclass of the AbstractController class. Creating the controller is easy. Just use the (proxy) function in Clojure. The controller implements the handleRequestInternal()-method, that implements the controller method.

(.registerHandler this "/index.html"
  (proxy [AbstractController] []
    (handleRequestInternal [request response]
      (ModelAndView. "index" "info" "Clojure has done it!")))

AbstractController is the class we want to proxy. [] is a list of empty constructor arguments. handleRequestInternal (that takes a request and a response) is the method we are implementing. And (ModelAndView.) calls the constructor of the ModelAndView class, with three arguments.

The above code maps requests to “/index.html” to the specified controller, that forwards to the index-view, with the text “Clojure has done it!” in a model variable named “info”.

The above code must be executed on construction of the UrlHandlerMappingPrototype. Clojure has two constructs for initialising a class. With :init, you can specify the parameters for the constructor of the superclass. Optionally, :init lets you specify a Clojure variable that contains state information for the object. Within :init, you cannot yet access the this object, since it has not been constructed yet. For that, we need the :post-init. Between :extends … and the right bracket, write:

:post-init post-init

This defines that post initialisation of the class is defined in the -post-init function (the minus symbol is the default symbol for functions implementing a class method). Type (doc gen-class) at the REPL if you want to know more about class definition options. Remember, the REPL and the (doc) function are sometimes bigger friends than Google.

The full class is now:

(ns com.vxcompany.clojuremvc.UrlHandlerMappingPrototype
  (:gen-class
    :extends ...     
    :post-init post-init)
  (:import ...))

(defn -post-init [this]
  (do
    (.registerHandler this "/index.html"
      (proxy [AbstractController] []
        (handleRequestInternal [request response]
          (ModelAndView. "index" "info" "Clojure has done it!"))))
    (.registerHandler this "/another.html"
      (proxy [AbstractController] []
        (handleRequestInternal [request response]
          (ModelAndView. "another" "info" "Clojure has done it again!"))))))

Remember that instance methods (like -post-init) take this as their first argument.

Glueing the pieces together

We wrote the implementation for the UrlHandlerMapping. We still have to create a Spring MVC project, with the UrlHandlerMapping in it. In Netbeans, using the Enclojure plugin, I did:

  1. Create a new Clojure project. Include the Spring Framework, Spring Web MVC and Servlet-API libraries. Define the single class UrlHandlerMappingPrototype.
  2. Create a separate Spring MVC project. Include the Clojure library, and the library (compiled jar) for the Clojure project. Create two views index.jsp and another.jsp, that show the contents of the variable ${info}. In your web.xml include the dispatcher servlet. In the dispatcher-servlet.xml set up an InternalViewResolver.
  3. Tell the Dispatcher Servlet to use the UrlHandlerMappingPrototype. Remove other UrlHandlerMappings. Include the following in your dispatcher-servlet.xml:
<bean class="com.vxcompany.clojuremvc.UrlHandlerMappingPrototype"/>

That’s right. A single line in your dispatcher-servlet.xml does everything. Now run the application and surf to ../index.html and ../another.html, and see that it works.

Is that it?

This is just the beginning. The Clojure code we wrote is very verbose. It does not look as nice as the annotated Java method we had earlier at all! The next step is to put the boilerplate code in a reusable element, so we can just specify the url pattern and the handler method. In Java, we used existing classes and annotations as reusable elements. In Clojure, we have something much better. I’ll use the above code as an example why Clojure’s macros are so powerful. But that’s something for another post. In the meantime, enjoy writing your controller methods in Clojure!