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.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
41 if (config == null)
42 {
43 return callback.doInTransaction();
44 }
45
46 Transaction joinedExternal = null;
47 byte action = (config != null) ? config.getAction() : TransactionConfig.ACTION_DEFAULT;
48 Transaction tx = TransactionCoordination.getInstance().getTransaction();
49 if (tx == null && context != null && config != null && config.isInteractWithExternal())
50 {
51
52 TransactionFactory tmFactory = config.getFactory();
53 if (tmFactory instanceof ExternalTransactionAwareTransactionFactory)
54 {
55 ExternalTransactionAwareTransactionFactory extmFactory =
56 (ExternalTransactionAwareTransactionFactory) tmFactory;
57 joinedExternal = tx = extmFactory.joinExternalTransaction(context);
58 }
59 }
60
61 Transaction suspendedXATx = null;
62
63 if (action == TransactionConfig.ACTION_NEVER && tx != null)
64 {
65 throw new IllegalTransactionStateException(
66 CoreMessages.transactionAvailableButActionIs("Never"));
67 }
68 else if ((action == TransactionConfig.ACTION_NONE || action == TransactionConfig.ACTION_ALWAYS_BEGIN)
69 && tx != null)
70 {
71 if (logger.isDebugEnabled())
72 {
73 logger.debug(action + ", " + "current TX: " + tx);
74 }
75
76 if (tx.isXA())
77 {
78
79 suspendedXATx = tx;
80 suspendXATransaction(suspendedXATx);
81 }
82 else
83 {
84
85 resolveTransaction(tx);
86 }
87
88 tx = null;
89 }
90 else if (action == TransactionConfig.ACTION_ALWAYS_JOIN && tx == null)
91 {
92 throw new IllegalTransactionStateException(
93 CoreMessages.transactionNotAvailableButActionIs("Always Join"));
94 }
95
96 if (action == TransactionConfig.ACTION_ALWAYS_BEGIN
97 || (action == TransactionConfig.ACTION_BEGIN_OR_JOIN && tx == null))
98 {
99 logger.debug("Beginning transaction");
100 tx = config.getFactory().beginTransaction(context);
101 logger.debug("Transaction successfully started: " + tx);
102 }
103 else
104 {
105 tx = null;
106 }
107
108 try
109 {
110 T result = callback.doInTransaction();
111 if (tx != null)
112 {
113
114 tx = TransactionCoordination.getInstance().getTransaction();
115 }
116 if (tx != null)
117 {
118 resolveTransaction(tx);
119 }
120 if (suspendedXATx != null)
121 {
122 resumeXATransaction(suspendedXATx);
123 tx = suspendedXATx;
124 }
125 return result;
126 }
127 catch (Exception e)
128 {
129 tx = TransactionCoordination.getInstance().getTransaction();
130 if (tx != null)
131 {
132 tx.setRollbackOnly();
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 return null;
150 }
151 throw e;
152 }
153 catch (Error e)
154 {
155 if (tx != null)
156 {
157 logger.info("Error caught, rolling back TX " + tx, e);
158 tx.rollback();
159 }
160 throw e;
161 }
162 finally
163 {
164 if (joinedExternal != null)
165 TransactionCoordination.getInstance().unbindTransaction(joinedExternal);
166 }
167 }
168
169 protected void resolveTransaction(Transaction tx) throws TransactionException
170 {
171 if (tx.isRollbackOnly())
172 {
173 if (logger.isDebugEnabled())
174 {
175 logger.debug("Transaction has been marked rollbackOnly, rolling it back: " + tx);
176 }
177 tx.rollback();
178 }
179 else
180 {
181 if (logger.isDebugEnabled())
182 {
183 logger.debug("Committing transaction " + tx);
184 }
185 tx.commit();
186 }
187 }
188
189 protected void suspendXATransaction(Transaction tx) throws TransactionException
190 {
191 if (logger.isDebugEnabled())
192 {
193 logger.debug("Suspending " + tx);
194 }
195
196 tx.suspend();
197
198 if (logger.isDebugEnabled())
199 {
200 logger.debug("Successfully suspended " + tx);
201 logger.debug("Unbinding the following TX from the current context: " + tx);
202 }
203
204 TransactionCoordination.getInstance().unbindTransaction(tx);
205 }
206
207 protected void resumeXATransaction(Transaction tx) throws TransactionException
208 {
209 if (logger.isDebugEnabled())
210 {
211 logger.debug("Re-binding and Resuming " + tx);
212 }
213
214 TransactionCoordination.getInstance().bindTransaction(tx);
215 tx.resume();
216 }
217
218 }
219