| 1 22 package org.jboss.tm; 23 24 import java.util.ArrayList ; 25 import java.util.Collection ; 26 import java.util.Collections ; 27 import java.util.HashMap ; 28 import java.util.Iterator ; 29 import java.util.List ; 30 import java.util.Map ; 31 32 import javax.resource.spi.work.Work ; 33 import javax.resource.spi.work.WorkCompletedException ; 34 import javax.resource.spi.work.WorkException ; 35 import javax.transaction.HeuristicMixedException ; 36 import javax.transaction.HeuristicRollbackException ; 37 import javax.transaction.InvalidTransactionException ; 38 import javax.transaction.NotSupportedException ; 39 import javax.transaction.RollbackException ; 40 import javax.transaction.Status ; 41 import javax.transaction.SystemException ; 42 import javax.transaction.Transaction ; 43 import javax.transaction.TransactionManager ; 44 import javax.transaction.xa.XAException ; 45 import javax.transaction.xa.Xid ; 46 47 import org.jboss.logging.Logger; 48 import org.jboss.tm.integrity.TransactionIntegrity; 49 import org.jboss.tm.recovery.LogRecord; 50 import org.jboss.tm.recovery.RecoveryLogger; 51 import org.jboss.tm.recovery.TxCompletionHandler; 52 import org.jboss.tm.remoting.interfaces.Coordinator; 53 import org.jboss.tm.remoting.interfaces.RecoveryCoordinator; 54 import org.jboss.tm.remoting.interfaces.Resource; 55 import org.jboss.tm.remoting.interfaces.TxPropagationContext; 56 import org.jboss.util.UnexpectedThrowable; 57 import org.jboss.util.UnreachableStatementException; 58 59 72 public class TxManager 73 implements TransactionManager , 74 TransactionPropagationContextImporter, 75 TransactionPropagationContextFactory, 76 TransactionLocalDelegate, 77 TransactionTimeoutConfiguration, 78 JBossXATerminator, 79 StringRemoteRefConverter 80 { 81 83 85 88 private boolean globalIdsEnabled = false; 89 90 93 private boolean dtmEnabled = false; 94 95 98 private boolean interruptThreads = false; 99 100 103 private Logger log = Logger.getLogger(this.getClass()); 104 105 108 private boolean trace = log.isTraceEnabled(); 109 110 114 private long timeOut = 5 * 60 * 1000; 115 116 126 private volatile int commitCount; 127 130 private volatile int rollbackCount; 131 132 133 private RecoveryLogger recoveryLogger; 134 135 136 private boolean recoveryPending = true; 137 138 139 private TransactionIntegrity integrity; 140 141 142 private int completionRetryLimit = 0; 144 145 private int completionRetryTimeout = 1 * 1000; 147 148 private int xaRetryTimeout = 60 * 1000; 149 150 151 private int preparedTimeout = 60 * 1000; 152 153 154 private boolean rootBranchRemembersHeuristicDecisions = true; 155 156 157 private boolean reportHeuristicHazardAsHeuristicMixed = false; 158 159 161 164 private static TxManager singleton = new TxManager(); 165 166 169 public static TxManager getInstance() 170 { 171 return singleton; 172 } 173 174 176 180 private TxManager() 181 { 182 TransactionImpl.defaultXidFactory(); 184 } 185 186 188 193 public void clear() 194 { 195 Collection txCollection = localIdTx.values(); 196 synchronized (localIdTx) 197 { 198 Iterator i = txCollection.iterator(); 199 while (i.hasNext()) 200 { 201 TransactionImpl tx = (TransactionImpl) i.next(); 202 tx.deactivate(); 203 } 204 } 205 localIdTx.clear(); 206 if (globalIdsEnabled) 207 globalIdTx.clear(); 208 } 209 210 213 public void setGlobalIdsEnabled(boolean newValue) 214 { 215 trace = log.isTraceEnabled(); XidImpl.setTrulyGlobalIdsEnabled(newValue); 217 globalIdsEnabled = newValue; 218 } 219 220 223 public boolean getGlobalIdsEnabled() 224 { 225 return globalIdsEnabled; 226 } 227 228 233 public void setInterruptThreads(boolean interruptThreads) 234 { 235 this.interruptThreads = interruptThreads; 236 } 237 238 243 public boolean isInterruptThreads() 244 { 245 return interruptThreads; 246 } 247 248 253 public void setRecoveryLogger(RecoveryLogger recoveryLogger) 254 { 255 this.recoveryLogger = recoveryLogger; 256 } 257 258 263 public RecoveryLogger getRecoveryLogger() 264 { 265 return recoveryLogger; 266 } 267 268 272 public void clearRecoveryPending() 273 { 274 this.recoveryPending = false; 275 } 276 277 282 public boolean isRecoveryPending() 283 { 284 return recoveryPending; 285 } 286 287 292 public void setTransactionIntegrity(TransactionIntegrity integrity) 293 { 294 this.integrity = integrity; 295 } 296 297 302 public TransactionIntegrity getTransactionIntegrity() 303 { 304 return integrity; 305 } 306 307 318 public void setCompletionRetryLimit(int maxCompletionRetries) 319 { 320 this.completionRetryLimit = maxCompletionRetries; 321 } 322 323 334 public int getCompletionRetryLimit() 335 { 336 return completionRetryLimit; 337 } 338 339 355 public void setCompletionRetryTimeout(int seconds) 356 { 357 this.completionRetryTimeout = 1000 * seconds; 358 } 359 360 376 public int getCompletionRetryTimeout() 377 { 378 return completionRetryTimeout / 1000; 379 } 380 381 388 public int getCompletionRetryTimeoutMillis() 389 { 390 return xaRetryTimeout; 391 } 392 393 399 public void setXARetryTimeout(int seconds) 400 { 401 this.xaRetryTimeout = 1000 * seconds; 402 } 403 404 409 public int getXARetryTimeout() 410 { 411 return xaRetryTimeout / 1000; 412 } 413 414 420 public int getXARetryTimeoutMillis() 421 { 422 return xaRetryTimeout; 423 } 424 425 434 public void setPreparedTimeout(int seconds) 435 { 436 this.preparedTimeout = 1000 * seconds; 437 } 438 439 448 public int getPreparedTimeout() 449 { 450 return preparedTimeout / 1000; 451 } 452 453 459 public int getPreparedTimeoutMillis() 460 { 461 return preparedTimeout; 462 } 463 464 475 public void setRootBranchRemembersHeuristicDecisions(boolean newValue) 476 { 477 rootBranchRemembersHeuristicDecisions = newValue; 478 } 479 480 491 public boolean isRootBranchRemembersHeuristicDecisions() 492 { 493 return rootBranchRemembersHeuristicDecisions; 494 } 495 496 513 public void setReportHeuristicHazardAsHeuristicMixed(boolean newValue) 514 { 515 reportHeuristicHazardAsHeuristicMixed = newValue; 516 } 517 518 534 public boolean isReportHeuristicHazardAsHeuristicMixed() 535 { 536 return reportHeuristicHazardAsHeuristicMixed; 537 } 538 539 543 public void begin() 544 throws NotSupportedException , 545 SystemException  546 { 547 trace = log.isTraceEnabled(); 549 ThreadInfo ti = getThreadInfo(); 550 TransactionImpl current = ti.tx; 551 552 if (current != null) 553 { 554 if (current.isDone()) 555 disassociateThread(ti); 556 else 557 throw new NotSupportedException  558 ("Transaction already active, cannot nest transactions."); 559 } 560 561 long timeout = (ti.timeout == 0) ? timeOut : ti.timeout; 562 TransactionImpl tx = new TransactionImpl(timeout); 563 associateThread(ti, tx); 564 localIdTx.put(tx.getLocalId(), tx); 565 if (globalIdsEnabled) 566 globalIdTx.put(tx.getGlobalId(), tx); 567 568 if (trace) 569 log.trace("began tx: " + tx); 570 } 571 572 575 public void commit() 576 throws RollbackException , 577 HeuristicMixedException , 578 HeuristicRollbackException , 579 SecurityException , 580 IllegalStateException , 581 SystemException  582 { 583 ThreadInfo ti = getThreadInfo(); 584 TransactionImpl current = ti.tx; 585 586 if (current != null) 587 { 588 current.commit(); 589 disassociateThread(ti); 590 if (trace) 591 log.trace("commited tx: " + current); 592 } 593 else 594 throw new IllegalStateException ("No transaction."); 595 } 596 597 602 public int getStatus() 603 throws SystemException  604 { 605 ThreadInfo ti = getThreadInfo(); 606 TransactionImpl current = ti.tx; 607 608 if (current != null) 609 { 610 if (current.isDone()) 611 disassociateThread(ti); 612 else 613 return current.getStatus(); 614 } 615 return Status.STATUS_NO_TRANSACTION; 616 } 617 618 622 public Transaction getTransaction() 623 throws SystemException  624 { 625 ThreadInfo ti = getThreadInfo(); 626 TransactionImpl current = ti.tx; 627 628 if (current != null && current.isDone()) 629 { 630 current = null; 631 disassociateThread(ti); 632 } 633 634 return current; 635 } 636 637 644 public void resume(Transaction transaction) 645 throws InvalidTransactionException , 646 IllegalStateException , 647 SystemException  648 { 649 if (transaction != null && !(transaction instanceof TransactionImpl)) 650 throw new RuntimeException ("Not a TransactionImpl, but a " + 651 transaction.getClass().getName()); 652 653 ThreadInfo ti = getThreadInfo(); 654 TransactionImpl current = ti.tx; 655 656 if (current != null) 657 { 658 if (current.isDone()) 659 current = ti.tx = null; 660 else 661 throw new IllegalStateException ("Already associated with a tx"); 662 } 663 664 if (current != transaction) 665 { 666 associateThread(ti, (TransactionImpl) transaction); 667 } 668 669 if (trace) 670 log.trace("resumed tx: " + ti.tx); 671 } 672 673 681 public Transaction suspend() 682 throws SystemException  683 { 684 ThreadInfo ti = getThreadInfo(); 685 TransactionImpl current = ti.tx; 686 687 if (current != null) 688 { 689 current.disassociateCurrentThread(); 690 ti.tx = null; 691 692 if (trace) 693 log.trace("suspended tx: " + current); 694 695 if (current.isDone()) 696 current = null; 697 } 698 699 return current; 700 } 701 702 705 public void rollback() 706 throws IllegalStateException , 707 SecurityException , 708 SystemException  709 { 710 ThreadInfo ti = getThreadInfo(); 711 TransactionImpl current = ti.tx; 712 713 if (current != null) 714 { 715 if (!current.isDone()) 716 { 717 current.rollback(); 718 719 if (trace) 720 log.trace("rolled back tx: " + current); 721 return; 722 } 723 disassociateThread(ti); 724 } 725 throw new IllegalStateException ("No transaction."); 726 } 727 728 732 public void setRollbackOnly() 733 throws IllegalStateException , 734 SystemException  735 { 736 ThreadInfo ti = getThreadInfo(); 737 TransactionImpl current = ti.tx; 738 739 if (current != null) 740 { 741 if (!current.isDone()) 742 { 743 current.setRollbackOnly(); 744 745 if (trace) 746 log.trace("tx marked for rollback only: " + current); 747 return; 748 } 749 ti.tx = null; 750 } 751 throw new IllegalStateException ("No transaction."); 752 } 753 754 public int getTransactionTimeout() 755 { 756 return (int) (getThreadInfo().timeout / 1000); 757 } 758 759 763 public void setTransactionTimeout(int seconds) 764 throws SystemException  765 { 766 getThreadInfo().timeout = 1000 * seconds; 767 768 if (trace) 769 log.trace("tx timeout is now: " + seconds + "s"); 770 } 771 772 777 public void setDefaultTransactionTimeout(int seconds) 778 { 779 timeOut = 1000L * seconds; 780 781 if (trace) 782 log.trace("default tx timeout is now: " + seconds + "s"); 783 } 784 785 790 public int getDefaultTransactionTimeout() 791 { 792 return (int) (timeOut / 1000); 793 } 794 795 public long getTimeLeftBeforeTransactionTimeout(boolean errorRollback) throws RollbackException  796 { 797 try 798 { 799 ThreadInfo ti = getThreadInfo(); 800 TransactionImpl current = ti.tx; 801 if (current != null && current.isDone()) 802 { 803 disassociateThread(ti); 804 return -1; 805 } 806 return current.getTimeLeftBeforeTimeout(errorRollback); 807 } 808 catch (RollbackException e) 809 { 810 throw e; 811 } 812 catch (Exception ignored) 813 { 814 return -1; 815 } 816 } 817 818 822 public Transaction disassociateThread() 823 { 824 return disassociateThread(getThreadInfo()); 825 } 826 827 private Transaction disassociateThread(ThreadInfo ti) 828 { 829 TransactionImpl current = ti.tx; 830 ti.tx = null; 831 current.disassociateCurrentThread(); 832 return current; 833 } 834 835 public void associateThread(Transaction transaction) 836 { 837 if (transaction != null && !(transaction instanceof TransactionImpl)) 838 throw new RuntimeException ("Not a TransactionImpl, but a " + 839 transaction.getClass().getName()); 840 841 TransactionImpl transactionImpl = (TransactionImpl) transaction; 843 ThreadInfo ti = getThreadInfo(); 844 ti.tx = transactionImpl; 845 transactionImpl.associateCurrentThread(); 846 } 847 848 private void associateThread(ThreadInfo ti, TransactionImpl transaction) 849 { 850 ti.tx = transaction; 852 transaction.associateCurrentThread(); 853 } 854 855 858 public int getTransactionCount() 859 { 860 return localIdTx.size(); 861 } 862 863 866 public long getCommitCount() 867 { 868 return commitCount; 869 } 870 871 874 public long getRollbackCount() 875 { 876 return rollbackCount; 877 } 878 879 884 public String listInDoubtTransactions() 885 { 886 throw new org.jboss.util.NotImplementedException(); 888 } 889 890 896 public void heuristicallyCommit(long localTransactionId) 897 { 898 throw new org.jboss.util.NotImplementedException(); 900 } 901 902 905 public void heuristicallyCommitAll() 906 { 907 throw new org.jboss.util.NotImplementedException(); 909 } 910 911 917 public void heuristicallyRollback(long localTransactionId) 918 { 919 throw new org.jboss.util.NotImplementedException(); 921 } 922 923 926 public void heuristicallyRollbackAll() 927 { 928 throw new org.jboss.util.NotImplementedException(); 930 } 931 932 944 public String listHeuristicallyCompletedTransactions() 945 { 946 throw new org.jboss.util.NotImplementedException(); 948 } 949 950 958 public void forget(long localTransactionId) 959 { 960 throw new org.jboss.util.NotImplementedException(); 962 } 963 964 968 public void forgetAll() 969 { 970 throw new org.jboss.util.NotImplementedException(); 972 } 973 974 976 991 public Transaction importTransactionPropagationContext(Object tpc) 992 { 993 if (tpc instanceof LocalId) 994 { 995 LocalId id = (LocalId) tpc; 996 return (Transaction ) localIdTx.get(id); 997 } 998 else if (tpc instanceof GlobalId && globalIdsEnabled) 999 { 1000 GlobalId id = (GlobalId) tpc; 1001 Transaction tx = (Transaction ) globalIdTx.get(id); 1002 if (trace) 1003 { 1004 if (tx != null) 1005 log.trace("Successfully imported transaction context " + tpc); 1006 else 1007 log.trace("Could not import transaction context " + tpc); 1008 } 1009 &nbs
|