akhikhl / gretty

Advanced gradle plugin for running web-apps on jetty and tomcat.
MIT License
655 stars 174 forks source link

Missing DBCP 2 libraries using Tomcat 8 container #234

Open sargue opened 8 years ago

sargue commented 8 years ago

I am trying to run tomcat through gretty (Tomcat 8). The application uses a JDBC pool using standard Tomcat 8 configuration. Unfortunately an error prevents Tomcat from starting.

17:45:47 WARN Failed to register in JMX: javax.naming.NamingException: Could not create resource factory instance [Root exception is java.lang.ClassNotFoundException: org.apache.tomcat.dbcp.dbcp2.BasicDataSourceFactory]

17:45:47 ERROR Exception processing Global JNDI Resources

Between Tomcat 7 and Tomcat 8 there are changes on the DBCP classes used. See the upgrading guide. Apache Commons DBCP 2.x is used instead of 1.x. Perhaps that is the problem.

To trigger the problem you just need an app who tries to use a pool.

Tomcat's server.xml:

<?xml version='1.0' encoding='utf-8'?>
<Server port="8005" shutdown="SHUTDOWN">
    <Listener className="org.apache.catalina.startup.VersionLoggerListener" />
    <Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener" />
    <Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" />
    <Listener className="org.apache.catalina.core.ThreadLocalLeakPreventionListener" />

    <GlobalNamingResources>
        <Resource name="jdbc/resourcename" auth="Container" type="javax.sql.DataSource" username="someuser"
                  password="somepassword" driverClassName="org.gjt.mm.mysql.Driver"
                  url="jdbc:mysql://localhost/somedatabase" />
    </GlobalNamingResources>
    <Service name="Catalina">
        <Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" />
        <Engine name="Catalina" defaultHost="localhost">
            <Host name="localhost"  appBase="webapps"
                  unpackWARs="true" autoDeploy="true">
            </Host>
        </Engine>
    </Service>
</Server>

App context.xml:

<?xml version='1.0' encoding='utf-8'?>
<Context>
    <ResourceLink global="jdbc/resourcename" name="jdbc/resourcename" type="javax.sql.DataSource"/>
</Context>
djKianoosh commented 8 years ago

Maybe you can try adding something like

    providedCompile 'org.apache.tomcat:tomcat-catalina:8.0.23'
    providedCompile 'org.apache.tomcat:tomcat-jdbc:8.0.23'

to your dependencies.

sargue commented 8 years ago

Not working, same error.

