Closed jumblerg closed 10 years ago
this same code worked fine with boot 1; it also works using the lein repl.
create a project.clj
(defproject tomcatlein "0.1.0-SNAPSHOT"
:description "FIXME: write description"
:url "http://example.com/FIXME"
:license {:name "Eclipse Public License"
:url "http://www.eclipse.org/legal/epl-v10.html"}
:dependencies [[org.clojure/clojure "1.5.1"]
[org.apache.tomcat.embed/tomcat-embed-jasper "8.0.8"]
[org.apache.tomcat.embed/tomcat-embed-logging-juli "8.0.8"]
[org.apache.tomcat.embed/tomcat-embed-core "8.0.8" ]])
and launch the repl:
stratus:tomcatlein jumblerg$ lein repl
nREPL server started on port 54809 on host 127.0.0.1
REPL-y 0.3.0
Clojure 1.5.1
Docs: (doc function-name-here)
(find-doc "part-of-name-here")
Source: (source function-name-here)
Javadoc: (javadoc java-object-or-class-here)
Exit: Control+D or (exit) or (quit)
Results: Stored in vars *1, *2, *3, an exception in *e
user=> (import 'org.apache.catalina.startup.Tomcat)
org.apache.catalina.startup.Tomcat
user=> (require '[clojure.java.io :as io])
nil
user=> (defn create [dir war port]
#_=> (.mkdirs (io/file dir "webapps"))
#_=> (doto (Tomcat.)
#_=> (.setBaseDir dir)
#_=> (.setPort port)
#_=> (.addWebapp "" war)
#_=> (.start) ))
#'user/create
user=> (def server (create "basedir" "my.war" 8888))
Sep 11, 2014 1:26:14 AM org.apache.coyote.AbstractProtocol init
INFO: Initializing ProtocolHandler ["http-nio-8888"]
Sep 11, 2014 1:26:14 AM org.apache.tomcat.util.net.NioSelectorPool getSharedSelector
INFO: Using a shared selector for servlet write/read
Sep 11, 2014 1:26:14 AM org.apache.catalina.core.StandardService startInternal
INFO: Starting service Tomcat
Sep 11, 2014 1:26:14 AM org.apache.catalina.core.StandardEngine startInternal
INFO: Starting Servlet Engine: Apache Tomcat/8.0.8
Sep 11, 2014 1:26:15 AM org.apache.catalina.startup.ContextConfig getDefaultWebXmlFragment
INFO: No global web.xml found
Sep 11, 2014 1:26:15 AM org.apache.jasper.servlet.TldScanner scanJars
INFO: At least one JAR was scanned for TLDs yet contained no TLDs. Enable debug logging for this logger for a complete list of JARs that were scanned but no TLDs were found in them. Skipping unneeded JARs during scanning can improve startup time and JSP compilation time.
Sep 11, 2014 1:26:16 AM org.apache.catalina.util.SessionIdGenerator createSecureRandom
INFO: Creation of SecureRandom instance for session ID generation using [SHA1PRNG] took [608] milliseconds.
Sep 11, 2014 1:26:16 AM org.apache.coyote.AbstractProtocol start
INFO: Starting ProtocolHandler ["http-nio-8888"]
#'user/server
the missing class appears in an uberjar built with boot 2. it can be required from the boot 2 using the previous build.boot script:
boot.user=> (import 'org.apache.catalina.startup.Tomcat)
org.apache.catalina.startup.Tomcat
boot.user=> (import 'org.apache.tomcat.util.descriptor.web.ServletDef)
org.apache.tomcat.util.descriptor.web.ServletDef
also tried commenting out line 95 of boot.clj at micha's suggestion, this had no impact, but did cause the repl to crash: https://github.com/tailrecursion/boot/blob/v2-r1/boot/base/src/main/java/boot/App.java#L95
jumblerg$ boot repl
clojure.lang.ExceptionInfo:
data: {:file ".boot/tmp/12568/9dcf3c24/boot/user.clj", :line 40}
java.lang.ExceptionInInitializerError:
java.lang.IllegalStateException: Var clojure.core/refer is unbound.
...
clojure.zip/loading--auto-- zip.clj: 12
clojure.zip__init.load : 12
clojure.zip__init.<clinit>
...
clojure.test__init.<clinit>
...
clojure.core/load/fn core.clj: 5641
clojure.core/load core.clj: 5640
...
clojure.core/load-one core.clj: 5446
clojure.core/load-lib/fn core.clj: 5486
clojure.core/load-lib core.clj: 5485
...
clojure.core/apply core.clj: 626
clojure.core/load-libs core.clj: 5528
...
clojure.core/apply core.clj: 626
clojure.core/require core.clj: 5607
...
clojure.tools.nrepl.middleware.session/loading--auto-- session.clj: 2
clojure.tools.nrepl.middleware.session__init.load : 2
clojure.tools.nrepl.middleware.session__init.<clinit>
...
clojure.core/load/fn core.clj: 5641
clojure.core/load core.clj: 5640
...
clojure.core/load-one core.clj: 5446
clojure.core/load-lib/fn core.clj: 5486
clojure.core/load-lib core.clj: 5485
...
clojure.core/apply core.clj: 626
clojure.core/load-libs core.clj: 5528
...
clojure.core/apply core.clj: 626
clojure.core/require core.clj: 5607
...
clojure.tools.nrepl.server/loading--auto-- server.clj: 1
clojure.tools.nrepl.server__init.load : 1
clojure.tools.nrepl.server__init.<clinit>
...
clojure.core/load/fn core.clj: 5641
clojure.core/load core.clj: 5640
...
clojure.core/load-one core.clj: 5446
clojure.core/load-lib/fn core.clj: 5486
clojure.core/load-lib core.clj: 5485
...
clojure.core/apply core.clj: 626
clojure.core/load-libs core.clj: 5524
...
clojure.core/apply core.clj: 626
clojure.core/require core.clj: 5607
...
reply.eval-modes.nrepl/loading--auto-- nrepl.clj: 1
reply.eval_modes.nrepl__init.load : 1
reply.eval_modes.nrepl__init.<clinit>
...
clojure.core/load/fn core.clj: 5641
clojure.core/load core.clj: 5640
...
clojure.core/load-one core.clj: 5446
clojure.core/load-lib/fn core.clj: 5486
clojure.core/load-lib core.clj: 5485
...
clojure.core/apply core.clj: 626
clojure.core/load-libs core.clj: 5524
...
clojure.core/apply core.clj: 626
clojure.core/require core.clj: 5607
...
reply.main/loading--auto-- main.clj: 1
reply.main__init.load : 1
reply.main__init.<clinit>
...
clojure.core/load/fn core.clj: 5641
clojure.core/load core.clj: 5640
...
clojure.core/load-one core.clj: 5446
clojure.core/load-lib/fn core.clj: 5486
clojure.core/load-lib core.clj: 5485
...
clojure.core/apply core.clj: 626
clojure.core/load-libs core.clj: 5524
...
clojure.core/apply core.clj: 626
clojure.core/require core.clj: 5607
...
boot.repl-client/loading--auto-- repl_client.clj: 1
boot.repl_client__init.load : 1
boot.repl_client__init.<clinit>
...
clojure.core/load/fn core.clj: 5641
clojure.core/load core.clj: 5640
...
clojure.core/load-one core.clj: 5446
clojure.core/load-lib/fn core.clj: 5486
clojure.core/load-lib core.clj: 5485
...
clojure.core/apply core.clj: 626
clojure.core/load-libs core.clj: 5524
...
clojure.core/apply core.clj: 626
clojure.core/require core.clj: 5607
...
boot.pod/call-in pod.clj: 127
...
boot.pod/call-in pod.clj: 132
boot.pod/call-worker pod.clj: 137
boot.task.built-in/fn/fn/fn/fn/fn built_in.clj: 156
boot.task.built-in/fn/fn/fn/fn built_in.clj: 145
boot.core/run-tasks core.clj: 292
boot.user/eval1278 user.clj: 47
...
boot.main/-main/fn main.clj: 103
boot.main/-main main.clj: 103
...
boot.App.main App.java: 185
tomcat's sprawling codebase is bloated in classic j2ee style. internal classloader mismanagement may be the issue. consider using winstone instead.
Line 95 mentioned above is calling a fn in the shim that uses dynapath to make the AppClassLoader immutable, by the way.
Thanks to @tcrawley for this! Apparently Tomcat was using the AppClassLoader instead of the one that it was loaded into. Tomcat needs to be told which classloader to use:
(defn create [dir war port]
(.mkdirs (io/file dir "webapps"))
(doto (Tomcat.)
(as-> % (.setParentClassLoader (.getServer %) (.getContextClassLoader (Thread/currentThread))))
(.setBaseDir dir)
(.setPort port)
(.addWebapp "" war)
(.start) ))
Yes, otherwise it will fall back to using the AppClassLoader, which is above boot and has no knowledge of the tomcat jars.
terrific! thanks for the insight toby. we should probably document this technique in the "writing boot tasks" documentation.
Sent from my phone, please excuse the brevity and typos,
On Sep 11, 2014, at 12:02 PM, Toby Crawley notifications@github.com wrote:
Yes, otherwise it will fall back to using the AppClassLoader, which is above boot and has no knowledge of the tomcat jars.
— Reply to this email directly or view it on GitHub.
to reproduce, create a project with the following build script:
then launch the repl: