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