Hi Todd, here's a pattern for doing what you want;
1.) Create svlt/Svlt.clj as below
2.) Compile it separately using
(binding [*compile-path* "./tmp"] (compile 'svlt.Svlt))
3.) cp ./tmp/* [tomcat]/myctx/WEB-INF/classes/
4.) cp clojure.jar to myctx/WEB-INF/lib
It is better to have clojure.jar in each context's WEB-INF
as then class loading works correctly.
5.) Create your app clj functions in say myapp/clfns.clj
(as below) and copy this (not compiled)
to myctx/WEB-INF/classes/myapp/clfns.clj
6.) Add to myctx/WEB-INF/web.xml;
<servlet>
<servlet-name>Svlt</servlet-name>
<servlet-class>svlt.Svlt</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Svlt</servlet-name>
<url-pattern>/svlt/*</url-pattern>
7.) Open http://whatever/myctx/svlt/myapp.clfns/html-hi
; -------------------- svlt/Svlt.clj
(ns svlt.Svlt
(import (javax.servlet.http HttpServletRequest
HttpServletResponse))
(:gen-class :extends javax.servlet.http.HttpServlet))
(def re-ipath #"\/(.*)\/(.*)")
(defn -service
[this #^HttpServletRequest req #^HttpServletRequest rsp]
(let [ipath (.getPathInfo req)
g (re-matches re-ipath ipath)
_ (when (nil? g) (throw (java.io.IOException.
(str "Invalid svlt ipath (parse): " ipath))))
[_ ns-sym req-fn-nm] g
ns-sym (symbol ns-sym)
found-ns (find-ns ns-sym)
found-ns (if (nil? found-ns)
(let [n (create-ns ns-sym)] (require ns-sym) n)
found-ns)
_ (when (nil? found-ns) (throw (java.io.IOException.
(str "Namespace not found for: " ns-sym))))
req-fn (get (ns-publics ns-sym) (symbol req-fn-nm)) ]
(req-fn req rsp)))
; --------------------- myapp/clfns.clj
(ns myapp.clfns
(:import (javax.servlet.http HttpServletRequest
HttpServletResponse)))
(defn html-hi
[#^HttpServletRequest req #^HttpServletResponse rsp]
(.setContentType rsp "text/html")
(with-open [wtr (java.io.PrintWriter. (.getOutputStream rsp))]
(.println wtr "<html><body><p>Hi</p></body></html>"))))
Notes;
- to update, simply copy new app clj file/s to WEB-INF/classes and
reload the context.
- Borrow http://github.com/weavejester/hiccup for some cool html
generation stuff.
- you should be able to adapt the above (namespace requiring) to your
other java integration needs.
-Rgds, Adrian.
AC> Notes;
AC> - to update, simply copy new app clj file/s to WEB-INF/classes and
AC> reload the context.
AC> - Borrow http://github.com/weavejester/hiccup for some cool html
AC> generation stuff.
AC> - you should be able to adapt the above (namespace requiring) to your
AC> other java integration needs.
You can use Compojure to build webapp in more convenient way.
It's also possible to use Leiningen + lein-war plugin to build .war file
with all dependencies inside.
Another possibility is use maven to build .war. I have simple example of
Compojure + war at
http://github.com/alexott/clojure-examples/tree/master/compojure-simple/,
but I have no description of it yet (I planned to do this, but had no
time).
This is very simple multi-module example - cpj-core defines compojure
routes + implementation of functions, while cpj-war is used to generate
.war file. (cpj-standalone uses jetty to run webapp without deploying to
existing container)
--
With best wishes, Alex Ott, MBA
http://alexott.blogspot.com/ http://alexott.net
http://alexott-ru.blogspot.com/
I should elaborate on my previous post. It was intended not to
recommend the clojure way of building web apps (there's plenty of info
regarding that - compojure, ring, clout, hiccup, conjure, etc), but
rather as a specific, detailed example of integration from java to
clojure and how to extend java classes and implement java interfaces
in clojure.
A "canonical" example of this, (as Todd originally requested) is how
one implements the servet interface in clojure and uses it in a
container like tomcat. That is presented in my example.
A further important detail (for me at least), is how one can (from
java) dynamically load clojure namespaces and call clojure functions
in a way that allows one to extend existing java systems easily. That
is also shown in the example (see the ns-sym/require logic). This is
very useful for dynamically loading alternative implementations of
functions from different namespaces, giving the ability to deploy
dependency injection, factory mechanisms and other such strategies.
An example of using this ns loading technique for creating TimerTasks,
callable from java (or clojure), implemented in clojure is shown in
http://groups.google.co.za/group/clojure/browse_thread/thread/a35e45935af55a3/7ba78a7223c1f802?hl=en&lnk=gst&q=Timertask#7ba78a7223c1f802
The 1.2 master branch also introduces deftype and reify which (over
and above defprotocol and defrecord) add greatly to the tools for
modular, extensible java/clojure interop.
-Rgds, Adrian.
As I'm new to clojure (and lisp in general), it'll take me a bit to
puzzle through your code and links. However, I'll use it as an example
to study the language. Thanks again!
-Todd