1
2
3
4
5
6
7 package org.mule.transaction;
8
9 import org.mule.api.MuleContext;
10 import org.mule.api.transaction.TransactionException;
11 import org.mule.config.i18n.CoreMessages;
12 import org.mule.config.i18n.MessageFactory;
13
14 import java.util.HashMap;
15 import java.util.Iterator;
16 import java.util.Map;
17
18 import javax.transaction.HeuristicRollbackException;
19 import javax.transaction.InvalidTransactionException;
20 import javax.transaction.RollbackException;
21 import javax.transaction.SystemException;
22 import javax.transaction.Transaction;
23 import javax.transaction.TransactionManager;
24 import javax.transaction.xa.XAResource;
25
26
27
28
29 public class XaTransaction extends AbstractTransaction
30 {
31
32
33
34 protected Transaction transaction = null;
35
36
37
38
39 private Map resources = new HashMap();
40
41 protected TransactionManager txManager;
42
43 public XaTransaction(MuleContext context)
44 {
45 super(context);
46 this.txManager = context.getTransactionManager();
47 }
48
49 protected void doBegin() throws TransactionException
50 {
51 if (txManager == null)
52 {
53 throw new IllegalStateException(
54 CoreMessages.objectNotRegistered("javax.transaction.TransactionManager", "Transaction Manager").getMessage());
55 }
56
57 try
58 {
59 txManager.begin();
60 synchronized (this)
61 {
62 transaction = txManager.getTransaction();
63 }
64 }
65 catch (Exception e)
66 {
67 throw new TransactionException(CoreMessages.cannotStartTransaction("XA"), e);
68 }
69 }
70
71 protected synchronized void doCommit() throws TransactionException
72 {
73 try
74 {
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112 delistResources();
113 txManager.commit();
114 }
115 catch (RollbackException e)
116 {
117 throw new TransactionRollbackException(CoreMessages.transactionMarkedForRollback(), e);
118 }
119 catch (HeuristicRollbackException e)
120 {
121 throw new TransactionRollbackException(CoreMessages.transactionMarkedForRollback(), e);
122 }
123 catch (Exception e)
124 {
125 throw new IllegalTransactionStateException(CoreMessages.transactionCommitFailed(), e);
126 }
127 finally
128 {
129
130
131
132
133
134
135
136 this.transaction = null;
137 closeResources();
138 }
139 }
140
141 protected void doRollback() throws TransactionRollbackException
142 {
143 try
144 {
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183 txManager.rollback();
184 }
185 catch (SystemException e)
186 {
187 throw new TransactionRollbackException(e);
188 }
189 catch (Exception e)
190 {
191 throw new TransactionRollbackException(e);
192 }
193 finally
194 {
195
196
197
198
199
200
201
202 this.transaction = null;
203 closeResources();
204 }
205 }
206
207 public synchronized int getStatus() throws TransactionStatusException
208 {
209 if (transaction == null)
210 {
211 return STATUS_NO_TRANSACTION;
212 }
213
214 try
215 {
216 return transaction.getStatus();
217 }
218 catch (SystemException e)
219 {
220 throw new TransactionStatusException(e);
221 }
222 }
223
224 public void setRollbackOnly()
225 {
226 if (transaction == null)
227 {
228 throw new IllegalStateException("Current thread is not associated with a transaction.");
229 }
230
231 try
232 {
233 synchronized (this)
234 {
235 transaction.setRollbackOnly();
236 }
237 }
238 catch (SystemException e)
239 {
240 throw (IllegalStateException) new IllegalStateException(
241 "Failed to set transaction to rollback only: " + e.getMessage()
242 ).initCause(e);
243 }
244 }
245
246 public synchronized Object getResource(Object key)
247 {
248 return resources.get(key);
249 }
250
251 public synchronized boolean hasResource(Object key)
252 {
253 return resources.containsKey(key);
254 }
255
256 public synchronized void bindResource(Object key, Object resource) throws TransactionException
257 {
258 if (resources.containsKey(key))
259 {
260 throw new IllegalTransactionStateException(
261 CoreMessages.transactionResourceAlreadyListedForKey(key));
262 }
263
264 resources.put(key, resource);
265
266 if (key == null)
267 {
268 logger.error("Key for bound resource " + resource + " is null");
269 }
270
271 if (resource instanceof MuleXaObject)
272 {
273 MuleXaObject xaObject = (MuleXaObject) resource;
274 xaObject.enlist();
275 }
276 else if (resource instanceof XAResource)
277 {
278 enlistResource((XAResource) resource);
279 }
280 else
281 {
282 logger.error("Bound resource " + resource + " is neither a MuleXaObject nor XAResource");
283 }
284 }
285
286
287
288 public boolean enlistResource(XAResource resource) throws TransactionException
289 {
290 TransactionManager txManager = muleContext.getTransactionManager();
291 try
292 {
293 Transaction jtaTransaction = txManager.getTransaction();
294 if (jtaTransaction == null)
295 {
296 throw new TransactionException(MessageFactory.createStaticMessage("XATransaction is null"));
297 }
298 return jtaTransaction.enlistResource(resource);
299 }
300 catch (RollbackException e)
301 {
302 throw new TransactionException(e);
303 }
304 catch (SystemException e)
305 {
306 throw new TransactionException(e);
307 }
308 }
309
310 public boolean delistResource(XAResource resource, int tmflag) throws TransactionException
311 {
312 TransactionManager txManager = muleContext.getTransactionManager();
313 try
314 {
315 Transaction jtaTransaction = txManager.getTransaction();
316 if (jtaTransaction == null)
317 {
318 throw new TransactionException(CoreMessages.noJtaTransactionAvailable(Thread.currentThread()));
319 }
320 return jtaTransaction.delistResource(resource, tmflag);
321 }
322 catch (SystemException e)
323 {
324 throw new TransactionException(e);
325 }
326 }
327
328
329 public String toString()
330 {
331 return transaction == null ? " <n/a>" : transaction.toString();
332 }
333
334 public Transaction getTransaction()
335 {
336 return transaction;
337 }
338
339 public boolean isXA()
340 {
341 return true;
342 }
343
344 public void resume() throws TransactionException
345 {
346 TransactionManager txManager = muleContext.getTransactionManager();
347
348 if (txManager == null)
349 {
350 throw new IllegalStateException(
351 CoreMessages.objectNotRegistered("javax.transaction.TransactionManager", "Transaction Manager").getMessage());
352 }
353 try
354 {
355 txManager.resume(transaction);
356 }
357 catch (InvalidTransactionException e)
358 {
359 throw new TransactionException(e);
360 }
361 catch (SystemException e)
362 {
363 throw new TransactionException(e);
364 }
365 }
366
367 public Transaction suspend() throws TransactionException
368 {
369 TransactionManager txManager = muleContext.getTransactionManager();
370
371 if (txManager == null)
372 {
373 throw new IllegalStateException(
374 CoreMessages.objectNotRegistered("javax.transaction.TransactionManager", "Transaction Manager").getMessage());
375 }
376 try
377 {
378 transaction = txManager.suspend();
379 }
380 catch (SystemException e)
381 {
382 throw new TransactionException(e);
383 }
384 return transaction;
385 }
386
387 protected void delistResources()
388 {
389 Iterator i = resources.entrySet().iterator();
390 while (i.hasNext())
391 {
392 Map.Entry entry = (Map.Entry) i.next();
393 final Object xaObject = entry.getValue();
394 if (xaObject instanceof MuleXaObject)
395 {
396
397 try
398 {
399 ((MuleXaObject) xaObject).delist();
400 }
401 catch (Exception e)
402 {
403 logger.error("Failed to delist resource " + xaObject, e);
404 }
405 }
406 }
407 }
408
409 protected void closeResources()
410 {
411 Iterator i = resources.entrySet().iterator();
412 while (i.hasNext())
413 {
414 Map.Entry entry = (Map.Entry) i.next();
415 final Object value = entry.getValue();
416 if (value instanceof MuleXaObject)
417 {
418 MuleXaObject xaObject = (MuleXaObject) value;
419 if (!xaObject.isReuseObject())
420 {
421 try
422 {
423 xaObject.close();
424 i.remove();
425 }
426 catch (Exception e)
427 {
428 logger.error("Failed to close resource " + xaObject, e);
429 }
430 }
431 }
432 }
433 }
434
435 public static interface MuleXaObject
436 {
437
438 void close() throws Exception;
439
440 void setReuseObject(boolean reuseObject);
441
442 boolean isReuseObject();
443
444 boolean enlist() throws TransactionException;
445
446 boolean delist() throws Exception;
447
448
449
450
451
452
453 Object getTargetObject();
454
455 String SET_REUSE_OBJECT_METHOD_NAME = "setReuseObject";
456 String IS_REUSE_OBJECT_METHOD_NAME = "isReuseObject";
457 String DELIST_METHOD_NAME = "delist";
458 String ENLIST_METHOD_NAME = "enlist";
459 String GET_TARGET_OBJECT_METHOD_NAME = "getTargetObject";
460 String CLOSE_METHOD_NAME = "close";
461 }
462
463 }