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