Log4j, Tapestry 5.1, Stand-Alone Jetty 6 not playing along?
up to this point I have been developing a Tapestry 5.1.0.5 web-app using Maven goals to compile/package/execute the application. I used the mvn jetty:run goal to run the Jetty maven plugin. This always worked fine. It seems Maven used Jetty 6.1.9.
I now need to setup a production environment that does NOT use maven goals for execution. I thought Jetty seemed simple enough and it was already working with Maven. I got 6.1.26 (later tried 6.1.9 too with no luck), got my application WAR file into the webapp directory and then tried to run it... no luck.
Every single time I get this error, never changes:
2010-11-17 18:33:13.436:WARN::Error starting handlers
java.lang.NoClassDefFoundError: org/apache/log4j/Level
at org.slf4j.LoggerFactory.getSingleton(LoggerFactory.java:228)
at org.slf4j.LoggerFactory.bind(LoggerFactory.java:120)
at org.slf4j.LoggerFactory.performInitialization(LoggerFactory.java:111)
at org.slf4j.LoggerFactory.getILoggerFactory(LoggerFactory.java:269)
at org.slf4j.LoggerFactory.getLogger(LoggerFactory.java:242)
at org.slf4j.LoggerFactory.getLogger(LoggerFactory.java:255)
at org.apache.tapestry5.TapestryFilter.<init>(TapestryFilter.java:45)
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)
at java.lang.reflect.Constructor.newInstance(Constructor.java:513)
at java.lang.Class.newInstance0(Class.java:355)
at java.lang.Class.newInstance(Class.java:308)
at org.mortbay.jetty.servlet.Holder.newInstance(Holder.java:153)
at org.mortbay.jetty.servlet.FilterHolder.doStart(FilterHolder.java:92)
at org.mortbay.component.AbstractLifeCycle.start(AbstractLifeCycl开发者_Go百科e.java:50)
at org.mortbay.jetty.servlet.ServletHandler.initialize(ServletHandler.java:713)
at org.mortbay.jetty.servlet.Context.startContext(Context.java:140)
at org.mortbay.jetty.webapp.WebAppContext.startContext(WebAppContext.java:1282)
at org.mortbay.jetty.handler.ContextHandler.doStart(ContextHandler.java:518)
at org.mortbay.jetty.webapp.WebAppContext.doStart(WebAppContext.java:499)
at org.mortbay.component.AbstractLifeCycle.start(AbstractLifeCycle.java:50)
at org.mortbay.jetty.handler.HandlerCollection.doStart(HandlerCollection.java:152)
at org.mortbay.jetty.handler.ContextHandlerCollection.doStart(ContextHandlerCollection.java:156)
at org.mortbay.component.AbstractLifeCycle.start(AbstractLifeCycle.java:50)
at org.mortbay.jetty.handler.HandlerCollection.doStart(HandlerCollection.java:152)
at org.mortbay.component.AbstractLifeCycle.start(AbstractLifeCycle.java:50)
at org.mortbay.jetty.handler.HandlerWrapper.doStart(HandlerWrapper.java:130)
at org.mortbay.jetty.Server.doStart(Server.java:224)
at org.mortbay.component.AbstractLifeCycle.start(AbstractLifeCycle.java:50)
at org.mortbay.xml.XmlConfiguration.main(XmlConfiguration.java:985)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.mortbay.start.Main.invokeMain(Main.java:194)
at org.mortbay.start.Main.start(Main.java:534)
at org.mortbay.start.Main.start(Main.java:441)
at org.mortbay.start.Main.main(Main.java:119)
I was initially using Log4J 1.2.8 as part of my manual dependencies for my application as a whole. I read this site http://tapestry.apache.org/tapestry5.1/jetty.html and then realized I ought to use 1.2.12 or higher for the TRACE level. First I updated my dependency to LOG4J 1.2.16. This did not work.
I then did some further reading that suggested the apache-commons-logging dependency can cause issues with logging at large due to how it works. I went through my whole dependency hierarchy and excluded the apache-commons-logging from everything. The application still works with maven jetty plugin at this point, so I didn't break anything by doing this. But when I deploy the WAR, I still get the exception, so that was not the solution.
Next step I realized that the tapestry-ioc dependency was conflicting over log4j versions between my system side log4j and the one it wanted. It seems that it uses log4j 1.2.13 and that the slf4j in the dependency itself uses a compile Log4J 1.2.14.
I updated my system dependency to be first 1.2.14 (since this error is occuring at slf4j in Tapestry) and then when that failed again with 1.2.13. Neither of these cases happened to work either.
I've heard mention of making sure Jetty does not override your Log4J with a lower version it uses for its own logging. Yet there is nowhere in the Jetty files that I can find any log4j dependency.
i'm going to have a guess:
this 'could' be caused by
when maven downloaded the log4j dependency, it failed or was corrupted - try deleting the log4j directory in your maven repository (windows: docs and settings/user/.m2/....)
there is some kind of dependency conflict and maven is doing a crap job at resolving it by not including either - this is unlikely, i think it would include the most up-to-date version
some other maven plugin or configuration is causing the log4j jar to be excluded from the WAR creation (duh)
dunno what else could cause this...
EDIT re comment:
ah yes, now that you mention it i have that problem to! i have a couple of 'self managed' (ie not maven managed) jars and as far as i know the only way to include them in the maven classpath is to give them a system
scope. your question becomes: "how do i include non-maven jars in the maven build?"
the documentation for the scope
element:
The scope of the dependency - compile, runtime, test, system, and provided. Used to calculate the various classpaths used for compilation, testing, and so on. It also assists in determining which artifacts to include in a distribution of this project. For more information, see the dependency mechanism.
also an error you get in your pom if you change the scope of an entry with a systemPath:
only dependency with system scope can specify systemPath.
EDIT 2: found a good solution...
i found this 'issue' report, and followed the path suggested by the last comment:
We won't do this. I guess that you might add a webresource section with an include for the files you want and a targetPath.
Here's the documentation regarding the mechanism.
so what you need to do is:
<build>
...
<plugins>
...
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>2.1.1</version>
<configuration>
<webResources>
<resource>
<directory>unmanaged-lib</directory>
<targetPath>WEB-INF/lib</targetPath>
<includes>
<include>**/*.jar</include>
</includes>
</resource>
</webResources>
</configuration>
</plugin>
...
<plugins>
...
<build>
note: the path 'unmanaged-lib' is a dir in the root of your project in this case (ie level with pom.xml)
精彩评论