Search code examples
javatomcath2resteasyjooq

Tomcat context resource won't load h2 driver


java.sql.SQLException: Cannot load JDBC driver class 'com.h2.Driver'
at org.apache.tomcat.dbcp.dbcp2.BasicDataSource.createConnectionFactory(BasicDataSource.java:2145)
at org.apache.tomcat.dbcp.dbcp2.BasicDataSource.createDataSource(BasicDataSource.java:2037)
at org.apache.tomcat.dbcp.dbcp2.BasicDataSource.getConnection(BasicDataSource.java:1543)
at com.apon.MessageService.getMessage(MessageService.java:68)

Setup
I am building a Java RESTService using RESTEasy, with Apache Shiro for security, and jOOQ as my ORM. I want tomcat to create a resource, handling the connections.

When I start tomcat (tomcat 8.5, not EE version just regular), I get no errors. When I go to /api/message, I execute the code getMessage below().

Executed code that fails

@Resource(name = "jdbc/TestingRest-db")
DataSource dataSource;
@GET
@Produces(MediaType.APPLICATION_JSON)
@RequiresUser
public List<MessagePojo> getMessage() {
    InitialContext initCtx = null;
    try {
        initCtx = new InitialContext();
        Context envCtx = (Context) initCtx.lookup("java:comp/env");

        DataSource ds = (DataSource) envCtx.lookup("jdbc/TestingRest-db");
        if (dataSource == null) {
            // This will always be executed, because it doesn't fill the resource??
            dataSource = ds;
        }
    } catch (NamingException e) {
        e.printStackTrace();
        return null;
    }
    try {
        // This line doesn't really help.
        Class.forName("org.h2.Driver");
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    }
    List<MessagePojo> list = new ArrayList();
    try {
        Connection connection = dataSource.getConnection();
        messageMyDao = new MessageMyDao(DSL.using(connection, JDBCUtils.dialect(connection)).configuration());
        list = messageMyDao.findAll();
    } catch (SQLException e) {
        e.printStackTrace();
    }

    return list;
}

What I did
I followed the tutorial https://www.mulesoft.com/tcat/tomcat-mysql basically. I just did it for H2 instead of MySQL. However, it seems the driver does not really load.

I tried executing some different code, namely just connecting using

// Load h2 driver on the classpath. If you do not do this, getConnection will fail.
    try {
        Class.forName("org.h2.Driver");
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    }

    // The following connection works perfectly fine.
    connection = DriverManager.getConnection(url, userName, password);

This does work! So the problem really lies in getting the driver loaded by tomcat. Not with my pom setup or classpath from my application (h2 jar is also located in WEB-INF/lib).

Pom.xml

<properties>
    <resteasy.version>3.1.4.Final</resteasy.version>
    <apache.shiro.version>1.3.2</apache.shiro.version>
    <apache.log4j.version>2.9.1</apache.log4j.version>
    <jooq.version>3.10.2</jooq.version>
</properties>
<dependencies>
    <!-- RESTService framework: RESTEasy -->
    <dependency>
        <groupId>org.jboss.resteasy</groupId>
        <artifactId>resteasy-jaxrs</artifactId>
        <version>${resteasy.version}</version>
    </dependency>
    <dependency>
        <groupId>org.jboss.resteasy</groupId>
        <artifactId>resteasy-jaxb-provider</artifactId>
        <version>${resteasy.version}</version>
    </dependency>
    <dependency>
        <groupId>org.jboss.resteasy</groupId>
        <artifactId>resteasy-servlet-initializer</artifactId>
        <version>${resteasy.version}</version>
    </dependency>
    <dependency>
        <groupId>org.jboss.resteasy</groupId>
        <artifactId>resteasy-jackson2-provider</artifactId>
        <version>3.1.4.Final</version>
    </dependency>

    <!-- Security framework: Apache Shiro -->
    <dependency>
        <groupId>org.apache.shiro</groupId>
        <artifactId>shiro-core</artifactId>
        <version>${apache.shiro.version}</version>
    </dependency>
    <dependency>
        <groupId>org.apache.shiro</groupId>
        <artifactId>shiro-web</artifactId>
        <version>${apache.shiro.version}</version>
    </dependency>

    <!-- Use jOOQ as ORM. -->
    <dependency>
        <groupId>org.jooq</groupId>
        <artifactId>jooq</artifactId>
        <version>${jooq.version}</version>
    </dependency>
    <dependency>
        <groupId>org.jooq</groupId>
        <artifactId>jooq-meta</artifactId>
        <version>${jooq.version}</version>
    </dependency>
    <dependency>
        <groupId>org.jooq</groupId>
        <artifactId>jooq-codegen</artifactId>
        <version>${jooq.version}</version>
    </dependency>
    <!-- H2 database -->
    <dependency>
        <groupId>com.h2database</groupId>
        <artifactId>h2</artifactId>
        <version>1.4.196</version>
    </dependency>

Web.xml

<listener>
    <listener-class>org.h2.server.web.DbStarter</listener-class>
</listener>
<listener>
    <listener-class>org.apache.shiro.web.env.EnvironmentLoaderListener</listener-class>
</listener>

<filter>
    <filter-name>ShiroFilter</filter-name>
    <filter-class>org.apache.shiro.web.servlet.ShiroFilter</filter-class>
</filter>

<filter-mapping>
    <filter-name>ShiroFilter</filter-name>
    <url-pattern>/api/*</url-pattern>
    <dispatcher>REQUEST</dispatcher>
    <dispatcher>FORWARD</dispatcher>
    <dispatcher>INCLUDE</dispatcher>
    <dispatcher>ERROR</dispatcher>
</filter-mapping>

<resource-ref>
    <res-ref-name>jdbc/TestingRest-db</res-ref-name>
    <res-type>javax.sql.DataSource</res-type>
    <res-auth>Container</res-auth>
    <injection-target>
        <injection-target-class>com.MessageService</injection-target-class>
        <injection-target-name>dataSource</injection-target-name>
    </injection-target>
</resource-ref>

Context.xml

  <Resource name="jdbc/TestingRest-db" auth="Container" type="javax.sql.DataSource"
           maxTotal="100" maxIdle="30" maxWaitMillis="10000"
           driverClassName="com.h2.Driver"
           url="jdbc:jdbc:mysql:file:./TestingRest-db"/>

Things I don't get
First of all I dont get why @Resource doesn't work for the DataSource. Also, I don't get why my h2 driver doesnt get loaded. In the java code I can create new connections without problems, but I can't in tomcat.


Solution

  • com.h2.Driver vs org.h2.Driver, did you notice?