Dave Ray
Dave Ray

Reputation: 40005

Reloading Clojure code in Tomcat

I have an existing Java webapp running in Tomcat to which I'm adding some primitive Clojure support. For the time being, I'm just including Clojure source files as resources on the classpath and invoking it through clojure.lang.RT. It's primitive, but works fine.

However, I've noticed that Tomcat's WebappClassLoader caches resources retrieved through getResourceAsInputStream() which Clojure uses to retrieve and compile source code. That is, doing (require 'my-ns :reload) just reloads the cached version of the file even though an updated one is available on disk. Is there a way to circumvent or avoid this caching for Clojure files?

The best I've come up with after much fruitless googling is to use reflection to manually remove the entry from WebappClassLoader.resourceEntries which is awful.

I must be missing something.

Answers like "use Jetty/Glassfish/JBoss", "restart Tomcat", etc aren't what I'm looking for.

Upvotes: 5

Views: 649

Answers (4)

kotarak
kotarak

Reputation: 17299

Or use a patched version of clojure which does something along the lines:

(io/input-stream (io/resource "bla.clj"))

I found a remark on the net that this is not cached.

Upvotes: 0

kotarak
kotarak

Reputation: 17299

Is this related to the cachingAllowed flag as described here? Just shooting into the blue.

Upvotes: 0

Shantanu Kumar
Shantanu Kumar

Reputation: 1240

Can you put the Clojure source files under WEB-INF? Then you can read them using http://tomcat.apache.org/tomcat-5.5-doc/servletapi/javax/servlet/ServletContext.html#getResourceAsStream(java.lang.String)

servletContext.getResourceAsStream("/WEB-INF/foo/core.clj");

This worked for me in the past to load un-cached Groovy classes from source in Tomcat.

Upvotes: 0

cemerick
cemerick

Reputation: 5916

You're not going to be able to circumvent WebappClassLoader's behaviour there. What you can do is move the code that's being loaded outside of its jurisdiction; e.g. up to $CATALINA_HOME/lib, as described here.

You'll need to move all of your dependencies there as well, leaving the .war file you actually deploy as a webapp as a small shell that expects all the code to already be available elsewhere.

This will get you out of WebappClassLoader's jurisdiction, and hopefully its semantics as well. (If it caches things loaded from parent classloaders, that would seem thoroughly broken IMO.)

Upvotes: 2

Related Questions