Posted on by & filed under Content - Highlights and Reviews, java, programming.

by Julian Gamble

Did you know that NASA has debugged a spacecraft 100M miles away with LISP REPL?

Would you like to have that same power in your Java app today? (As an aside, some might contend this powerful enough to create a risk, so you should consider if this fits your needs. Don’t give access to this to anyone who shouldn’t have root access your server.)

Image

Today we’re going to build a web REPL in Clojure. Then we’ll integrate it into a Java application. Then we’ll use it to read a value inside the Java application that otherwise we’d have no visibility of.

Image

Steps – Part 1 – The Clojure App

  1. Install Leiningen2 if you haven’t already.
  2. Create a new Clojure App by running the following on the command line:

  1. Modify the file project.clj so it looks like Listing 1.
  2. Modify the file src/repl_jar/core.clj so it looks like Listing 2.
  3. Create a new directory public under resources
  4. Create two new directories css and js under resources/public
  5. Create the file webrepl.css under resources/public/css so it looks like Listing 3.
  6. Create the file webrepl.js under resources/public/js so it looks like Listing 4.
  7. Save the file https://code.jquery.com/jquery-2.1.4.min.js to the directory resources/public/js
  8. Save the file https://raw.githubusercontent.com/chrisdone/jquery-console/master/jquery.console.js to the directory resources/public/js
  9. To package this as a maven project for the next set of steps, run

Testing – Part 1 – The Clojure App

  1. In your repl-jar project directory, run

  1. In a web browser – navigate to the URL http://localhost:8090/ and observe the REPL
  2. On the web REPL in the browser – enter the expression

You should get the result:

We’ve got the first part of our Clojure Web REPL working. Now let’s integrate it into a Java Application.

Steps – Part 2 – Integrating it into your Java App

  1. Install Maven3 if you haven’t already.
  2. In the parent directory (the one above the repl-jar project) run the command:

  1. In the new app directory, modify the pom.xml to look like Listing 5.
  2. Modify the file src/main/java/demo/App.java to look like Listing 6.
  3. Add the file src/main/java/demo/Model.java to look like Listing 7.

Testing – Part 2 – Integrating it into your Java App

  1. In a command prompt in the directory of the app project, run the following command:

  1. Now run

  1. In a web browser – navigate to the URL http://localhost:8090/
  2. First we’ll load the class. On the web REPL – enter the expression

You should get the result

  1. Then enter the expression:

You should get the result

  1. Then enter the expression

You should get the result

Explanation

project.clj

You’ll notice we’ve added the following web-related library dependencies:

These are for routing and handing HTTP requests.

This library dependency:

gives us the Jetty web server.

In addition this json library:

Is for handing data embedded in json from the AJAX requests.

This change:

Is for changing the class that is finally created. By default, Leiningen wouldn’t create a Java class when we run lein install, it would simply create a jar with the uncompiled Java source files inside. The :aot step points it to compile the class files, and the :main tells the execution and packaging steps in Leiningen that we’ve remapped the resulting class. By default, our Clojure class repl-jar.core would compile down to a class named repl_jar.core, which isn’t very friendly to those with a Java background. In the Clojure file, we include some code:

to tell the Clojure compiler to compile to a Java class named repl.ApplicationREPL instead.

core.clj

The first thing to note is the :gen-class statement. Here we set the name of our compiled class to a Java style class name, to be friendly for integration. We also export the start method as a static method.

The next thing to notice are the libraries pulled in by :require. The Ring and Compojure libraries are for handling web requests. The Hiccup libraries are for generating html from Clojure data. The final Clojure json library is for unwrapping the data embedded in the GET statement as the expression is sent down from the browser.

The repl-sessions definition holds the environment for each of the REPLS in every browser session opened. The defonce tells the Compojure handlers not to reinitialize this value each time a new browser sends a request.

The current-bindings function is a wrapper around the base current Clojure environment to provide a framework for controls around what can and cannot be run.

The functions bindings-for, store-bindings-for and with-session are about linking the current session key to the current environment for that browser. Given a new session, create a new environment and store it associated with that session. Given a new request for an existing browser session, retrieve that environment and evaluate the expression in that context.

The do-eval function is the meat of the whole project. The main part of it is the expression (eval form). Outside that we wrap the stdout, handle errors and provide the environment in which to evaluate the expression.

The handle-request function pulls the session key from the request and passes it down to the evaluation function so that the corresponding environment can be retrieved.

The html-page function is where we get to use the Hiccup libraries to generate HTML. We see CSS and JavaScript being loaded, and we provide a console div that our jQuery console will hang off later.

The app-routes definition is a library call to a Compojure macro to define our routes. Similar to the Ruby Sinatra library, we can map an HTTP action and path to a function.

The ring-app definition wraps our Compojure routes with handlers for parameters, CSS, sessions and error handling. These libraries are all Ring middleware.

The start-jetty function makes a call to the embedded jetty library. The library function run-jetty takes a Compojure route definition, and a port.

The main function is the Clojure equivalent of the public static void main(String args[]) you see in Java. This is our default entry point into the application (we’ll use another to make the wrapper simple). We’re using it to kick off the start-jetty function.

The –start function is our entry point for integration into the application. We define it as static in the gen-class definition. This simply starts the –main function. We call this method from the Java class using .start().

webrepl.js

We keep this fairly simple, with the jQuery Console tied to the #console div. Into this we feed a welcome message, a validation method and a handler method. The validation message just does a simple check to exclude empty strings. The handler method passes the expression down to the server using a synchronous GET, and returns the result.

pom.xml

Here we just add one dependency for our repl jar. Everything else is boilerplate.

App.java

Here we just add one line to start the web REPL running in the background. This is how easy it is to integrate into your application.

Model.java

This is a plain Java class. We include a hard-coded instance-level value, and a getter, to keep our testing simple, but more realistic values would be an unpredictable value, sourced from another system. (See if you can guess the cultural reference. )

Conclusion

We’ve built and tested a Clojure Web REPL. We’ve integrated it into a Java Web application. We’ve used it to determine a value inside the Java application, that otherwise we’d have no visibility of. (We’ve used a fixed value, but imagine if it were a random number – or a value from an external source.) 

Next Steps & Acknowledgements

You can find the code listing for this blog post on GitHub. If you need sandboxing, Anthony Raynes has done some great work on the clojail library.

Any Clojure WebREPL is indebted to the pioneering work of Anthony Raynes and Jay Fields.

Chris Done’s JQuery Console project has earned its status as a foundation of many web REPL projects across languages.

Learn More in Safari

My book, “Clojure Recipes” is available in Safari now. Focusing on Clojure 1.7 and higher, topics include creating a REST Server in Compojure, loading a data file into Cascalog, and getting started with Storm.

Clojure Recipes

About the Author

Julian Gamble is a software engineer who has worked in the financial services industry for more than a decade. When he’s not enabling billions of dollars to orbit the globe, he writes and presents on all things software-related at juliangamble.com/blog.

Tags: Clojure, java, nasa,

Comments are closed.