View Javadoc

1   /*
2    * $Id: TransactionTemplate.java 12181 2008-06-26 20:05:55Z dirk.olmes $
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.api.MuleContext;
14  import org.mule.api.transaction.Transaction;
15  import org.mule.api.transaction.TransactionCallback;
16  import org.mule.api.transaction.TransactionConfig;
17  import org.mule.api.transaction.TransactionException;
18  import org.mule.config.i18n.CoreMessages;
19  
20  import java.beans.ExceptionListener;
21  
22  import org.apache.commons.logging.Log;
23  import org.apache.commons.logging.LogFactory;
24  
25  public class TransactionTemplate
26  {
27      private static final Log logger = LogFactory.getLog(TransactionTemplate.class);
28  
29      private final TransactionConfig config;
30      private final ExceptionListener exceptionListener;
31      private final MuleContext context;
32  
33      public TransactionTemplate(TransactionConfig config, ExceptionListener listener, MuleContext context)
34      {
35          this.config = config;
36          exceptionListener = listener;
37          this.context = context;
38      }
39  
40      public Object execute(TransactionCallback callback) throws Exception
41      {
42          //if we want to skip TT
43          if (config == null)
44          {
45              return callback.doInTransaction();
46          }
47  
48          byte action = (config != null) ? config.getAction() : TransactionConfig.ACTION_DEFAULT;
49          Transaction tx = TransactionCoordination.getInstance().getTransaction();
50          Transaction suspendedXATx = null;
51          
52          if (action == TransactionConfig.ACTION_NEVER && tx != null)
53          {
54              throw new IllegalTransactionStateException(
55                  CoreMessages.transactionAvailableButActionIs("Never"));
56          }
57          else if ((action == TransactionConfig.ACTION_NONE || action == TransactionConfig.ACTION_ALWAYS_BEGIN)
58                     && tx != null)
59          {
60              if (logger.isDebugEnabled())
61              {
62                  logger.debug(action + ", " + "current TX: " + tx);
63              }
64  
65              if (tx.isXA())
66              {
67                  // suspend current transaction
68                  suspendedXATx = tx;
69                  suspendXATransaction(suspendedXATx);
70              }
71              else
72              {
73                  // commit/rollback
74                  resolveTransaction(tx);
75              }
76              //transaction will be started below
77              tx = null;
78          }
79          else if (action == TransactionConfig.ACTION_ALWAYS_JOIN && tx == null)
80          {
81              throw new IllegalTransactionStateException(
82                  CoreMessages.transactionNotAvailableButActionIs("Always Join"));
83          }
84  
85          if (action == TransactionConfig.ACTION_ALWAYS_BEGIN
86              || (action == TransactionConfig.ACTION_BEGIN_OR_JOIN && tx == null))
87          {
88              logger.debug("Beginning transaction");
89              tx = config.getFactory().beginTransaction(context);
90              logger.debug("Transaction successfully started: " + tx);
91          }
92          else
93          {
94              tx = null;
95          }
96  
97          try
98          {
99              Object 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             return result;
115         }
116         catch (Exception e)
117         {
118             if (exceptionListener != null)
119             {
120                 logger.info("Exception Caught in Transaction template.  Handing off to exception handler: "
121                     + exceptionListener);
122                 exceptionListener.exceptionThrown(e);
123             }
124             else
125             {
126                 logger.info("Exception Caught in Transaction template without any exception listeners defined, exception is rethrown.");
127                 if (tx != null)
128                 {
129                     tx.setRollbackOnly();
130                 }
131             }
132             if (tx != null)
133             {
134                 // The exception strategy can choose to route exception
135                 // messages as part of the current transaction. So only rollback the
136                 // tx if it has been marked for rollback (which is the default
137                 // case in the AbstractExceptionListener)
138                 if (tx.isRollbackOnly())
139                 {
140                     logger.debug("Exception caught: rollback transaction", e);
141                 }
142                 resolveTransaction(tx);
143             }
144             if (suspendedXATx != null)
145             {
146                 resumeXATransaction(suspendedXATx);
147             }
148 
149             throw e;
150         }
151         catch (Error e)
152         {
153             if (tx != null)
154             {
155                 logger.info("Error caught, rolling back TX " + tx, e);
156                 tx.rollback();
157             }
158             throw e;
159         }
160     }
161 
162     protected void resolveTransaction(Transaction tx) throws TransactionException
163     {
164         if (tx.isRollbackOnly())
165         {
166             logger.debug("Transaction has been marked rollbackOnly, rolling it back: " + tx);
167             tx.rollback();
168         }
169         else
170         {
171             logger.debug("Committing transaction " + tx);
172             tx.commit();
173         }
174     }
175 
176     protected void suspendXATransaction(Transaction tx) throws TransactionException
177     {
178         if (logger.isDebugEnabled())
179         {
180             logger.debug("Suspending " + tx);
181         }
182 
183         tx.suspend();
184 
185         if (logger.isDebugEnabled())
186         {
187             logger.debug("Successfully suspended " + tx);
188             logger.debug("Unbinding the following TX from the current context: " + tx);
189         }
190 
191         TransactionCoordination.getInstance().unbindTransaction(tx);
192     }
193 
194     protected void resumeXATransaction(Transaction tx) throws TransactionException
195     {
196         if (logger.isDebugEnabled())
197         {
198             logger.debug("Re-binding and Resuming " + tx);
199         }
200 
201         TransactionCoordination.getInstance().bindTransaction(tx);
202         tx.resume();
203     }
204 
205 }