Home » activemq-parent-5.3.1-source-release » org.apache » activemq » transaction » [javadoc | source]

    1   /**
    2    * Licensed to the Apache Software Foundation (ASF) under one or more
    3    * contributor license agreements.  See the NOTICE file distributed with
    4    * this work for additional information regarding copyright ownership.
    5    * The ASF licenses this file to You under the Apache License, Version 2.0
    6    * (the "License"); you may not use this file except in compliance with
    7    * the License.  You may obtain a copy of the License at
    8    *
    9    *      http://www.apache.org/licenses/LICENSE-2.0
   10    *
   11    * Unless required by applicable law or agreed to in writing, software
   12    * distributed under the License is distributed on an "AS IS" BASIS,
   13    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   14    * See the License for the specific language governing permissions and
   15    * limitations under the License.
   16    */
   17   package org.apache.activemq.transaction;
   18   
   19   import java.io.IOException;
   20   
   21   import javax.transaction.xa.XAException;
   22   import javax.transaction.xa.XAResource;
   23   
   24   import org.apache.activemq.broker.TransactionBroker;
   25   import org.apache.activemq.command.TransactionId;
   26   import org.apache.activemq.command.XATransactionId;
   27   import org.apache.activemq.store.TransactionStore;
   28   import org.apache.commons.logging.Log;
   29   import org.apache.commons.logging.LogFactory;
   30   
   31   /**
   32    * @version $Revision: 1.4 $
   33    */
   34   public class XATransaction extends Transaction {
   35   
   36       private static final Log LOG = LogFactory.getLog(XATransaction.class);
   37   
   38       private final TransactionStore transactionStore;
   39       private final XATransactionId xid;
   40       private final TransactionBroker broker;
   41   
   42       public XATransaction(TransactionStore transactionStore, XATransactionId xid, TransactionBroker broker) {
   43           this.transactionStore = transactionStore;
   44           this.xid = xid;
   45           this.broker = broker;
   46           if (LOG.isDebugEnabled()) {
   47               LOG.debug("XA Transaction new/begin : " + xid);
   48           }
   49       }
   50   
   51       public void commit(boolean onePhase) throws XAException, IOException {
   52           if (LOG.isDebugEnabled()) {
   53               LOG.debug("XA Transaction commit: " + xid);
   54           }
   55   
   56           switch (getState()) {
   57           case START_STATE:
   58               // 1 phase commit, no work done.
   59               checkForPreparedState(onePhase);
   60               setStateFinished();
   61               break;
   62           case IN_USE_STATE:
   63               // 1 phase commit, work done.
   64               checkForPreparedState(onePhase);
   65               doPrePrepare();
   66               setStateFinished();
   67               transactionStore.commit(getTransactionId(), false);
   68               doPostCommit();
   69               break;
   70           case PREPARED_STATE:
   71               // 2 phase commit, work done.
   72               // We would record commit here.
   73               setStateFinished();
   74               transactionStore.commit(getTransactionId(), true);
   75               doPostCommit();
   76               break;
   77           default:
   78               illegalStateTransition("commit");
   79           }
   80       }
   81   
   82       private void illegalStateTransition(String callName) throws XAException {
   83           XAException xae = new XAException("Cannot call " + callName + " now.");
   84           xae.errorCode = XAException.XAER_PROTO;
   85           throw xae;
   86       }
   87   
   88       private void checkForPreparedState(boolean onePhase) throws XAException {
   89           if (!onePhase) {
   90               XAException xae = new XAException("Cannot do 2 phase commit if the transaction has not been prepared.");
   91               xae.errorCode = XAException.XAER_PROTO;
   92               throw xae;
   93           }
   94       }
   95   
   96       private void doPrePrepare() throws XAException, IOException {
   97           try {
   98               prePrepare();
   99           } catch (XAException e) {
  100               throw e;
  101           } catch (Throwable e) {
  102               LOG.warn("PRE-PREPARE FAILED: ", e);
  103               rollback();
  104               XAException xae = new XAException("PRE-PREPARE FAILED: Transaction rolled back.");
  105               xae.errorCode = XAException.XA_RBOTHER;
  106               xae.initCause(e);
  107               throw xae;
  108           }
  109       }
  110   
  111       private void doPostCommit() throws XAException {
  112           try {
  113               fireAfterCommit();
  114           } catch (Throwable e) {
  115               // I guess this could happen. Post commit task failed
  116               // to execute properly.
  117               LOG.warn("POST COMMIT FAILED: ", e);
  118               XAException xae = new XAException("POST COMMIT FAILED");
  119               xae.errorCode = XAException.XAER_RMERR;
  120               xae.initCause(e);
  121               throw xae;
  122           }
  123       }
  124   
  125       public void rollback() throws XAException, IOException {
  126   
  127           if (LOG.isDebugEnabled()) {
  128               LOG.debug("XA Transaction rollback: " + xid);
  129           }
  130   
  131           switch (getState()) {
  132           case START_STATE:
  133               // 1 phase rollback no work done.
  134               setStateFinished();
  135               break;
  136           case IN_USE_STATE:
  137               // 1 phase rollback work done.
  138               setStateFinished();
  139               transactionStore.rollback(getTransactionId());
  140               doPostRollback();
  141               break;
  142           case PREPARED_STATE:
  143               // 2 phase rollback work done.
  144               setStateFinished();
  145               transactionStore.rollback(getTransactionId());
  146               doPostRollback();
  147               break;
  148           default:
  149               throw new XAException("Invalid state");
  150           }
  151   
  152       }
  153   
  154       private void doPostRollback() throws XAException {
  155           try {
  156               fireAfterRollback();
  157           } catch (Throwable e) {
  158               // I guess this could happen. Post commit task failed
  159               // to execute properly.
  160               LOG.warn("POST ROLLBACK FAILED: ", e);
  161               XAException xae = new XAException("POST ROLLBACK FAILED");
  162               xae.errorCode = XAException.XAER_RMERR;
  163               xae.initCause(e);
  164               throw xae;
  165           }
  166       }
  167   
  168       public int prepare() throws XAException, IOException {
  169           if (LOG.isDebugEnabled()) {
  170               LOG.debug("XA Transaction prepare: " + xid);
  171           }
  172   
  173           switch (getState()) {
  174           case START_STATE:
  175               // No work done.. no commit/rollback needed.
  176               setStateFinished();
  177               return XAResource.XA_RDONLY;
  178           case IN_USE_STATE:
  179               // We would record prepare here.
  180               doPrePrepare();
  181               setState(Transaction.PREPARED_STATE);
  182               transactionStore.prepare(getTransactionId());
  183               return XAResource.XA_OK;
  184           default:
  185               illegalStateTransition("prepare");
  186               return XAResource.XA_RDONLY;
  187           }
  188       }
  189   
  190       private void setStateFinished() {
  191           setState(Transaction.FINISHED_STATE);
  192           broker.removeTransaction(xid);
  193       }
  194   
  195       public TransactionId getTransactionId() {
  196           return xid;
  197       }
  198   }

Home » activemq-parent-5.3.1-source-release » org.apache » activemq » transaction » [javadoc | source]