Skip to content

Commit

Permalink
Creating a ServletContextListener that will run the functions specifi…
Browse files Browse the repository at this point in the history
…ed in the context parameters context-init and context-destroy when the application is initialized or stopped. Both parameters are optional. Also included a small utility function to convert context params to a map.

The project now needs lein 2.0.0-preview10 to make use of the "provided" dependencies.
  • Loading branch information
dlebrero committed Sep 11, 2012
1 parent b91a417 commit 163e335
Show file tree
Hide file tree
Showing 5 changed files with 80 additions and 14 deletions.
44 changes: 38 additions & 6 deletions README.md
@@ -1,25 +1,26 @@
#Ring java servlet

Allows you to embed ring handlers in existing java web applications without having to add an AOT phase to your build process, by providing you with a generic way to declare servlets in your web.xml, and where the clojure ring handler is located.
It also provides a ServletContextListener which can be configured to run a function when the web app is initialized and destroyed.

##Example

### Add the Ring java servlet dependency to your project
##Setup
Add this project as a dependency of your project. By means of transitive dependencies magic, you''ll need to add no other dependency.

ring-java-servlet is distributed on clojars.org as a maven artifact, with following coordinates:

* groupId=org.lpetit.ring
* artifactId=ring-java-servlet
* version=0.1.0 (as of the time where this README was last updated)
* version=0.2.0 (as of the time where this README was last updated)

ring-java-servlet artifacts are currently only available on clojars.org

##Ring handler example

### Create your Ring handler
Write a clojure ring handler and place it somewhere in your source/resources folder (so that your build system adds it to the webapp classpath, e.g. places it in WEB-INF/classes folder of your webapp) :

; file lpetit.ring_test.clj
(ns lpetit.ring-test
(ns lpetit.ring-test)
(defn hello [req]
{:status 200
:headers {"Content-Type" "text/html"}
Expand All @@ -41,5 +42,36 @@ Write a clojure ring handler and place it somewhere in your source/resources fol
</servlet-mapping>

### Test it
That''s all. Next time you build your webapp and start it, you should see a "Hello world from ring java servlet" welcome message at http://the-server:the-port/<your-webapp-context>/foo.some-extension
That's all. Next time you build your webapp and start it, you should see a "Hello world from ring java servlet" welcome message at http://the-server:the-port/<your-webapp-context>/foo.some-extension

##ServletContextListener example

### Create startup and shutdown functions
Any clojure function with one parameter can be used as the startup or shutdown function. The RingServletContextListener will pass the ServletContext to the function. There is also a small utility function to convert the context parameters to a clojure map.

; file lpetit.ring_test.clj
(ns lpetit.context-test
(:require [org.lpetit.ring.servlet.util :as util])

(defn start-up [ctx]
(println "Starting app with params: " (util/context-params ctx))

(defn shutdown [ctx]
(println "Stopping app with params: " (util/context-params ctx))


### Declare the ServletContextListener in your web.xml

Specify which funtions to run at start/stop with the `context-init` and `context-destroy` context parameters. Both parameters are optional.

<context-param>
<param-name>context-init</param-name>
<param-value>lpetit.context-test/start-up</param-value>
</context-param>
<context-param>
<param-name>context-destroy</param-name>
<param-value>lpetit.context-test/shutdown</param-value>
</context-param>
<listener>
<listener-class>org.lpetit.ring.servlet.RingServletContextListener</listener-class>
</listener>
10 changes: 6 additions & 4 deletions project.clj
@@ -1,6 +1,8 @@
(defproject org.lpetit.ring/ring-java-servlet "0.1.0"
(defproject org.lpetit.ring/ring-java-servlet "0.2.0"
:description "Ring generic servlet for using ring without AOT."
:url "http://github.com/laurentpetit/ring-java-servlet"
:dependencies [[ring/ring-servlet "0.3.5" :exclusions [javax.servlet/servlet-api]]]
:dev-dependencies [[javax.servlet/servlet-api "2.5"]]
:aot [org.lpetit.ring.servlet.RingHttpServlet])
:dependencies [[ring/ring-servlet "1.1.0" :exclusions [javax.servlet/servlet-api]]]
:profiles {:provided
{:dependencies
[[javax.servlet/servlet-api "2.5"]]}}
:aot [org.lpetit.ring.servlet.RingHttpServlet org.lpetit.ring.servlet.RingServletContextListener])
8 changes: 4 additions & 4 deletions src/org/lpetit/ring/servlet/RingHttpServlet_impl.clj
@@ -1,17 +1,17 @@
(ns org.lpetit.ring.servlet.RingHttpServlet-impl
(:require [ring.util.servlet :as s])
(:use org.lpetit.ring.servlet.util)
(:import org.lpetit.ring.servlet.RingHttpServlet))

(defn -initState [] [[] (atom {})])

(defn -init-void [this]
(let [[n h] (map symbol ((juxt namespace name) (symbol (.getInitParameter this "handler"))))]
(require n)
(swap!
(let [resolved-fn (require-and-resolve (.getInitParameter this "handler"))]
(swap!
(.state this)
assoc
:service-fn
(s/make-service-method (ns-resolve (the-ns n) h)))))
(s/make-service-method resolved-fn))))

(defn -service [this req resp]
((-> this .state deref :service-fn) this req resp))
Expand Down
19 changes: 19 additions & 0 deletions src/org/lpetit/ring/servlet/RingServletContextListener.clj
@@ -0,0 +1,19 @@
(ns org.lpetit.ring.servlet.RingServletContextListener
(:use org.lpetit.ring.servlet.util)
(:gen-class :implements [javax.servlet.ServletContextListener])
(:import [javax.servlet ServletContextEvent]))

(defn run [contextEvent symbol-str]
(let [ctx (.getServletContext contextEvent)]
(if-let [the-fn (.getInitParameter ctx symbol-str)]
(let [resolved-fn (require-and-resolve the-fn)]
(resolved-fn ctx)))))

(defn -contextInitialized [this ^ServletContextEvent contextEvent]
(run contextEvent "context-init"))

(defn -contextDestroyed [this ^ServletContextEvent contextEvent]
(run contextEvent "context-destroy"))



13 changes: 13 additions & 0 deletions src/org/lpetit/ring/servlet/util.clj
@@ -0,0 +1,13 @@
(ns org.lpetit.ring.servlet.util
(:import [javax.servlet ServletContext]))

(defn require-and-resolve [symbol-str]
(let [[n h] (map symbol ((juxt namespace name) (symbol symbol-str)))]
(require n)
(ns-resolve (the-ns n) h)))

(defn context-params [^ServletContext ctx]
"Given a servlet context, it returns a map with all the context parameters. Keys are keywords."
(into {} (for [param (enumeration-seq (.getInitParameterNames ctx))
:let [value (.getInitParameter ctx param)]]
[(keyword param) value])))

0 comments on commit 163e335

Please sign in to comment.