View Javadoc

1   /*
2    * $Id: TransactionTemplate.java 22654 2011-08-12 07:32:57Z mike.schilling $
3    * --------------------------------------------------------------------------------------
4    * Copyright (c) MuleSoft, Inc.  All rights reserved.  http://www.mulesoft.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.api.MuleContext;
14  import org.mule.api.transaction.ExternalTransactionAwareTransactionFactory;
15  import org.mule.api.transaction.Transaction;
16  import org.mule.api.transaction.TransactionCallback;
17  import org.mule.api.transaction.TransactionConfig;
18  import org.mule.api.transaction.TransactionException;
19  import org.mule.api.transaction.TransactionFactory;
20  import org.mule.config.i18n.CoreMessages;
21  
22  import org.apache.commons.logging.Log;
23  import org.apache.commons.logging.LogFactory;
24  
25  public class TransactionTemplate<T>
26  {
27      private static final Log logger = LogFactory.getLog(TransactionTemplate.class);
28  
29      private final TransactionConfig config;
30      private final MuleContext context;
31  
32      public TransactionTemplate(TransactionConfig config, MuleContext context)
33      {
34          this.config = config;
35          this.context = context;
36      }
37  
38      public T execute(TransactionCallback<T> callback) throws Exception
39      {
40          byte action;
41  
42          // if we want to skip TT
43          if (config == null || (action  = config.getAction()) == TransactionConfig.ACTION_INDIFFERENT)
44          {
45              return callback.doInTransaction();
46          }
47  
48          Transaction joinedExternal = null;
49          Transaction tx = TransactionCoordination.getInstance().getTransaction();
50          if (tx == null && context != null && config != null && config.isInteractWithExternal())
51          {
52  
53              TransactionFactory tmFactory = config.getFactory();
54              if (tmFactory instanceof ExternalTransactionAwareTransactionFactory)
55              {
56                  ExternalTransactionAwareTransactionFactory extmFactory =
57                      (ExternalTransactionAwareTransactionFactory) tmFactory;
58                  joinedExternal = tx = extmFactory.joinExternalTransaction(context);
59              }
60          }
61  
62          Transaction suspendedXATx = null;
63          
64          if (action == TransactionConfig.ACTION_NEVER && tx != null)
65          {
66              throw new IllegalTransactionStateException(
67                  CoreMessages.transactionAvailableButActionIs("Never"));
68          }
69          else if ((action == TransactionConfig.ACTION_NONE || action == TransactionConfig.ACTION_ALWAYS_BEGIN)
70                     && tx != null)
71          {
72              if (logger.isDebugEnabled())
73              {
74                  logger.debug(action + ", " + "current TX: " + tx);
75              }
76  
77              if (tx.isXA())
78              {
79                  // suspend current transaction
80                  suspendedXATx = tx;
81                  suspendXATransaction(suspendedXATx);
82              }
83              else
84              {
85                  // commit/rollback
86                  resolveTransaction(tx);
87              }
88              //transaction will be started below
89              tx = null;
90          }
91          else if (action == TransactionConfig.ACTION_ALWAYS_JOIN && tx == null)
92          {
93              throw new IllegalTransactionStateException(
94                  CoreMessages.transactionNotAvailableButActionIs("Always Join"));
95          }
96  
97          if (action == TransactionConfig.ACTION_ALWAYS_BEGIN
98              || (action == TransactionConfig.ACTION_BEGIN_OR_JOIN && tx == null))
99          {
100             logger.debug("Beginning transaction");
101             tx = config.getFactory().beginTransaction(context);
102             logger.debug("Transaction successfully started: " + tx);
103         }
104         else
105         {
106             tx = null;
107         }
108 
109         T result = callback.doInTransaction();
110         if (tx != null)
111         {
112             //verify that transaction is still active
113             tx = TransactionCoordination.getInstance().getTransaction();
114         }
115         if (tx != null)
116         {
117             resolveTransaction(tx);
118         }
119         if (suspendedXATx != null)
120         {
121             resumeXATransaction(suspendedXATx);
122             tx = suspendedXATx;
123         }
124         if (joinedExternal != null)
125         {
126             TransactionCoordination.getInstance().unbindTransaction(joinedExternal);
127         }
128         return result;
129     }
130 
131     protected void resolveTransaction(Transaction tx) throws TransactionException
132     {
133         if (tx.isRollbackOnly())
134         {
135             if (logger.isDebugEnabled())
136             {
137                 logger.debug("Transaction has been marked rollbackOnly, rolling it back: " + tx);
138             }
139             tx.rollback();
140         }
141         else
142         {
143             if (logger.isDebugEnabled())
144             {
145                 logger.debug("Committing transaction " + tx);
146             }
147             tx.commit();
148         }
149     }
150 
151     protected void suspendXATransaction(Transaction tx) throws TransactionException
152     {
153         if (logger.isDebugEnabled())
154         {
155             logger.debug("Suspending " + tx);
156         }
157 
158         tx.suspend();
159 
160         if (logger.isDebugEnabled())
161         {
162             logger.debug("Successfully suspended " + tx);
163             logger.debug("Unbinding the following TX from the current context: " + tx);
164         }
165 
166         TransactionCoordination.getInstance().unbindTransaction(tx);
167     }
168 
169     protected void resumeXATransaction(Transaction tx) throws TransactionException
170     {
171         if (logger.isDebugEnabled())
172         {
173             logger.debug("Re-binding and Resuming " + tx);
174         }
175 
176         TransactionCoordination.getInstance().bindTransaction(tx);
177         tx.resume();
178     }
179 
180 }
181