Coverage Report - org.mule.transaction.TransactionTemplate
 
Classes in this File Line Coverage Branch Coverage Complexity
TransactionTemplate
9%
7/74
7%
4/54
6.8
 
 1  
 /*
 2  
  * $Id: TransactionTemplate.java 10524 2008-01-24 19:20:11Z akuzmin $
 3  
  * --------------------------------------------------------------------------------------
 4  
  * Copyright (c) MuleSource, Inc.  All rights reserved.  http://www.mulesource.com
 5  
  *
 6  
  * The software in this package is published under the terms of the CPAL v1.0
 7  
  * license, a copy of which has been included with this distribution in the
 8  
  * LICENSE.txt file.
 9  
  */
 10  
 
 11  
 package org.mule.transaction;
 12  
 
 13  
 import org.mule.config.i18n.CoreMessages;
 14  
 import org.mule.umo.TransactionException;
 15  
 import org.mule.umo.UMOTransaction;
 16  
 import org.mule.umo.UMOTransactionConfig;
 17  
 
 18  
 import java.beans.ExceptionListener;
 19  
 
 20  
 import org.apache.commons.logging.Log;
 21  
 import org.apache.commons.logging.LogFactory;
 22  
 
 23  
 public class TransactionTemplate
 24  
 {
 25  4
     private static final Log logger = LogFactory.getLog(TransactionTemplate.class);
 26  
 
 27  
     private final UMOTransactionConfig config;
 28  
     private final ExceptionListener exceptionListener;
 29  
 
 30  
     public TransactionTemplate(UMOTransactionConfig config, ExceptionListener listener)
 31  122
     {
 32  122
         this.config = config;
 33  122
         exceptionListener = listener;
 34  122
     }
 35  
 
 36  
     public Object execute(TransactionCallback callback) throws Exception
 37  
     {
 38  122
         if (config == null || (config!=null && !config.isConfigured()))
 39  
         {
 40  122
             return callback.doInTransaction();
 41  
         }
 42  
         else
 43  
         {
 44  0
             byte action = config.getAction();
 45  0
             UMOTransaction tx = TransactionCoordination.getInstance().getTransaction();
 46  0
             UMOTransaction suspendedXATx = null;
 47  
 
 48  0
             if (action == UMOTransactionConfig.ACTION_NONE && tx != null)
 49  
             {
 50  
                 //TODO RM*: I'm not sure there is any value in throwing an exection here, since
 51  
                 //there may be a transaction in progress but has nothing to to with this invocation
 52  
                 //so maybe we just process outside the tx. Not sure yet
 53  
                 //return callback.doInTransaction();
 54  
 
 55  
                 /*
 56  
                     Reply from AP: There is value at the moment, at least in having fewer surprises
 57  
                     with a more explicit config. Current behavior is that of 'Never' TX attribute
 58  
                     in Java EE parlance.
 59  
 
 60  
                     What you refer to, however, is the 'Not Supported' TX behavior. A SUSPEND is performed
 61  
                     in this case with (optional) RESUME later.
 62  
 
 63  
                  */
 64  
 
 65  0
                 throw new IllegalTransactionStateException(
 66  
                     CoreMessages.transactionAvailableButActionIs("None"));
 67  
             }
 68  0
             else if (action == UMOTransactionConfig.ACTION_ALWAYS_BEGIN && tx != null)
 69  
             {
 70  0
                 if (logger.isDebugEnabled())
 71  
                 {
 72  0
                     logger.debug("Transaction action is ACTION_ALWAYS_BEGIN, " +
 73  
                                  "current TX: " + tx);
 74  
                 }
 75  0
                 if (tx.isXA())
 76  
                 {
 77  
                     // suspend current transaction
 78  0
                     suspendedXATx = tx;
 79  0
                     suspendXATransaction(suspendedXATx);
 80  
                 }
 81  
                 else
 82  
                 {
 83  
                     // commit/rollback
 84  0
                     resolveTransaction(tx);
 85  
                 }
 86  
                 //transaction will be started below
 87  0
                 tx = null;
 88  
             }
 89  0
             else if (action == UMOTransactionConfig.ACTION_ALWAYS_JOIN && tx == null)
 90  
             {
 91  0
                 throw new IllegalTransactionStateException(
 92  
                     CoreMessages.transactionNotAvailableButActionIs("Always Join"));
 93  
             }
 94  
 
 95  0
             if (action == UMOTransactionConfig.ACTION_ALWAYS_BEGIN
 96  
                             || (action == UMOTransactionConfig.ACTION_BEGIN_OR_JOIN && tx == null))
 97  
             {
 98  0
                 logger.debug("Beginning transaction");
 99  0
                 tx = config.getFactory().beginTransaction();
 100  0
                 logger.debug("Transaction successfully started: " + tx);
 101  
             }
 102  
             else
 103  
             {
 104  0
                 tx = null;
 105  
             }
 106  
             try
 107  
             {
 108  0
                 Object result = callback.doInTransaction();
 109  0
                 if (tx != null)
 110  
                 {
 111  0
                     resolveTransaction(tx);
 112  0
                     if (suspendedXATx != null)
 113  
                     {
 114  0
                         resumeXATransaction(suspendedXATx);
 115  0
                         tx = suspendedXATx;
 116  
                     }
 117  
                 }
 118  0
                 return result;
 119  
             }
 120  0
             catch (Exception e)
 121  
             {
 122  0
                 if (exceptionListener != null)
 123  
                 {
 124  0
                     logger.info("Exception Caught in Transaction template.  Handing off to exception handler: "
 125  
                                         + exceptionListener);
 126  0
                     exceptionListener.exceptionThrown(e);
 127  
                 }
 128  
                 else
 129  
                 {
 130  0
                     logger
 131  
                         .info("Exception Caught in Transaction template without any exception listeners defined, exception is rethrown.");
 132  0
                     if (tx != null)
 133  
                     {
 134  0
                         tx.setRollbackOnly();
 135  
                     }
 136  
                 }
 137  0
                 if (tx != null)
 138  
                 {
 139  
                     // The exception strategy can choose to route exception
 140  
                     // messages
 141  
                     // as part of the current transaction. So only rollback the
 142  
                     // tx
 143  
                     // if it has been marked for rollback (which is the default
 144  
                     // case in the
 145  
                     // AbstractExceptionListener)
 146  0
                     if (tx.isRollbackOnly())
 147  
                     {
 148  0
                         logger.debug("Exception caught: rollback transaction", e);
 149  
                     }
 150  0
                     resolveTransaction(tx);
 151  0
                     if (suspendedXATx != null)
 152  
                     {
 153  0
                         resumeXATransaction(suspendedXATx);
 154  
                     }
 155  
                 }
 156  
                 // we've handled this exception above. just return null now
 157  0
                 if (exceptionListener != null)
 158  
                 {
 159  0
                     return null;
 160  
                 }
 161  
                 else
 162  
                 {
 163  0
                     throw e;
 164  
                 }
 165  
             }
 166  0
             catch (Error e)
 167  
             {
 168  0
                 if (tx != null)
 169  
                 {
 170  0
                     logger.info("Error caught, rolling back TX " + tx, e);
 171  0
                     tx.rollback();
 172  
                 }
 173  0
                 throw e;
 174  
             }
 175  
         }
 176  
     }
 177  
 
 178  
     protected void resolveTransaction(UMOTransaction tx) throws TransactionException
 179  
     {
 180  0
         if (tx.isRollbackOnly())
 181  
         {
 182  0
             logger.debug("Transaction has been marked rollbackOnly, rolling it back: " + tx);
 183  0
             tx.rollback();
 184  
         }
 185  
         else
 186  
         {
 187  0
             logger.debug("Committing transaction " + tx);
 188  0
             tx.commit();
 189  
         }
 190  0
     }
 191  
 
 192  
     protected void suspendXATransaction(UMOTransaction tx) throws TransactionException
 193  
     {
 194  0
         if (logger.isDebugEnabled())
 195  
         {
 196  0
             logger.debug("Suspending " + tx);
 197  
         }
 198  
 
 199  0
         tx.suspend();
 200  
 
 201  0
         if (logger.isDebugEnabled())
 202  
         {
 203  0
             logger.debug("Successfully suspended " + tx);
 204  0
             logger.debug("Unbinding the following TX from the current context: " + tx);
 205  
         }
 206  
         
 207  0
         TransactionCoordination.getInstance().unbindTransaction(tx);
 208  0
     }
 209  
 
 210  
     protected void resumeXATransaction(UMOTransaction tx) throws TransactionException
 211  
     {
 212  0
         if (logger.isDebugEnabled())
 213  
         {
 214  0
             logger.debug("Re-binding and Resuming " + tx);
 215  
         }
 216  
 
 217  0
         TransactionCoordination.getInstance().bindTransaction(tx);
 218  0
         tx.resume();
 219  0
     }
 220  
 
 221  
 }