code example from a blogpost
Java JavaScript
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Failed to load latest commit information.
src/main
.gitignore
README.org
pom.xml

README.org

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 with 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:

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

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-clojure</groupId>
  <artifactId>swank-clojure</artifactId>
  <version>1.4.2</version>
</dependency>

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) {
        System.out.println(">>>>>>>>>>>>>>> Context Created");
        context = contextEvent.getServletContext();
        // set variable to servlet context
        context.setAttribute("TEST", "TEST_VALUE");
        
        System.out.println(">>>>>>>>>>>>>>> now waiting ... ;)");

        new Thread() {
            public void run() {
                try {
                    final String startSwankScript = 
                        "(ns my-app\n" + 
                        "  (:use [swank.swank :as swank]))\n" + 
                        "(swank/start-repl) "; 
                    Compiler.load(new StringReader(startSwankScript)); 
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            }
        }.start();
    }
    public void contextDestroyed(ServletContextEvent contextEvent) {
        context = contextEvent.getServletContext();
        System.out.println(">>>>>>>>>>>>>>>> Context Destroyed");
    }
}

Declare the ServletContextListener

In web.xml:

<listener>
  <listener-class>
    cljinject.SwankServletContextListener
  </listener-class>
</listener>

Launch the webapp

Now in the Jetty logs you should see:

2012-04-15 22:05:23.845:INFO::No Transaction manager found - if your webapp requires one, please configure one.
>>>>>>>>>>>>>>> Context Created
>>>>>>>>>>>>>>> now waiting ... ;)
2012-04-15 22:05:25.016:INFO::Started SelectChannelConnector@0.0.0.0:8080
[INFO] Started Jetty Server
[INFO] Starting scanner at interval of 10 seconds.
my-app=> Connection opened on null port 4005.
nil

Connect from Emacs

Setup

Even if you already have clojure-mode, you may need to install slime-repl.

Connect

  • 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:<snip>}>

That’s it!

Isn’t life beautiful?

References