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