Jetty + DataSource + JTA

Working on my next post about Drools Flow Work Items I wanted to have a one click example. This example involves a web application so I started with Jetty which fits perfect for a mvn jetty:run example. In the standalone example we run our own JNDI directory provided by Bitronix. Jetty has JNDI directory embedded so we have to register the datasource and the transaction manager. Doing this task for a totally jetty noob could be a little difficult and time consuming. So, hoping nobody has to spend too much time on this, I’ll try to summarize the steps I did to make this.

Jetty configuration files

There are two main configuration files: jetty.xml and jetty-env.xml. The first one is for configuring the whole server and the last for your specifc context (the webapp). To load the first one you have to configure the maven plugin to set the location.

<plugin>
  <groupId>org.mortbay.jetty</groupId>
  <artifactId>maven-jetty-plugin</artifactId>
  <configuration>
    <jettyConfig>src/main/webapp/WEB-INF/jetty.xml</jettyConfig>
  </configuration>
  [...]
</plugin>

The jetty-env.xml file will be auto loaded from your src/main/webapp/WEB-INF folder.

Datasources and jetty-env.xml file

Below, you can see how a WebAppContext is configured (pay attention to how readable this xml is). This is the way you expose objects in the JNDI directory: create a Resource into the jetty-env.xml file passing as first argument, the entry, in the directory and as second argument the object itself. In this example we are exposing a pooled datasource provided by H2, giving it a name that we’ll refer in persistence.xml as jta-data-source prefixed by java:comp/env/.

<?xml version="1.0"?>
<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://jetty.mortbay.org/configure.dtd">
<Configure class="org.mortbay.jetty.webapp.WebAppContext">
    <New id="DSTest" class="org.mortbay.jetty.plus.naming.Resource">
        <Arg>jdbc/testDS</Arg>
        <Arg>
            <New id="poolingDS" class="bitronix.tm.resource.jdbc.PoolingDataSource">
                <Set name="uniqueName">foobar</Set>
                <Set name="className">org.h2.jdbcx.JdbcDataSource</Set>
                <Set name="allowLocalTransactions">true</Set>
                <Get name="driverProperties">
                    <Put name="user">sa</Put>
                    <Put name="password">sasa</Put>
                    <Put name="URL">jdbc:h2:/tmp/droolsflow.db</Put>
                </Get>
                <Set name="maxPoolSize">3</Set>
                <Call name="init" />
            </New>
        </Arg>
    </New>
</Configure>

Finally you have to configure web.xml to expose the resource to your web application.

<web-app>
...
    <resource-ref>
        <description>My DataSource Reference</description>
        <res-ref-name>jdbc/testDS</res-ref-name>
        <res-type>javax.sql.DataSource</res-type>
        <res-auth>Container</res-auth>
    </resource-ref>
</web-app>

Transaction Manager & jetty.xml

Now it’s time to configure the Transaction Manager, so we will use Bitronix which provides a maven+jetty plugin. To start using it, you have to add it as a dependency of the maven-jetty-plugin in the corresponding section as follows:

            <plugin>
                <groupId>org.mortbay.jetty</groupId>
                <artifactId>maven-jetty-plugin</artifactId>
                <configuration>
                    <jettyConfig>src/main/webapp/WEB-INF/jetty.xml</jettyConfig>
                </configuration>
                <dependencies>
                    <dependency>
                        <groupId>org.codehaus.btm</groupId>
                        <artifactId>btm-jetty6-lifecycle</artifactId>
                        <version>1.3.3</version>
                    </dependency>
                    <dependency>
                        <groupId>org.slf4j</groupId>
                        <artifactId>slf4j-log4j12</artifactId>
                        <version>1.4.2</version>
                    </dependency>
                    <dependency>
                        <groupId>log4j</groupId>
                        <artifactId>log4j</artifactId>
                        <version>1.2.14</version>
                    </dependency>
                </dependencies>
            </plugin>

Next, you need to tell jetty to associate the Transaction Manager to start and shutdown the server life cycle. All this goes into jetty.xml:

<?xml version="1.0"?>
<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://jetty.mortbay.org/configure.dtd">

<Configure id="Server" class="org.mortbay.jetty.Server">
    <Call name="getConfiguration" class="bitronix.tm.TransactionManagerServices">
        <Set name="serverId">jetty-btm-node0</Set>
        <Set name="logPart1Filename">
            <SystemProperty name="jetty.home" default="." />
            btm1.tlog
        </Set>
        <Set name="logPart2Filename">
            <SystemProperty name="jetty.home" default="." />
            btm2.tlog
        </Set>
    </Call>
    <Call name="addLifeCycle">
        <Arg>
            <New class="bitronix.tm.integration.jetty6.BTMLifeCycle" />
        </Arg>
    </Call>

    <New class="org.mortbay.jetty.plus.naming.Transaction">
        <Arg>
            <Call name="getTransactionManager" class="bitronix.tm.TransactionManagerServices" />
        </Arg>
    </New>
</Configure>

Conclusion

After this xml battle, you are able to run any JPA+JTA application inside your jetty environment with minimum effort, just mvn jetty:run. All this was especially applied to run a Drools Flow application with persistent StatefullKnowledgeSession, which, btw, runs like a charm :)

Bonus stage

Remote debugging your mvn jetty:run with Eclipse

If you want to debug any maven application (in particular jetty running inside maven), try to execute mvnDebug jetty:run, which starts port 8000 and waits until Eclipse connects to it. To create a remote application debug configuration, go to Run > Debug Configurations > Remote Java Application and set port 8000; in the source tab you can attach the sources where you want to put your breakpoints, and finally click the Debug button.

Advertisements

3 Responses

  1. Diega,
    Awesome post!.
    I think that in the pom.xml you should not include sl4j-log4j and log4j, since including the first it’s enough.

  2. Nice post! Helped a lot to understand why my jta data source wasn’t working on jetty!

  3. anybody can help me?

    InvocationTargetException: cannot create JDBC datasource named foobar: org.h2.jdbcx.JdbcDataSource

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s