1
2
3
4
5
6
7
8
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
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
68 suspendedXATx = tx;
69 suspendXATransaction(suspendedXATx);
70 }
71 else
72 {
73
74 resolveTransaction(tx);
75 }
76
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
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
135
136
137
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 }