10:30:26: Executing external task 'tomcatStart'...
:prepareInplaceWebAppFolder
:createInplaceWebAppFolder UP-TO-DATE
:compileJava
:processResources UP-TO-DATE
:classes
:prepareInplaceWebAppClasses
:prepareInplaceWebApp
:tomcatStart
10:30:35 INFO  Configuring /gc with file:/C:/prj/gc/build/inplaceWebapp/META-INF/context.xml
10:30:35 WARN  Failed to register in JMX: javax.naming.NamingException: Could not create resource factory instance [Root exception is java.lang.ClassNotFoundException: org.apache.tomcat.dbcp.dbcp2.BasicDataSourceFactory]
10:30:35 ERROR Exception processing Global JNDI Resources
javax.naming.NamingException: Could not create resource factory instance
    at org.apache.naming.factory.ResourceFactory.getDefaultFactory(ResourceFactory.java:50) ~[tomcat-embed-core-8.0.23.jar:8.0.23]
    at org.apache.naming.factory.FactoryBase.getObjectInstance(FactoryBase.java:90) ~[tomcat-embed-core-8.0.23.jar:8.0.23]
    at javax.naming.spi.NamingManager.getObjectInstance(NamingManager.java:321) ~[na:1.8.0_45]
    at org.apache.naming.NamingContext.lookup(NamingContext.java:841) ~[tomcat-embed-core-8.0.23.jar:8.0.23]
    at org.apache.naming.NamingContext.lookup(NamingContext.java:152) ~[tomcat-embed-core-8.0.23.jar:8.0.23]
    at org.apache.naming.NamingContextBindingsEnumeration.nextElementInternal(NamingContextBindingsEnumeration.java:117) ~[tomcat-embed-core-8.0.23.jar:8.0.23]
    at org.apache.naming.NamingContextBindingsEnumeration.next(NamingContextBindingsEnumeration.java:71) ~[tomcat-embed-core-8.0.23.jar:8.0.23]
    at org.apache.naming.NamingContextBindingsEnumeration.next(NamingContextBindingsEnumeration.java:34) ~[tomcat-embed-core-8.0.23.jar:8.0.23]
    at org.apache.catalina.mbeans.GlobalResourcesLifecycleListener.createMBeans(GlobalResourcesLifecycleListener.java:138) [tomcat-embed-core-8.0.23.jar:8.0.23]
    at org.apache.catalina.mbeans.GlobalResourcesLifecycleListener.createMBeans(GlobalResourcesLifecycleListener.java:145) [tomcat-embed-core-8.0.23.jar:8.0.23]
    at org.apache.catalina.mbeans.GlobalResourcesLifecycleListener.createMBeans(GlobalResourcesLifecycleListener.java:110) [tomcat-embed-core-8.0.23.jar:8.0.23]
    at org.apache.catalina.mbeans.GlobalResourcesLifecycleListener.lifecycleEvent(GlobalResourcesLifecycleListener.java:82) [tomcat-embed-core-8.0.23.jar:8.0.23]
    at org.apache.catalina.util.LifecycleSupport.fireLifecycleEvent(LifecycleSupport.java:117) [tomcat-embed-core-8.0.23.jar:8.0.23]
    at org.apache.catalina.util.LifecycleBase.fireLifecycleEvent(LifecycleBase.java:90) [tomcat-embed-core-8.0.23.jar:8.0.23]
    at org.apache.catalina.util.LifecycleBase.setStateInternal(LifecycleBase.java:402) [tomcat-embed-core-8.0.23.jar:8.0.23]
    at org.apache.catalina.util.LifecycleBase.setState(LifecycleBase.java:347) [tomcat-embed-core-8.0.23.jar:8.0.23]
    at org.apache.catalina.core.StandardServer.startInternal(StandardServer.java:762) [tomcat-embed-core-8.0.23.jar:8.0.23]
    at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150) [tomcat-embed-core-8.0.23.jar:8.0.23]
    at org.apache.catalina.startup.Tomcat.start(Tomcat.java:337) [tomcat-embed-core-8.0.23.jar:8.0.23]
    at org.apache.catalina.startup.Tomcat$start$1.call(Unknown Source) [tomcat-embed-core-8.0.23.jar:8.0.23]
    at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:45) [groovy-all-2.3.10.jar:2.3.10]
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:108) [groovy-all-2.3.10.jar:2.3.10]
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:112) [groovy-all-2.3.10.jar:2.3.10]
    at org.akhikhl.gretty.TomcatServerManager.startServer(TomcatServerManager.groovy:49) [gretty-runner-tomcat-1.2.4.jar:na]
    at org.akhikhl.gretty.ServerManager$startServer$0.call(Unknown Source) [gretty-runner-1.2.4.jar:na]
    at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:45) [groovy-all-2.3.10.jar:2.3.10]
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:108) [groovy-all-2.3.10.jar:2.3.10]
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:116) [groovy-all-2.3.10.jar:2.3.10]
    at org.akhikhl.gretty.Runner.run(Runner.groovy:119) [gretty-runner-1.2.4.jar:na]
    at org.akhikhl.gretty.Runner.this$2$run(Runner.groovy) [gretty-runner-1.2.4.jar:na]
    at org.akhikhl.gretty.Runner$this$2$run.call(Unknown Source) [gretty-runner-1.2.4.jar:na]
    at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:45) [groovy-all-2.3.10.jar:2.3.10]
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:108) [groovy-all-2.3.10.jar:2.3.10]
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:112) [groovy-all-2.3.10.jar:2.3.10]
    at org.akhikhl.gretty.Runner.main(Runner.groovy:46) [gretty-runner-1.2.4.jar:na]
Caused by: java.lang.ClassNotFoundException: org.apache.tomcat.dbcp.dbcp2.BasicDataSourceFactory
    at java.net.URLClassLoader.findClass(URLClassLoader.java:381) ~[na:1.8.0_45]
    at java.lang.ClassLoader.loadClass(ClassLoader.java:424) ~[na:1.8.0_45]
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:331) ~[na:1.8.0_45]
    at java.lang.ClassLoader.loadClass(ClassLoader.java:357) ~[na:1.8.0_45]
    at java.lang.Class.forName0(Native Method) ~[na:1.8.0_45]
    at java.lang.Class.forName(Class.java:264) ~[na:1.8.0_45]
    at org.apache.naming.factory.ResourceFactory.getDefaultFactory(ResourceFactory.java:47) ~[tomcat-embed-core-8.0.23.jar:8.0.23]
    ... 34 common frames omitted
