Clojure Scripting in Vaadin
Introduction
Since Vaadin runs (partially) server-side, it is theoritecally possible to implement GUI logic in any language that runs on Java VM as a scripting extension. In this article, I will provide an example and proof of concept implementation based on Clojure (Jython, JRuby, Beanshell, etc. -based implementations could probably be also possible using this technique).
Clojure is a Lisp dialect, which runs on Java VM. More information is available at Clojure web site.
Vaadin/Grails integration is far more advanced example of scripting in Vaadin.
Implementation
This implementation serves only as an example and proof-of-concept rather than final, production-ready solution.
The implementation is based on:
- simple servlet, which provides Vaadin-Clojure bridge
- web.xml descriptor, parametrising above servlet
- example clojure App, written entirely in Clojure
The servlet
The implementation is really straightforward:
package com.example.testvaadin;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import clojure.lang.RT;
import com.vaadin.Application;
import com.vaadin.terminal.gwt.server.AbstractApplicationServlet;
public class Clojure4Vaadin extends AbstractApplicationServlet {
@Override
protected Class<? extends Application> getApplicationClass()
throws ClassNotFoundException {
return Application.class;
}
@Override
protected Application getNewApplication(HttpServletRequest request) throws ServletException {
try {
//load script, with name provided as a servlet's parameter
RT.load(getServletConfig().getInitParameter("script-name"), true);
//run Lisp function
return (Application)RT.var(getServletConfig().getInitParameter("package-name"),
getServletConfig().getInitParameter("function-name"))
.invoke(new String[0]);
}
catch (Exception e) {
throw new ServletException(e);
}
}
}
web.xml
web.xml descriptor is as simple as servlet implemenation. It only provides mappings and parameters to the servlet and was generated using Vaadin Eclipse plugin.
<?xml version="1.0" encoding="UTF-8"?> <web-app id="WebApp_ID" version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"> <display-name>testVaadin</display-name> <context-param> <description>Vaadin production mode</description> <param-name>productionMode</param-name> <param-value>false</param-value> </context-param> <servlet> <servlet-name>Lisp</servlet-name> <servlet-class>com.example.testvaadin.Clojure4Vaadin</servlet-class> <init-param> <param-name>script-name</param-name> <param-value>test</param-value> </init-param> <init-param> <param-name>package-name</param-name> <param-value>test.tlp</param-value> </init-param> <init-param> <param-name>function-name</param-name> <param-value>main</param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>Lisp</servlet-name> <url-pattern>/*</url-pattern> </servlet-mapping> </web-app>
The application
Finally, the interactive Clojure application, which displays notification "test" when user clicks on a button labeled "button":
(ns test.tlp)
(defn main [args]
(proxy [com.vaadin.Application] []
(init []
(let [app this]
(.setMainWindow this
(doto (new com.vaadin.ui.Window "Test application")
(.addComponent
(new com.vaadin.ui.Label "Hello Vaadin/LISP user!"))
(.addComponent
(doto (new com.vaadin.ui.Button "button")
(.addListener (proxy [com.vaadin.ui.Button$ClickListener] []
(buttonClick [event] (. (. app (getMainWindow)) (showNotification "test")))))))))))))
And that is it.
