ひがやすを技術ブログ

電通国際情報サービスのプログラマ

Slim3のトランザクション管理

Slim3トランザクション管理の部分を実装しました。
http://svn.slim3.org/browse/trunk/slim3/slim3-transaction/src/main/java/org/slim3/transaction/
一番のポイントは、どのアプリケーションサーバで動いているかを自動で検知して、適切なセットアップをすることです。これにより、単に設定が楽になるだけではなく、同じ設定ファイルで、テストのときも本番のときも動かすことができます。
設定といってもslim3_configuration.propertiesに次の一行を足すだけ。


slim3.plugins=org.slim3.transaction.plugin.TransactionPlugin
Pluginというのは、アプリケーションの開始時と終了時に呼び出されるクラスで、通常は、Plugin#initialize()で必要な設定を行います。複数のPluginを指定する場合は、カンマで区切ります。
トランザクションの機能を持たないアプリケーションサーバで動くときのロジックは次のようになります。

S3Container container = S3ContainerFactory.getInstance().getContainer();
TransactionManager tm = new TransactionManagerImpl();
UserTransaction ut = new UserTransactionImpl(tm);
container.bind(UserTransaction.class.getSimpleName(), ut);
TransactionController controller = new JtaTransactionController(ut, tm);
container.bind(TransactionController.class.getSimpleName(), controller);
TransactionSynchronizationRegistry registry =
    new TransactionSynchronizationRegistryImpl(tm);
container.bind(TransactionSynchronizationRegistry.class.getSimpleName(), registry);

Slim3では、通常のコンポーネント(ActionとかService)は、何の設定をしなくても自動認識できます。トランザクション管理やコネクションプール管理などのインフラストラクチャ層のコンポーネントは、Pluginを使って、Javaのコードで設定します。


アプリケーションサーバを認識している部分はこんな感じ。特定のクラスが存在するかをチェックしています。

protected static boolean webSpherePresent = ClassUtil
            .isPresent("com.ibm.wsspi.uow.UOWManager");

protected static boolean webLogicPresent = ClassUtil
            .isPresent("weblogic.transaction.UserTransaction");

protected static boolean jbossPresent = ClassUtil
            .isPresent("org.jboss.tm.TxManager");

protected static boolean glassfishPresent = ClassUtil
            .isPresent("com.sun.enterprise.naming.SerialInitContextFactory");

protected static boolean geronimoPresent = ClassUtil
            .isPresent("org.apache.geronimo.kernel.Kernel");

JBossGlassfishGeronimoを特定するクラスがこれでいいのかは、まったく自信がないので、より良いクラスがあれば教えてもらえるとうれしいです。


トランザクションをコントロールするには、UserTransactionをクラスにDIして自前で制御してもいいし、Java標準のTransactionAttributeを使うこともできます。
UserTransactionをDIするのはこんな感じ。

@Resource
protected UserTransaction userTransaction;

Slim3は、名前のみでコンポーネントを探す(デフォルトはフィールド名の先頭を大文字にしたコンポーネントを探す)ので、フィールド名をuserTransactionにするか、@Resource(name = "UserTransaction")のように明示的にname属性を設定します。
TransactionAttributeの使い方はこんな感じ。

@TransactionAttribute
public void foo() {
    ...
}

@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
public void bar() {
    ...
}

TransactionAttributeを設定しない場合は、デフォルトのREQUIREDになります。