djKianoosh commented 8 years ago

question is what are the maven coordinates for dbcp2. that's probably what you have to punch into your dependencies, since the exception is ClassNotFoundException.

sargue commented 8 years ago

Added 'org.apache.tomcat:tomcat-dbcp:8.0.23' which contains de class but I'm seeing the same error.

Anyway I don't understand why a providedCompile should work, but of course I don't really know how the plugin works.

djKianoosh commented 8 years ago

the plugin creates a few different gradle configurations. if you do a gradle dependencies you'll see all of them. now, when you do gradle run to run your embedded tomcat, gretty loads up your deps as you've defined them... since you're defining GlobalNamingResources in server.xml, then maybe you need to put your tomcat-dbcb lib in a different configuration. you're getting into different classloaders here, so it is a bit more complicated. when you eventually deploy your app to your target environment, will your tomcat server have the jars available in /lib or somewhere else on the classpath?

sargue commented 8 years ago

The missing class is part of the Tomcat distribution. The jar file is tomcat-dbcp.jar and it is bundled in the /libdirectory.

iMyon commented 8 years ago

Same problem. You can try gretty 'org.apache.tomcat:tomcat-dbcp:8.0.23',instead of providedCompile.

sargue commented 8 years ago

It works. Thanks @iMyon !

mohamnag commented 8 years ago

I just wasted half a day on same problem with Jetty when some JNDI resource has been defined in a context xml file which was defined on Gretty config using contextConfigFile. The same file worked when renamed to jetty-env.xml and moved under WEB-INF but as soon as it was defined as context xml it did not work and I constantly was getting following error when trying to start integration test task:

java.lang.ClassNotFoundException: org.apache.commons.dbcp2.BasicDataSource
    at java.net.URLClassLoader.findClass(URLClassLoader.java:381) ~[na:1.8.0_40]
    at java.lang.ClassLoader.loadClass(ClassLoader.java:424) ~[na:1.8.0_40]
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:331) ~[na:1.8.0_40]
    at java.lang.ClassLoader.loadClass(ClassLoader.java:357) ~[na:1.8.0_40]
    at org.eclipse.jetty.util.Loader.loadClass(Loader.java:86) ~[jetty-util-9.2.10.v20150310.jar:9.2.10.v20150310]
    at org.eclipse.jetty.xml.XmlConfiguration$JettyXmlConfiguration.nodeClass(XmlConfiguration.java:364) ~[jetty-xml-9.2.10.v20150310.jar:9.2.10.v20150310]
    at org.eclipse.jetty.xml.XmlConfiguration$JettyXmlConfiguration.newObj(XmlConfiguration.java:754) ~[jetty-xml-9.2.10.v20150310.jar:9.2.10.v20150310]
    at org.eclipse.jetty.xml.XmlConfiguration$JettyXmlConfiguration.itemValue(XmlConfiguration.java:1125) ~[jetty-xml-9.2.10.v20150310.jar:9.2.10.v20150310]
    at org.eclipse.jetty.xml.XmlConfiguration$JettyXmlConfiguration.value(XmlConfiguration.java:1030) ~[jetty-xml-9.2.10.v20150310.jar:9.2.10.v20150310]
    at org.eclipse.jetty.xml.XmlConfiguration$JettyXmlConfiguration.newObj(XmlConfiguration.java:775) ~[jetty-xml-9.2.10.v20150310.jar:9.2.10.v20150310]
    at org.eclipse.jetty.xml.XmlConfiguration$JettyXmlConfiguration.configure(XmlConfiguration.java:423) ~[jetty-xml-9.2.10.v20150310.jar:9.2.10.v20150310]
...

After looking at Jetty documentation I found out that actual difference between context file and env file is that the former needs the dependencies on scope of server where for latter it is enough if resources are available on scope of web app.

So if somebody needs to use context files (Jetty or tomcat) the dependencies should be added to gretty as @iMyon also pointed out. I use this config:

gretty {
    dependencies {
        gretty 'org.postgresql:postgresql:9.4.1208'
        gretty 'org.apache.commons:commons-dbcp2:2.1.1'
    }
}

I dont know why is this not in docs. Actually this has to be stated directly on both this for Jetty and this for tomcat because as soon as some one uses context files this problem will appear!