1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.geronimo.transaction.manager;
19
20 import java.io.PrintWriter;
21 import java.io.StringWriter;
22 import java.io.Writer;
23 import java.util.ArrayList;
24 import java.util.HashMap;
25 import java.util.IdentityHashMap;
26 import java.util.Iterator;
27 import java.util.LinkedList;
28 import java.util.List;
29 import java.util.Map;
30 import java.util.Set;
31
32 import javax.transaction.HeuristicMixedException;
33 import javax.transaction.HeuristicRollbackException;
34 import javax.transaction.RollbackException;
35 import javax.transaction.Status;
36 import javax.transaction.Synchronization;
37 import javax.transaction.SystemException;
38 import javax.transaction.Transaction;
39 import javax.transaction.xa.XAException;
40 import javax.transaction.xa.XAResource;
41 import javax.transaction.xa.Xid;
42
43 import org.slf4j.Logger;
44 import org.slf4j.LoggerFactory;
45
46
47
48
49
50
51
52 public class TransactionImpl implements Transaction {
53 private static final Logger log = LoggerFactory.getLogger("Transaction");
54
55 private final XidFactory xidFactory;
56 private final Xid xid;
57 private final TransactionLog txnLog;
58 private final long timeout;
59 private final List syncList = new ArrayList(5);
60 private final List interposedSyncList = new ArrayList(3);
61 private final LinkedList resourceManagers = new LinkedList();
62 private final IdentityHashMap activeXaResources = new IdentityHashMap(3);
63 private final IdentityHashMap suspendedXaResources = new IdentityHashMap(3);
64 private int status = Status.STATUS_NO_TRANSACTION;
65 private Object logMark;
66
67 private final Map resources = new HashMap();
68
69 TransactionImpl(XidFactory xidFactory, TransactionLog txnLog, long transactionTimeoutMilliseconds) throws SystemException {
70 this(xidFactory.createXid(), xidFactory, txnLog, transactionTimeoutMilliseconds);
71 }
72
73 TransactionImpl(Xid xid, XidFactory xidFactory, TransactionLog txnLog, long transactionTimeoutMilliseconds) throws SystemException {
74 this.xidFactory = xidFactory;
75 this.txnLog = txnLog;
76 this.xid = xid;
77 this.timeout = transactionTimeoutMilliseconds + TransactionTimer.getCurrentTime();
78 try {
79 txnLog.begin(xid);
80 } catch (LogException e) {
81 status = Status.STATUS_MARKED_ROLLBACK;
82 SystemException ex = new SystemException("Error logging begin; transaction marked for roll back)");
83 ex.initCause(e);
84 throw ex;
85 }
86 status = Status.STATUS_ACTIVE;
87 }
88
89
90 public TransactionImpl(Xid xid, TransactionLog txLog) {
91 this.xidFactory = null;
92 this.txnLog = txLog;
93 this.xid = xid;
94 status = Status.STATUS_PREPARED;
95
96 this.timeout = Long.MAX_VALUE;
97 }
98
99 public synchronized int getStatus() {
100 return status;
101 }
102
103 public Object getResource(Object key) {
104 return resources.get(key);
105 }
106
107 public boolean getRollbackOnly() {
108 return status == Status.STATUS_MARKED_ROLLBACK;
109 }
110
111 public Object getTransactionKey() {
112 return xid;
113 }
114
115 public int getTransactionStatus() {
116 return status;
117 }
118
119 public void putResource(Object key, Object value) {
120 if (key == null) {
121 throw new NullPointerException("You must supply a non-null key for putResource");
122 }
123 resources.put(key, value);
124 }
125
126 public void registerInterposedSynchronization(Synchronization synchronization) {
127 interposedSyncList.add(synchronization);
128 }
129
130 public synchronized void setRollbackOnly() throws IllegalStateException {
131 switch (status) {
132 case Status.STATUS_ACTIVE:
133 case Status.STATUS_PREPARING:
134 status = Status.STATUS_MARKED_ROLLBACK;
135 break;
136 case Status.STATUS_MARKED_ROLLBACK:
137 case Status.STATUS_ROLLING_BACK:
138
139 break;
140 default:
141 throw new IllegalStateException("Cannot set rollback only, status is " + getStateString(status));
142 }
143 }
144
145 public synchronized void registerSynchronization(Synchronization synch) throws IllegalStateException, RollbackException, SystemException {
146 if (synch == null) {
147 throw new IllegalArgumentException("Synchronization is null");
148 }
149 switch (status) {
150 case Status.STATUS_ACTIVE:
151 case Status.STATUS_PREPARING:
152 break;
153 case Status.STATUS_MARKED_ROLLBACK:
154 throw new RollbackException("Transaction is marked for rollback");
155 default:
156 throw new IllegalStateException("Status is " + getStateString(status));
157 }
158 syncList.add(synch);
159 }
160
161 public synchronized boolean enlistResource(XAResource xaRes) throws IllegalStateException, RollbackException, SystemException {
162 if (xaRes == null) {
163 throw new IllegalArgumentException("XAResource is null");
164 }
165 switch (status) {
166 case Status.STATUS_ACTIVE:
167 break;
168 case Status.STATUS_MARKED_ROLLBACK:
169 break;
170 default:
171 throw new IllegalStateException("Status is " + getStateString(status));
172 }
173
174 if (activeXaResources.containsKey(xaRes)) {
175 throw new IllegalStateException("xaresource: " + xaRes + " is already enlisted!");
176 }
177
178 try {
179 TransactionBranch manager = (TransactionBranch) suspendedXaResources.remove(xaRes);
180 if (manager != null) {
181
182 xaRes.start(manager.getBranchId(), XAResource.TMRESUME);
183 activeXaResources.put(xaRes, manager);
184 return true;
185 }
186
187 for (Iterator i = resourceManagers.iterator(); i.hasNext();) {
188 manager = (TransactionBranch) i.next();
189 boolean sameRM;
190
191 if (xaRes == manager.getCommitter()) {
192 throw new IllegalStateException("xaRes " + xaRes + " is a committer but is not active or suspended");
193 }
194
195 try {
196 sameRM = xaRes.isSameRM(manager.getCommitter());
197 } catch (XAException e) {
198 log.warn("Unexpected error checking for same RM", e);
199 continue;
200 }
201 if (sameRM) {
202 xaRes.start(manager.getBranchId(), XAResource.TMJOIN);
203 activeXaResources.put(xaRes, manager);
204 return true;
205 }
206 }
207
208 Xid branchId = xidFactory.createBranch(xid, resourceManagers.size() + 1);
209 xaRes.start(branchId, XAResource.TMNOFLAGS);
210 activeXaResources.put(xaRes, addBranchXid(xaRes, branchId));
211 return true;
212 } catch (XAException e) {
213 log.warn("Unable to enlist XAResource " + xaRes + ", errorCode: " + e.errorCode, e);
214
215 setRollbackOnly();
216 return false;
217 }
218 }
219
220 public synchronized boolean delistResource(XAResource xaRes, int flag) throws IllegalStateException, SystemException {
221 if (!(flag == XAResource.TMFAIL || flag == XAResource.TMSUCCESS || flag == XAResource.TMSUSPEND)) {
222 throw new IllegalStateException("invalid flag for delistResource: " + flag);
223 }
224 if (xaRes == null) {
225 throw new IllegalArgumentException("XAResource is null");
226 }
227 switch (status) {
228 case Status.STATUS_ACTIVE:
229 case Status.STATUS_MARKED_ROLLBACK:
230 break;
231 default:
232 throw new IllegalStateException("Status is " + getStateString(status));
233 }
234 TransactionBranch manager = (TransactionBranch) activeXaResources.remove(xaRes);
235 if (manager == null) {
236 if (flag == XAResource.TMSUSPEND) {
237 throw new IllegalStateException("trying to suspend an inactive xaresource: " + xaRes);
238 }
239
240 manager = (TransactionBranch) suspendedXaResources.remove(xaRes);
241 if (manager == null) {
242 throw new IllegalStateException("Resource not known to transaction: " + xaRes);
243 }
244 }
245
246 try {
247 xaRes.end(manager.getBranchId(), flag);
248 if (flag == XAResource.TMSUSPEND) {
249 suspendedXaResources.put(xaRes, manager);
250 }
251 return true;
252 } catch (XAException e) {
253 log.warn("Unable to delist XAResource " + xaRes + ", error code: " + e.errorCode, e);
254 return false;
255 }
256 }
257
258
259 public void commit() throws HeuristicMixedException, HeuristicRollbackException, RollbackException, SecurityException, SystemException {
260 beforePrepare();
261
262 try {
263 boolean timedout = false;
264 if (TransactionTimer.getCurrentTime() > timeout) {
265 status = Status.STATUS_MARKED_ROLLBACK;
266 timedout = true;
267 }
268
269 if (status == Status.STATUS_MARKED_ROLLBACK) {
270 rollbackResourcesDuringCommit(resourceManagers, false);
271 if (timedout) {
272 throw new RollbackException("Unable to commit: Transaction timeout");
273 } else {
274 throw new RollbackException("Unable to commit: transaction marked for rollback");
275 }
276 }
277 synchronized (this) {
278 if (status == Status.STATUS_ACTIVE) {
279 if (this.resourceManagers.size() == 0) {
280
281 status = Status.STATUS_COMMITTED;
282 } else if (this.resourceManagers.size() == 1) {
283
284 status = Status.STATUS_COMMITTING;
285 } else {
286
287 status = Status.STATUS_PREPARING;
288 }
289 }
290
291 }
292
293
294 if (resourceManagers.size() == 0) {
295 synchronized (this) {
296 status = Status.STATUS_COMMITTED;
297 }
298 return;
299 }
300
301
302 if (resourceManagers.size() == 1) {
303 TransactionBranch manager = (TransactionBranch) resourceManagers.getFirst();
304 commitResource(manager);
305 return;
306 }
307
308 boolean willCommit = false;
309 try {
310
311 willCommit = internalPrepare();
312 } catch (SystemException e) {
313 rollbackResources(resourceManagers);
314 throw e;
315 }
316
317
318 if (willCommit) {
319 commitResources(resourceManagers);
320 } else {
321
322
323 rollbackResourcesDuringCommit(resourceManagers, true);
324 }
325 } finally {
326 afterCompletion();
327 synchronized (this) {
328 status = Status.STATUS_NO_TRANSACTION;
329 }
330 }
331 }
332
333
334 int prepare() throws SystemException, RollbackException {
335 beforePrepare();
336 int result = XAResource.XA_RDONLY;
337 try {
338 LinkedList rms;
339 synchronized (this) {
340 if (status == Status.STATUS_ACTIVE) {
341 if (resourceManagers.size() == 0) {
342
343 status = Status.STATUS_COMMITTED;
344 return result;
345 } else {
346
347 status = Status.STATUS_PREPARING;
348 }
349 }
350
351 rms = resourceManagers;
352 }
353
354 boolean willCommit = internalPrepare();
355
356
357 if (willCommit) {
358 if (!rms.isEmpty()) {
359 result = XAResource.XA_OK;
360 }
361 } else {
362 rollbackResources(rms);
363 throw new RollbackException("Unable to commit");
364 }
365 } finally {
366 if (result == XAResource.XA_RDONLY) {
367 afterCompletion();
368 synchronized (this) {
369 status = Status.STATUS_NO_TRANSACTION;
370 }
371 }
372 }
373 return result;
374 }
375
376
377 void preparedCommit() throws HeuristicRollbackException, HeuristicMixedException, SystemException {
378 try {
379 commitResources(resourceManagers);
380 } finally {
381 afterCompletion();
382 synchronized (this) {
383 status = Status.STATUS_NO_TRANSACTION;
384 }
385 }
386 }
387
388
389 private void beforePrepare() {
390 synchronized (this) {
391 switch (status) {
392 case Status.STATUS_ACTIVE:
393 case Status.STATUS_MARKED_ROLLBACK:
394 break;
395 default:
396 throw new IllegalStateException("Status is " + getStateString(status));
397 }
398 }
399
400 beforeCompletion();
401 endResources();
402 }
403
404
405
406 private boolean internalPrepare() throws SystemException {
407 for (Iterator rms = resourceManagers.iterator(); rms.hasNext();) {
408 synchronized (this) {
409 if (status != Status.STATUS_PREPARING) {
410
411 break;
412 }
413 }
414 TransactionBranch manager = (TransactionBranch) rms.next();
415 try {
416 int vote = manager.getCommitter().prepare(manager.getBranchId());
417 if (vote == XAResource.XA_RDONLY) {
418
419 rms.remove();
420 }
421 } catch (XAException e) {
422 if (e.errorCode == XAException.XAER_RMERR
423 || e.errorCode == XAException.XAER_PROTO
424 || e.errorCode == XAException.XAER_INVAL) {
425 throw (SystemException) new SystemException("Error during prepare; transaction was rolled back").initCause(e);
426 }
427 synchronized (this) {
428 status = Status.STATUS_MARKED_ROLLBACK;
429
430
431
432
433
434
435
436
437 break;
438 }
439 }
440 }
441
442
443 boolean willCommit;
444 synchronized (this) {
445 willCommit = (status != Status.STATUS_MARKED_ROLLBACK);
446 if (willCommit) {
447 status = Status.STATUS_PREPARED;
448 }
449 }
450
451 if (willCommit && !resourceManagers.isEmpty()) {
452 try {
453 logMark = txnLog.prepare(xid, resourceManagers);
454 } catch (LogException e) {
455 try {
456 rollbackResources(resourceManagers);
457 } catch (Exception se) {
458 log.error("Unable to rollback after failure to log prepare", se.getCause());
459 }
460 throw (SystemException) new SystemException("Error logging prepare; transaction was rolled back)").initCause(e);
461 }
462 }
463 return willCommit;
464 }
465
466 public void rollback() throws IllegalStateException, SystemException {
467 List rms;
468 synchronized (this) {
469 switch (status) {
470 case Status.STATUS_ACTIVE:
471 status = Status.STATUS_MARKED_ROLLBACK;
472 break;
473 case Status.STATUS_MARKED_ROLLBACK:
474 break;
475 default:
476 throw new IllegalStateException("Status is " + getStateString(status));
477 }
478 rms = resourceManagers;
479 }
480
481 endResources();
482 try {
483 rollbackResources(rms);
484
485 if (logMark != null) {
486 try {
487 txnLog.rollback(xid, logMark);
488 } catch (LogException e) {
489 try {
490 rollbackResources(rms);
491 } catch (Exception se) {
492 log.error("Unable to rollback after failure to log decision", se.getCause());
493 }
494 throw (SystemException) new SystemException("Error logging rollback").initCause(e);
495 }
496 }
497 } finally {
498 afterCompletion();
499 synchronized (this) {
500 status = Status.STATUS_NO_TRANSACTION;
501 }
502 }
503 }
504
505 private void beforeCompletion() {
506 beforeCompletion(syncList);
507 beforeCompletion(interposedSyncList);
508 }
509
510 private void beforeCompletion(List syncs) {
511 int i = 0;
512 while (true) {
513 Synchronization synch;
514 synchronized (this) {
515 if (i == syncs.size()) {
516 return;
517 } else {
518 synch = (Synchronization) syncs.get(i++);
519 }
520 }
521 try {
522 synch.beforeCompletion();
523 } catch (Exception e) {
524 log.warn("Unexpected exception from beforeCompletion; transaction will roll back", e);
525 synchronized (this) {
526 status = Status.STATUS_MARKED_ROLLBACK;
527 }
528 }
529 }
530 }
531
532 private void afterCompletion() {
533
534 afterCompletion(interposedSyncList);
535 afterCompletion(syncList);
536 }
537
538 private void afterCompletion(List syncs) {
539 for (Iterator i = syncs.iterator(); i.hasNext();) {
540 Synchronization synch = (Synchronization) i.next();
541 try {
542 synch.afterCompletion(status);
543 } catch (Exception e) {
544 log.warn("Unexpected exception from afterCompletion; continuing", e);
545 }
546 }
547 }
548
549 private void endResources() {
550 endResources(activeXaResources);
551 endResources(suspendedXaResources);
552 }
553
554 private void endResources(IdentityHashMap resourceMap) {
555 while (true) {
556 XAResource xaRes;
557 TransactionBranch manager;
558 int flags;
559 synchronized (this) {
560 Set entrySet = resourceMap.entrySet();
561 if (entrySet.isEmpty()) {
562 return;
563 }
564 Map.Entry entry = (Map.Entry) entrySet.iterator().next();
565 xaRes = (XAResource) entry.getKey();
566 manager = (TransactionBranch) entry.getValue();
567 flags = (status == Status.STATUS_MARKED_ROLLBACK) ? XAResource.TMFAIL : XAResource.TMSUCCESS;
568 resourceMap.remove(xaRes);
569 }
570 try {
571 xaRes.end(manager.getBranchId(), flags);
572 } catch (XAException e) {
573 log.warn("Error ending association for XAResource " + xaRes + "; transaction will roll back. XA error code: " + e.errorCode, e);
574 synchronized (this) {
575 status = Status.STATUS_MARKED_ROLLBACK;
576 }
577 }
578 }
579 }
580
581 private void rollbackResources(List rms) throws SystemException {
582 SystemException cause = null;
583 synchronized (this) {
584 status = Status.STATUS_ROLLING_BACK;
585 }
586 try {
587 for (Iterator i = rms.iterator(); i.hasNext();) {
588 TransactionBranch manager = (TransactionBranch) i.next();
589 try {
590 manager.getCommitter().rollback(manager.getBranchId());
591 } catch (XAException e) {
592 log.error("Unexpected exception rolling back " + manager.getCommitter() + "; continuing with rollback", e);
593 if (e.errorCode == XAException.XA_HEURRB) {
594
595 log.info("Transaction has been heuristically rolled back " + manager.getCommitter() + "; continuing with rollback", e);
596 manager.getCommitter().forget(manager.getBranchId());
597 } else if (e.errorCode == XAException.XA_RBROLLBACK
598 || e.errorCode == XAException.XAER_RMERR
599 || e.errorCode == XAException.XAER_NOTA
600 || e.errorCode == XAException.XAER_RMFAIL) {
601
602
603
604 } else if (cause == null) {
605 cause = new SystemException(e.errorCode);
606 }
607 }
608 }
609 } catch (XAException e) {
610 throw (SystemException) new SystemException("Error during rolling back").initCause(e);
611 }
612
613 synchronized (this) {
614 status = Status.STATUS_ROLLEDBACK;
615 }
616 if (cause != null) {
617 throw cause;
618 }
619 }
620
621 private void rollbackResourcesDuringCommit(List rms, boolean everRb) throws HeuristicMixedException, RollbackException, SystemException {
622 XAException cause = null;
623 boolean everRolledback = everRb;
624 synchronized (this) {
625 status = Status.STATUS_ROLLING_BACK;
626 }
627 try {
628 for (Iterator i = rms.iterator(); i.hasNext();) {
629 TransactionBranch manager = (TransactionBranch) i.next();
630 try {
631 manager.getCommitter().rollback(manager.getBranchId());
632 everRolledback = true;
633 } catch (XAException e) {
634 if (e.errorCode == XAException.XA_HEURRB) {
635
636 log.error("Transaction has been heuristically rolled back " + manager.getCommitter() + "; continuing with rollback", e);
637 everRolledback = true;
638 manager.getCommitter().forget(manager.getBranchId());
639 } else if (e.errorCode == XAException.XA_HEURMIX) {
640 log.error("Transaction has been heuristically committed and rolled back " + manager.getCommitter() + "; continuing with rollback", e);
641 cause = e;
642 everRolledback = true;
643 manager.getCommitter().forget(manager.getBranchId());
644 } else if (e.errorCode == XAException.XA_HEURCOM) {
645 log.error("Transaction has been heuristically committed " + manager.getCommitter() + "; continuing with rollback", e);
646 cause = e;
647 manager.getCommitter().forget(manager.getBranchId());
648 } else if (e.errorCode == XAException.XA_RBROLLBACK
649 || e.errorCode == XAException.XAER_RMERR
650 || e.errorCode == XAException.XAER_NOTA
651 || e.errorCode == XAException.XAER_RMFAIL) {
652
653
654
655
656
657 } else if (cause == null) {
658 cause = e;
659 }
660 }
661 }
662 } catch (XAException e) {
663 throw (SystemException) new SystemException("System error during commit/rolling back").initCause(e);
664 }
665
666 synchronized (this) {
667 status = Status.STATUS_ROLLEDBACK;
668 }
669
670 if (cause == null) {
671 throw (RollbackException) new RollbackException("Unable to commit: transaction marked for rollback").initCause(cause);
672 } else {
673 if (cause.errorCode == XAException.XA_HEURCOM && everRolledback) {
674 throw (HeuristicMixedException) new HeuristicMixedException("HeuristicMixed error during commit/rolling back").initCause(cause);
675 } else if (cause.errorCode == XAException.XA_HEURMIX) {
676 throw (HeuristicMixedException) new HeuristicMixedException("HeuristicMixed error during commit/rolling back").initCause(cause);
677 } else {
678 throw (SystemException) new SystemException("System Error during commit/rolling back").initCause(cause);
679 }
680 }
681 }
682
683 private void commitResource(TransactionBranch manager) throws RollbackException, HeuristicRollbackException, HeuristicMixedException, SystemException{
684 XAException cause = null;
685 try {
686 try {
687
688 manager.getCommitter().commit(manager.getBranchId(), true);
689 synchronized (this) {
690 status = Status.STATUS_COMMITTED;
691 }
692 return;
693 } catch (XAException e) {
694 synchronized (this) {
695 status = Status.STATUS_ROLLEDBACK;
696 }
697
698 if (e.errorCode == XAException.XA_HEURRB) {
699 cause = e;
700 manager.getCommitter().forget(manager.getBranchId());
701
702 } else if (e.errorCode == XAException.XA_HEURMIX) {
703 cause = e;
704 manager.getCommitter().forget(manager.getBranchId());
705 throw (HeuristicMixedException) new HeuristicMixedException("Error during one-phase commit").initCause(e);
706 } else if (e.errorCode == XAException.XA_HEURCOM) {
707
708 log.info("Transaction has been heuristically committed");
709 manager.getCommitter().forget(manager.getBranchId());
710 } else if (e.errorCode == XAException.XA_RBROLLBACK
711 || e.errorCode == XAException.XAER_RMERR
712 || e.errorCode == XAException.XAER_NOTA) {
713
714
715
716
717 log.info("Transaction has been rolled back");
718 cause = e;
719
720 } else {
721 cause = e;
722
723 }
724 }
725 } catch (XAException e) {
726 if (e.errorCode == XAException.XAER_NOTA) {
727
728
729 } else {
730 throw (SystemException) new SystemException("Error during one phase commit").initCause(e);
731 }
732 }
733
734 if (cause != null) {
735 if (cause.errorCode == XAException.XA_HEURRB) {
736 throw (HeuristicRollbackException) new HeuristicRollbackException("Error during two phase commit").initCause(cause);
737 } else if (cause.errorCode == XAException.XA_HEURMIX) {
738 throw (HeuristicMixedException) new HeuristicMixedException("Error during two phase commit").initCause(cause);
739 } else if (cause.errorCode == XAException.XA_RBROLLBACK
740 || cause.errorCode == XAException.XAER_RMERR
741 || cause.errorCode == XAException.XAER_NOTA) {
742 throw (RollbackException) new RollbackException("Error during two phase commit").initCause(cause);
743 } else {
744 throw (SystemException) new SystemException("Error during two phase commit").initCause(cause);
745 }
746 }
747 }
748
749 private void commitResources(List rms) throws HeuristicRollbackException, HeuristicMixedException, SystemException {
750 XAException cause = null;
751 boolean evercommit = false;
752 synchronized (this) {
753 status = Status.STATUS_COMMITTING;
754 }
755 try {
756 for (Iterator i = rms.iterator(); i.hasNext();) {
757 TransactionBranch manager = (TransactionBranch) i.next();
758 try {
759 manager.getCommitter().commit(manager.getBranchId(), false);
760 evercommit = true;
761 } catch (XAException e) {
762 log.error("Unexpected exception committing " + manager.getCommitter() + "; continuing to commit other RMs", e);
763
764 if (e.errorCode == XAException.XA_HEURRB) {
765 log.info("Transaction has been heuristically rolled back");
766 cause = e;
767 manager.getCommitter().forget(manager.getBranchId());
768 } else if (e.errorCode == XAException.XA_HEURMIX) {
769 log.info("Transaction has been heuristically committed and rolled back");
770 cause = e;
771 evercommit = true;
772 manager.getCommitter().forget(manager.getBranchId());
773 } else if (e.errorCode == XAException.XA_HEURCOM) {
774
775 log.info("Transaction has been heuristically committed");
776 evercommit = true;
777 manager.getCommitter().forget(manager.getBranchId());
778 } else {
779 cause = e;
780 }
781 }
782 }
783 } catch (XAException e) {
784 if (e.errorCode == XAException.XAER_NOTA) {
785
786
787 } else {
788 throw (SystemException) new SystemException("Error during two phase commit").initCause(e);
789 }
790 }
791
792 if (!rms.isEmpty()) {
793 try {
794 txnLog.commit(xid, logMark);
795 } catch (LogException e) {
796 log.error("Unexpected exception logging commit completion for xid " + xid, e);
797 throw (SystemException) new SystemException("Unexpected error logging commit completion for xid " + xid).initCause(e);
798 }
799 }
800 synchronized (this) {
801 status = Status.STATUS_COMMITTED;
802 }
803 if (cause != null) {
804 if (cause.errorCode == XAException.XA_HEURRB && !evercommit) {
805 throw (HeuristicRollbackException) new HeuristicRollbackException("Error during two phase commit").initCause(cause);
806 } else if (cause.errorCode == XAException.XA_HEURRB && evercommit) {
807 throw (HeuristicMixedException) new HeuristicMixedException("Error during two phase commit").initCause(cause);
808 } else if (cause.errorCode == XAException.XA_HEURMIX) {
809 throw (HeuristicMixedException) new HeuristicMixedException("Error during two phase commit").initCause(cause);
810 } else {
811 throw (SystemException) new SystemException("Error during two phase commit").initCause(cause);
812 }
813 }
814 }
815
816 private static String getStateString(int status) {
817 switch (status) {
818 case Status.STATUS_ACTIVE:
819 return "STATUS_ACTIVE";
820 case Status.STATUS_PREPARING:
821 return "STATUS_PREPARING";
822 case Status.STATUS_PREPARED:
823 return "STATUS_PREPARED";
824 case Status.STATUS_MARKED_ROLLBACK:
825 return "STATUS_MARKED_ROLLBACK";
826 case Status.STATUS_ROLLING_BACK:
827 return "STATUS_ROLLING_BACK";
828 case Status.STATUS_COMMITTING:
829 return "STATUS_COMMITTING";
830 case Status.STATUS_COMMITTED:
831 return "STATUS_COMMITTED";
832 case Status.STATUS_ROLLEDBACK:
833 return "STATUS_ROLLEDBACK";
834 case Status.STATUS_NO_TRANSACTION:
835 return "STATUS_NO_TRANSACTION";
836 case Status.STATUS_UNKNOWN:
837 return "STATUS_UNKNOWN";
838 default:
839 throw new AssertionError();
840 }
841 }
842
843 public boolean equals(Object obj) {
844 if (obj instanceof TransactionImpl) {
845 TransactionImpl other = (TransactionImpl) obj;
846 return xid.equals(other.xid);
847 } else {
848 return false;
849 }
850 }
851
852
853
854 public TransactionBranch addBranchXid(XAResource xaRes, Xid branchId) {
855 TransactionBranch manager = new TransactionBranch(xaRes, branchId);
856 resourceManagers.add(manager);
857 return manager;
858 }
859
860 private static class TransactionBranch implements TransactionBranchInfo {
861 private final XAResource committer;
862 private final Xid branchId;
863
864 public TransactionBranch(XAResource xaRes, Xid branchId) {
865 committer = xaRes;
866 this.branchId = branchId;
867 }
868
869 public XAResource getCommitter() {
870 return committer;
871 }
872
873 public Xid getBranchId() {
874 return branchId;
875 }
876
877 public String getResourceName() {
878 if (committer instanceof NamedXAResource) {
879 return ((NamedXAResource) committer).getName();
880 } else {
881
882
883 log.error("Please correct the integration and supply a NamedXAResource", new IllegalStateException("Cannot log transactions as " + committer + " is not a NamedXAResource."));
884 return committer.toString();
885 }
886 }
887
888 public Xid getBranchXid() {
889 return branchId;
890 }
891 }
892
893
894 }