dimanche 15 avril 2012


Injecting a Clojure REPL into your Existing Java Web app

What?

  • You develop an existing Java Web app
  • You would like to tinker with it using Clojure
  • And to connect to it from Emacs to mess around the live Web app
Let's do that!

The existing Java Web app

For this example, must be Mavenized, must have the Jetty plugin.
This maven archetype has that:
mvn archetype:generate \
-DarchetypeGroupId=org.cometd.archetypes \
-DarchetypeArtifactId=cometd-archetype-jquery-jetty6 \
-DgroupId=cljinject \
-DartifactId=cljinject
Check it's running correctly with:
cd cljinject
mvn jetty:run
You should have something on http://localhost:8080/cljinject

Add the clojars repository

Clojars is where all the Clojure goodies lives.
Add to your pom.xml:
<version>1.0-SNAPSHOTversion>

<repositories>
  <repository>
    <id>clojars.orgid>
    <url>http://clojars.org/repourl>
  repository>
repositories>

<build>


Add the swank-clojure dependency

This will allow to start a swank server from within the Web app.
Add to your pom.xml:
   
   
   <dependency>
     <groupId>swank-clojuregroupId>
     <artifactId>swank-clojureartifactId>
     <version>1.4.2version>
   dependency>
   
dependencies>


Create the ServletContextListener that will launch Swank

Create the class: ./src/main/java/cljinject/SwankServletContextListener.java:
package cljinject;

import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import clojure.lang.Compiler;
import java.io.StringReader;

public class SwankServletContextListener implements ServletContextListener{

    // keep a hand on the context so we can get it from within clojure
    public static ServletContext context;

    public void contextInitialized(ServletContextEvent contextEvent) {
        context = contextEvent.getServletContext();

        final String startSwankScript =
        "(ns my-app\n" +
        "  (:use [swank.swank :as swank]))\n" +
        "(swank/start-repl) ";

        // launch swank in a separate thread otherwise it will 
        // block the webapp startup
        new Thread() {
            public void run() {
                try {
                    Compiler.load(new StringReader(startSwankScript));
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            }
        }.start();
    }

    public void contextDestroyed(ServletContextEvent contextEvent) {
    }
}


Declare the ServletContextListener

In web.xml:
       <url-pattern>/cometd/*url-pattern>
   filter-mapping>
   
   <listener>
     <listener-class>
       cljinject.SwankServletContextListener
     listener-class>
   listener>
   
web-app>


Launch the webapp

Now in the Jetty logs you should see:
my-app=> Connection opened on null port 4005.
nil


Connect from Emacs

Note: You may need to install slime-rep.
  • In emacs: M-x slime-connect
  • Now in the slime REPL type:
user> (.println System/out "---- hello from clojure!!! -----")
nil
  • You should see it on the Jetty console:
---- hello from clojure!!! -----


Mess around ;-)

We took care to expose the context in the SwankServletContextListener, so now we can access it from the REPL and mess around:
user> cljinject.SwankServletContextListener/context
#<SContext ServletContext@178820c{/cljinject,file:}>

That's it!
Isn't life beautiful?
HTML generated by org-mode 6.33x in emacs 23

Aucun commentaire:

Enregistrer un commentaire

Membres