/* * Copyright 2004-2015 the Seasar Foundation and the Others. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, * either express or implied. See the License for the specific language * governing permissions and limitations under the License. */ package org.seasar.extension.tx.adapter; import javax.transaction.TransactionRolledbackException; import org.seasar.extension.tx.TransactionCallback; import org.seasar.extension.tx.TransactionManagerAdapter; import org.seasar.framework.exception.SIllegalStateException; import org.seasar.framework.log.Logger; import com.ibm.websphere.uow.UOWSynchronizationRegistry; import com.ibm.wsspi.uow.UOWAction; import com.ibm.wsspi.uow.UOWActionException; import com.ibm.wsspi.uow.UOWException; import com.ibm.wsspi.uow.UOWManager; /** * WebSphere version 6 (6.0.2.19以降または6.1.0.9以降) が提供するUOW APIを使用してトランザクションを制御する、 * {@link TransactionManagerAdapter}の実装です。 * * @author koichik * @since 2.4.18 */ public class WAS6TransactionManagerAdapter implements TransactionManagerAdapter { /** グローバルトランザクションを示します */ protected static final int GLOBAL_TX = UOWSynchronizationRegistry.UOW_TYPE_GLOBAL_TRANSACTION; /** ローカルトランザクションを示します */ protected static final int LOCAL_TX = UOWSynchronizationRegistry.UOW_TYPE_LOCAL_TRANSACTION; /** 既存のトランザクションがあれば参加することを示します */ protected static final boolean JOIN_TX = true; /** 新規のトランザクションを開始することを示します */ protected static final boolean NEW_TX = false; private static final Logger logger = Logger .getLogger(WAS6TransactionManagerAdapter.class); /** UOW API の提供するトランザクションマネージャ */ protected final UOWManager uowManager; /** * インスタンスを構築します。 * * @param uowManager * UOW API の提供するトランザクションマネージャ */ public WAS6TransactionManagerAdapter(final UOWManager uowManager) { this.uowManager = uowManager; } public Object required(final TransactionCallback callback) throws Throwable { return executeCallback(callback, GLOBAL_TX, JOIN_TX); } public Object requiresNew(final TransactionCallback callback) throws Throwable { return executeCallback(callback, GLOBAL_TX, NEW_TX); } public Object mandatory(final TransactionCallback callback) throws Throwable { if (!hasTransaction()) { throw new SIllegalStateException("ESSR0311", null); } return callback.execute(this); } public Object notSupported(final TransactionCallback callback) throws Throwable { return executeCallback(callback, LOCAL_TX, NEW_TX); } public Object never(final TransactionCallback callback) throws Throwable { if (hasTransaction()) { throw new SIllegalStateException("ESSR0317", null); } return callback.execute(this); } public void setRollbackOnly() { try { if (uowManager.getUOWStatus() == UOWSynchronizationRegistry.UOW_STATUS_ACTIVE) { uowManager.setRollbackOnly(); } } catch (final Exception e) { logger.log("ESSR0017", new Object[] { e.getMessage() }, e); } } /** * トランザクション制御下でトランザクションコールバックを呼び出します。 * * @param callback * トランザクションコールバック * @param transactionType * {@link #GLOBAL_TX}または{@link #LOCAL_TX} * @param joinTransaction * {@link #JOIN_TX}または{@link #NEW_TX} * @return トランザクションコールバックの戻り値 * @throws Throwable * トランザクションコールバックが例外をスローした場合 */ protected Object executeCallback(final TransactionCallback callback, final int transactionType, final boolean joinTransaction) throws Throwable { try { final UOWActionImpl action = new UOWActionImpl(callback); uowManager.runUnderUOW(transactionType, joinTransaction, action); return action.getResult(); } catch (final UOWActionException e) { final Throwable cause = e.getCause(); if (cause instanceof WrappedException) { throw cause.getCause(); } throw cause; } catch (final UOWException e) { final TransactionRolledbackException ex = new TransactionRolledbackException( e.getMessage()); ex.detail = e; throw ex; } } /** * 現在のスレッド上でトランザクションが開始されている場合は<code>true</code>を、それ以外の場合は<code>false</code> * を返します。 * * @return 現在のスレッド上でトランザクションが開始されている場合は<code>true</code> */ protected boolean hasTransaction() { return uowManager.getUOWStatus() != UOWSynchronizationRegistry.UOW_STATUS_NONE; } /** * <code>UOWManager</code>が制御するトランザクション中に実行するアクションの実装です。 * * @author koichik */ public class UOWActionImpl implements UOWAction { /** トランザクションコールバック */ protected TransactionCallback callback; /** トランザクションコールバックの戻り値 */ protected Object result; /** * インスタンスを構築します。 * * @param callback * トランザクションコールバック */ public UOWActionImpl(final TransactionCallback callback) { this.callback = callback; } /** * <code>UOWManager</code>から呼び出されます。 */ public void run() throws Exception { try { result = callback.execute(WAS6TransactionManagerAdapter.this); } catch (final Throwable e) { throw new WrappedException(e); } } /** * トランザクションコールバックの戻り値を返します。 * * @return トランザクションコールバックの戻り値 */ public Object getResult() { return result; } } /** * トランザクションコールバックからスローされた例外をラップする例外です。 * <p> * <code>UOWAction</code>からチェックされない例外をスローするとトランザクションがロールバックされてしまうので、 * トランザクションコールバックで発生した例外は全てこの例外でラップします。 トランザクションの制御 (コミットするかロールバックするかの判定) * はトランザクションコールバックで完了しています。 * </p> * * @author koichik */ public static class WrappedException extends Exception { private static final long serialVersionUID = 1L; /** * インスタンスを構築します。 * * @param cause * 原因となった例外 */ public WrappedException(final Throwable cause) { super(cause); } } }