Wednesday, 3 December 2008

Simpler Clojure/SLIME Embedding

Thanks to Craig McDaniel's hint, I know a simpler way to embed Clojure/SLIME than I used before. Since Clojure svn revision 1127, macro clojure.main/with-bindings makes the embedding as trivial as this jsp page.

8 comments:

  1. Hi Anton,

    I'm trying to solve the same problem, and using your JSP I can get Swank running under Tomcat and connect to it. But, none of the classes that should be in the classpath (anything in common/lib for example) seem to be available to the JSP REPL - almost like it spawned a new JVM. I just dropped your JSP into webapps/ROOT but that should see other classes in common-lib... did you do anything special deploying the JSP to get it to see other classes in the classpath?

    ReplyDelete
  2. Hi Earl.

    Well, if classes are available to java/JSP code, they are available for Clojure too.

    The Tomcat I use is build from sources Tomcat 6.0x. It seems to me that it does not use directory $CATALINA_HOME/common/lib at all. Instead, it uses $CATALINA_HOME/lib.

    Unfortunately, Tomcat class loader documentation page http://tomcat.apache.org/tomcat-6.0-doc/class-loader-howto.html contains contradictory information: first it explains class loader hierarchy without common/lib, but below, in the "XML Parsers and JSE 5" section, they mention commmon/lib.

    I believe the latter is typo.

    In short, classes are available for me if I place a .jar into WEB-INF/lib or into $CATALINA_HOME/lib.

    I hope you have not forgotten (import '(foo Bar)) in Clojure, if you want access java class foo.Bar.

    - Anton

    ReplyDelete
  3. You're right - I'm using Tomcat 5.5 where a jar in common/lib should be picked up. In any case, I've verified that the test class I'm trying to access is available to the JSP, but not from inside the REPL.

    It's not a matter of import - import gives me a ClassNotFoundException (as expected if the class doesn't exist on the classpath at all).

    My current working theory is that perhaps a new classloader is being created and used by Swank. When I evaluate the following to print the classpath:

    (println (seq (.getURLs (java.lang.ClassLoader/getSystemClassLoader))))

    I only see what the (add-classpath) line from the JSP explicitly added.

    -Greg
    [Sorry, Earl Radio was a penname that I was playing around with in Google/Blogger for experimentation, forgot to shut it off for my last post]

    ReplyDelete
  4. Hi Greg.

    Indeed, if Java can access the class, but Clojure can't, there must be something with Clojure or Clojure/swank setup.

    It may be a matter of Clojure and Clojure/swank versions you use. Mine are SVN 1128 for Clojure and Git 886d66ed571fe2908de4f5714c735ab48054d587 for Clojure/swank.

    Try also to investigate (.getContextClassLoader (java.lang.Thread/currentThread)) and its parent, ant its parent, and so on. What are their classes and what URLs they know.

    Can you access the class if the .jar is placed in WEB-INF/lib?

    - Anton

    ReplyDelete
  5. The context classloader has the same stuff in it as the system classloader. What's interesting is that it's not just my .jar that's missing but *all* Tomcat jars. In fact, the reported classpath is what I would expect to see if I had just started swank from the command line outside of Tomcat. (And putting the jar in WEB-INF/lib doesn't change anything.)

    From that result, I would almost think that my SLIME is not connecting to the Swank instance that I think it is (starting a new one instead of connecting to Tomcat's). The thing is, killing Tomcat's process will break the link to SLIME so I think that has to be the one.

    Regarding versions, I have newer ones (Clojure 1162, I think). I could downgrade if I get desperate, but I never like that as a solution...

    -Greg

    ReplyDelete
  6. Downgrading may help to find the cause and therefore more appropriate solution.

    Perhaps it would be helpful to ask in the Clojure google group.

    Anyway, I'd be interested to know how you solve this.

    Good luck,
    - Anton

    ReplyDelete
  7. > Perhaps it would be helpful to ask in the Clojure google group.

    Yes, I suppose I will - I just wanted to start here and see if there was some apparent difference between your setup (as a "known good") and mine.

    > Anyway, I'd be interested to know how you solve this.

    I'll post the solution here when I get it working. Thanks for your advice so far...

    -Greg

    ReplyDelete
  8. Anton,

    Just to wrap up this thread, I did try to revert versions. I found that the JSP didn't work with Clojure 1128 - the require statement wasn't finding swank. It "works" as now with the latest Clojure but the older version of Swank that you were using.

    That said, I'll take this to the Clojure Google group. Thanks again,

    Greg

    ReplyDelete