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