JOTMのセットアップ手順(Tomcat)

JOTMを使用してJTATomcat(と言うかServlet)で使用する手順です。DBはApache Derbyを使用して、JDBCでInsertを行うところまでを説明します。使用するソフトウェアは次の通りです。バージョンが異なるとセットアップ方法が異なるかも知れません。

Eclipseを使用する場合はfor Java EE Developersを使用します。

Apache Tomcatのダウンロード、セットアップ

Apache Tomcatからファイルをダウンロードして、適当なフォルダに展開します。

Apache Derbyのダウンロード、セットアップ、データベースとテーブルの作成

Apache Derbyからファイルをダウンロードして、適当なフォルダに展開します。

%DERBY%/bin/startNetworkServer.batを実行して、Apache Derbyを起動します。

%DERBY%/bin/ij.batを実行します。connectコマンドを使用して、データベースを作成 & 接続します。

connect 'jdbc:derby://localhost:1527/foo;create=true';

create table文を実行して、テーブルを作成します。

create table foo (
    id integer primary key,
    name varchar(100) not null
);

%DERBY%/lib/derbyclient.jarを%TOMCAT%/libフォルダにコピーします。

JOTMのダウンロード、セットアップ

JOTMからファイルをダウンロードして、適当なフォルダに展開します。

%JOTM%/examples/tomcat/README.txtを見ると、次のように書いてあります。

Put these libraries in $CATALINA_HOME/common/lib :
  cp $JOTM_HOME/lib/carol-*.jar $CATALINA_HOME/common/lib
  cp $JOTM_HOME/lib/howl-*.jar $CATALINA_HOME/common/lib
  cp $JOTM_HOME/lib/jotm-core.jar $CATALINA_HOME/common/lib
  cp $JOTM_HOME/lib/jotm-datasource.jar $CATALINA_HOME/common/lib
  cp $JOTM_HOME/lib/ow2-connector-1.5-*.jar $CATALINA_HOME/common/lib
  cp $JOTM_HOME/lib/ow2-jta-1.1-spec-*.jar $CATALINA_HOME/common/lib
  cp $JOTM_HOME/lib/xapool-*.jar $CATALINA_HOME/common/lib

自分が試したところ、これだけではjarファイルが足りず、NoClassDefFoundError例外が何度も発生しました。自分が試したときに必要だったjarファイルは次の通りです(*のファイルがREADME.txtの記述以外に必要だったファイルです)。

  • %JOTM%/lib/carol.jar
  • %JOTM%/lib/carol-iiop-delegate.jar
  • %JOTM%/lib/carol-interceptors.jar
  • %JOTM%/lib/cmi-api-client.jar (*)
  • %JOTM%/lib/cmi-core-common.jar (*)
  • %JOTM%/lib/cmi-jndi.jar (*)
  • %JOTM%/lib/commons-logging-api.jar
  • %JOTM%/lib/howl.jar
  • %JOTM%/lib/jotm-core.jar
  • %JOTM%/lib/jotm-datasource.jar
  • %JOTM%/lib/ow2-connector-1.5-spec.jar
  • %JOTM%/lib/ow2-jta-1.1-spec.jar
  • %JOTM%/lib/util-component-api.jar (*)
  • %JOTM%/lib/util-component-impl.jar (*)
  • %JOTM%/lib/util-i18n.jar (*)
  • %JOTM%/lib/util-log.jar (*)
  • %JOTM%/lib/util-xmlconfig.jar (*)
  • %JOTM%/lib/xapool.jar

これらのファイルを%TOMCAT%/libフォルダにコピーします。

context.xml

DataSourceとUserTransactionの設定を追加します。

<Resource
    name="jdbc/foo-ds"
    auth="Container"
    type="javax.sql.DataSource"
    factory="org.objectweb.jotm.datasource.DataSourceFactory"
    driverClassName="org.apache.derby.jdbc.ClientDriver"
    url="jdbc:derby://localhost:1527/foo"
    username="APP"
    password="APP" />

<Resource
    name="UserTransaction"
    auth="Container"
    type="javax.transaction.UserTransaction" />

<Transaction
    factory="org.objectweb.jotm.UserTransactionFactory"
    jotm.timeout="60" />

web.xml

DataSourceの設定を追加します。

<resource-ref>
    <res-ref-name>jdbc/foo-ds</res-ref-name>
    <res-type>javax.sql.DataSource</res-type>
    <res-auth>Container</res-auth>
</resource-ref>

Servlet作成

foo.FooServletクラスを作成します。

package foo;

import java.io.IOException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;

import javax.naming.InitialContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.sql.DataSource;
import javax.transaction.UserTransaction;

@SuppressWarnings("serial")
public class FooServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        try {
            InitialContext ctx = new InitialContext();

            DataSource ds = (DataSource) ctx.lookup("java:comp/env/jdbc/foo-ds");

            UserTransaction utx = (UserTransaction) ctx.lookup("java:comp/UserTransaction");

            try {
                utx.begin();

                Connection con = ds.getConnection();
                try {
                    PreparedStatement ps = con.prepareStatement("insert into foo values (?, ?)");
                    try {
                        ps.setInt(1, 1);
                        ps.setString(2, "one");

                        int result = ps.executeUpdate();

                        System.out.println(result);
                    } finally {
                        ps.close();
                    }
                } finally {
                    con.close();
                }

                utx.commit();
            } catch (SQLException e) {
                e.printStackTrace();

                utx.rollback();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}

web.xmlに、FooServletの設定を追加します。

<servlet>
    <servlet-name>FooServlet</servlet-name>
    <servlet-class>foo.FooServlet</servlet-class>
</servlet>

<servlet-mapping>
    <servlet-name>FooServlet</servlet-name>
    <url-pattern>/foo</url-pattern>
</servlet-mapping>

実行(コミット)

まず、データが空であることを確認します。

ij> select * from foo;
ID         |NAME
------------------------------------------

0 行が選択されました

Webアプリケーションを実行して、FooServletにアクセスして、正常終了したらデータが登録されていることを確認します。

ij> select * from foo;
ID         |NAME
------------------------------------------
1          |one

1 行が選択されました

実行(ロールバック)

FooServletのutx.commit()をutx.rollback()に変更します。これで、処理が正常でもロールバックするようになります。

先ほどデータを登録したので、データを削除して空にします。

ij> delete from foo;
1 行が挿入/更新/削除されました
ij> select * from foo;
ID         |NAME
------------------------------------------

0 行が選択されました

先ほどと同じように、Webアプリケーションを実行して、FooServletにアクセスして、正常終了したらデータを確認します。

ij> select * from foo;
ID         |NAME
-------------------------------

0 行が選択されました

ロールバックしているので、データは登録されていません。

もしデータが登録されている場合、JTAがうまく機能していなくて自動コミットされているかもしれません。自分はcontext.xmlの記述をミスして(DataSourceの設定のfactory属性を書いてなかったり)しばらく悩んだことがあるので、そういった設定周りを再確認してみてください。