| 1 22 package org.jboss.tm; 23 24 import java.lang.reflect.Proxy ; 25 import java.rmi.NoSuchObjectException ; 26 import java.rmi.RemoteException ; 27 import java.util.ArrayList ; 28 import java.util.Collections ; 29 import java.util.HashMap ; 30 import java.util.HashSet ; 31 import java.util.Iterator ; 32 import java.util.List ; 33 import java.util.Map ; 34 import java.util.Set ; 35 36 import javax.resource.spi.work.Work ; 37 import javax.resource.spi.work.WorkCompletedException ; 38 import javax.resource.spi.work.WorkException ; 39 import javax.transaction.HeuristicCommitException ; 40 import javax.transaction.HeuristicMixedException ; 41 import javax.transaction.HeuristicRollbackException ; 42 import javax.transaction.RollbackException ; 43 import javax.transaction.Status ; 44 import javax.transaction.Synchronization ; 45 import javax.transaction.SystemException ; 46 import javax.transaction.Transaction ; 47 import javax.transaction.TransactionRolledbackException ; 48 import javax.transaction.xa.XAException ; 49 import javax.transaction.xa.XAResource ; 50 import javax.transaction.xa.Xid ; 51 52 import org.jboss.logging.Logger; 53 import org.jboss.tm.integrity.TransactionIntegrity; 54 import org.jboss.tm.recovery.HeuristicStatus; 55 import org.jboss.tm.recovery.LogRecord; 56 import org.jboss.tm.recovery.RecoveryLogger; 57 import org.jboss.tm.recovery.RecoveryTestingException; 58 import org.jboss.tm.recovery.TxCompletionHandler; 59 import org.jboss.tm.recovery.XAResourceAccess; 60 import org.jboss.tm.recovery.XAWork; 61 import org.jboss.tm.remoting.interfaces.Coordinator; 62 import org.jboss.tm.remoting.interfaces.HeuristicHazardException; 63 import org.jboss.tm.remoting.interfaces.RecoveryCoordinator; 64 import org.jboss.tm.remoting.interfaces.Resource; 65 import org.jboss.tm.remoting.interfaces.TransactionAlreadyPreparedException; 66 import org.jboss.tm.remoting.interfaces.TransactionInactiveException; 67 import org.jboss.tm.remoting.interfaces.TransactionNotPreparedException; 68 import org.jboss.tm.remoting.interfaces.TxPropagationContext; 69 import org.jboss.tm.remoting.interfaces.Vote; 70 import org.jboss.util.timeout.Timeout; 71 import org.jboss.util.timeout.TimeoutFactory; 72 import org.jboss.util.timeout.TimeoutTarget; 73 74 90 public class TransactionImpl 91 implements Transaction , TimeoutTarget 92 { 93 95 99 private static final int HEUR_NONE = 0; 100 101 105 private static final int HEUR_UNKNOWN = XAException.XA_RETRY; 106 107 private final static int RS_NEW = 0; private final static int RS_ENLISTED = 1; private final static int RS_SUSPENDED = 2; private final static int RS_ENDED = 3; private final static int RS_VOTE_READONLY = 4; private final static int RS_VOTE_OK = 5; private final static int RS_FORGOT = 6; private final static int RS_COMMITTED = 7; private final static int RS_ROLLEDBACK = 8; private final static int RS_HEUR_OUTCOME = 8; private final static int RS_ERROR = 9; 120 122 125 private boolean trace = log.isTraceEnabled(); 126 127 130 private XidImpl xid; 131 132 private HashSet threads = new HashSet (1); 133 134 private Map transactionLocalMap = Collections.synchronizedMap(new HashMap ()); 135 136 private Throwable cause; 137 138 143 private final boolean foreignTx; 144 145 151 private Coordinator parentCoordinator = null; 152 153 156 private Resource registeredResource = null; 157 158 162 private RecoveryCoordinator recoveryCoordinator = null; 163 164 168 private byte[] inboundBranchQualifier = null; 169 170 173 private Synchronization [] sync = new Synchronization [3]; 174 175 178 private int syncAllocSize = 3; 179 180 183 private int syncCount = 0; 184 185 188 private ArrayList xaResources = new ArrayList (3); 189 190 193 private ArrayList remoteResources = new ArrayList (3); 194 195 198 private EnlistedXAResource lastResource; 199 200 203 private boolean resourcesEnded = false; 204 205 208 private long lastBranchId = 0; 209 210 213 private int status; 214 215 218 private int heuristicCode = HEUR_NONE; 219 220 223 private long start; 224 225 228 private Timeout timeout; 229 230 233 private long timeoutPeriod; 234 235 239 private Thread locked = null; 240 241 244 private int lockDepth = 0; 245 246 249 private Work work; 250 251 254 private boolean done = false; 255 256 259 private TxPropagationContext dtmPropagationContext = null; 260 261 264 private Object otsPropagationContext = null; 265 266 269 private TxCompletionHandler completionHandler = null; 270 271 274 private int xaResourcesToRetry = 0; 275 276 279 private int remoteResourcesToRetry = 0; 280 281 285 private Timeout preparedTimeout = null; 286 287 291 private Timeout xaRetryTimeout = null; 292 293 297 private List xaResourcesWithHeuristicDecisions = null; 298 299 303 private List remoteResourcesWithHeuristicDecisions = null; 304 305 308 private int committedResources = 0; 309 310 313 private int rolledbackResources = 0; 314 315 319 private boolean heuristicHazard = false; 320 321 323 326 private static Logger log = Logger.getLogger(TransactionImpl.class); 327 328 333 static XidFactoryBase xidFactory; 334 335 static XAExceptionFormatter xaExceptionFormatter; 336 337 338 static TimeoutFactory timeoutFactory = TimeoutFactory.getSingleton(); 339 340 344 private static CoordinatorFactory dtmCoordinatorFactory = null; 345 346 350 private static ResourceFactory dtmResourceFactory = null; 351 352 356 private static ResourceFactory otsResourceFactory = null; 357 358 362 private static OTSContextFactory otsContextFactory = null; 363 364 367 private static boolean interpositionEnabled = false; 368 369 373 private static StringRemoteRefConverter dtmStrRemoteRefConverter = null; 374 375 379 private static StringRemoteRefConverter otsStrRemoteRefConverter = null; 380 381 385 public static XidFactoryBase defaultXidFactory() 386 { 387 if (xidFactory == null) 388 { 389 XidFactoryImpl impl = new XidFactoryImpl(); 390 impl.start(); 391 xidFactory = impl; 392 } 393 return xidFactory; 394 } 395 396 399 static void setDTMCoordinatorFactory(CoordinatorFactory dtmCoordinatorFactory) 400 { 401 TransactionImpl.dtmCoordinatorFactory = dtmCoordinatorFactory; 402 } 403 404 407 static void setDTMResourceFactory(ResourceFactory dtmResourceFactory) 408 { 409 TransactionImpl.dtmResourceFactory = dtmResourceFactory; 410 } 411 412 415 static void setOTSResourceFactory(ResourceFactory otsResourceFactory) 416 { 417 TransactionImpl.otsResourceFactory = otsResourceFactory; 418 } 419 420 423 static void setOTSContextFactory(OTSContextFactory otsContextFactory) 424 { 425 TransactionImpl.otsContextFactory = otsContextFactory; 426 } 427 428 431 static void setInterpositionEnabled(boolean interpositionEnabled) 432 { 433 TransactionImpl.interpositionEnabled = interpositionEnabled; 434 } 435 436 439 static boolean getInterpositionEnabled() 440 { 441 return TransactionImpl.interpositionEnabled; 442 } 443 444 447 static void setDTMStrRemoteRefConverter( 448 StringRemoteRefConverter dtmStrRemoteRefConverter) 449 { 450 TransactionImpl.dtmStrRemoteRefConverter = dtmStrRemoteRefConverter; 451 } 452 453 456 static void setOTSStrRemoteRefConverter( 457 StringRemoteRefConverter otsStrRemoteRefConverter) 458 { 459 TransactionImpl.otsStrRemoteRefConverter = otsStrRemoteRefConverter; 460 } 461 462 469 static Resource stringToResource(String strResource) 470 { 471 if (strResource.startsWith("IOR:")) 472 { 473 if (otsStrRemoteRefConverter != null) 474 return otsStrRemoteRefConverter.stringToResource(strResource); 475 else 476 throw new IllegalArgumentException (); 477 } 478 else 479 { 480 if (dtmStrRemoteRefConverter != null) 481 return dtmStrRemoteRefConverter.stringToResource(strResource); 482 else 483 throw new IllegalArgumentException (); 484 } 485 } 486 487 495 static RecoveryCoordinator stringToRecoveryCoordinator( 496 String strRecCoordinator) 497 { 498 if (strRecCoordinator.startsWith("IOR:")) 499 { 500 if (otsStrRemoteRefConverter != null) 501 return otsStrRemoteRefConverter.stringToRecoveryCoordinator( 502 strRecCoordinator); 503 else 504 throw new IllegalArgumentException (); 505 } 506 else 507 { 508 if (dtmStrRemoteRefConverter != null) 509 return dtmStrRemoteRefConverter.stringToRecoveryCoordinator( 510 strRecCoordinator); 511 else 512 throw new IllegalArgumentException (); 513 } 514 } 515 516 522 static String resourceToString(Resource res) 523 { 524 if (Proxy.isProxyClass(res.getClass())) 525 { 526 if (dtmStrRemoteRefConverter != null) 527 return dtmStrRemoteRefConverter.resourceToString(res); 528 else 529 throw new IllegalArgumentException (); 530 } 531 else 532 { 533 if (otsStrRemoteRefConverter != null) 534 return otsStrRemoteRefConverter.resourceToString(res); 535 else 536 throw new IllegalArgumentException (); 537 } 538 } 539 540 547 static String recoveryCoordinatorToString(RecoveryCoordinator recoveryCoord) 548 { 549 if (Proxy.isProxyClass(recoveryCoord.getClass())) 550 { 551 if (dtmStrRemoteRefConverter != null) 552 return dtmStrRemoteRefConverter.recoveryCoordinatorToString( 553 recoveryCoord); 554 else 555 throw new IllegalArgumentException (); 556 } 557 else 558 { 559 if (otsStrRemoteRefConverter != null) 560 return otsStrRemoteRefConverter.recoveryCoordinatorToString( 561 recoveryCoord); 562 else 563 throw new IllegalArgumentException (); 564 } 565 } 566 567 569 572 TransactionImpl(long timeout) 573 { 574 foreignTx = false; 575 xid = xidFactory.newXid(); 576 577 status = Status.STATUS_ACTIVE; 578 579 start = System.currentTimeMillis(); 580 this.timeout = timeoutFactory.createTimeout(start + timeout, this); 581 this.timeoutPeriod = timeout; 582 if (trace) 583 log.trace("Created new instance for tx=" + toString()); 584 } 585 586 590 TransactionImpl(GlobalId gid, Coordinator parentCoordinator, long timeout) 591 { 592 foreignTx = true; 593 xid = xidFactory.newBranch(gid); 594 595 this.parentCoordinator = parentCoordinator; 596 597 status = Status.STATUS_ACTIVE; 598 599 start = System.currentTimeMillis(); 600 this.timeout = timeoutFactory.createTimeout(start + timeout, this); 601 this.timeoutPeriod = timeout; 602 if (trace) 603 log.trace("Created new instance for tx=" + toString()); 604 } 605 606 610 TransactionImpl(GlobalId gid, byte[] inboundBranchQualifier, long timeout) 611 { 612 foreignTx = true; 613 xid = xidFactory.newBranch(gid); 614 615 this.inboundBranchQualifier = inboundBranchQualifier; 616 617 status = Status.STATUS_ACTIVE; 618 619 start = System.currentTimeMillis(); 620 this.timeout = timeoutFactory.createTimeout(start + timeout, this); 621 this.timeoutPeriod = timeout; 622 if (trace) 623 log.trace("Created new instance for tx=" + toString()); 624 625 } 626 627 648 TransactionImpl(long localId, 649 List preparedXAWorkList, 650 TxCompletionHandler completionHandler, 651 LogRecord.HeurData heurData) 652 { 653 foreignTx = false; 654 xid = xidFactory.recreateXid(localId); 655 status = Status.STATUS_COMMITTING; 656 if (heurData != null) 657 { 658 heuristicCode = heurData.heuristicStatusCode; 659 heuristicHazard = heurData.locallyDetectedHeuristicHazard; 660 } 661 this.completionHandler = completionHandler; 662 for (Iterator it = preparedXAWorkList.iterator(); it.hasNext(); ) 663 { 664 XAWork preparedXAWork = (XAWork) it.next(); 665 EnlistedXAResource r = new EnlistedXAResource(preparedXAWork); 666 xaResources.add(r); 667 668 } 669 commitXAResourcesAfterTimeout(); 670 } 671 672 697 TransactionImpl(long localId, 698 List preparedXAWorkList, 699 String [] resources, 700 TxCompletionHandler completionHandler, 701 LogRecord.HeurData heurData) 702 { 703 foreignTx = false; 704 xid = xidFactory.recreateXid(localId); 705 status = Status.STATUS_COMMITTING; 706 this.completionHandler = completionHandler; 707 if (heurData != null) 708 { 709 heuristicCode = heurData.heuristicStatusCode; 710 heuristicHazard = heurData.locallyDetectedHeuristicHazard; 711 } 712 for (Iterator it = preparedXAWorkList.iterator(); it.hasNext(); ) 713 { 714 XAWork preparedXAWork = (XAWork) it.next(); 715 EnlistedXAResource r = new EnlistedXAResource(preparedXAWork); 716 xaResources.add(r); 717 } 718 for (int i = 0; i < resources.length; i++) 719 { 720 EnlistedRemoteResource r = 721 new EnlistedRemoteResource(stringToResource(resources[i]), true); 722 remoteResources.add(r); 723 } 724 lock(); 725 try 726 { 727 retryCommitRemoteResources(); 728 } 729 finally 730 { 731 unlock(); 732 } 733 if (preparedXAWorkList.size() > 0) 734 { 735 commitXAResourcesAfterTimeout(); 738 } 739 else if (remoteResourcesToRetry == 0 && heuristicCode == HEUR_NONE) 740 { 741 lock(); 743 try 744 { 745 completeTransaction(); 746 } 747 finally 748 { 749 unlock(); 750 } 751 } 752 else 753 { 754 } 757 } 758 759 787 TransactionImpl(long localId, 788 int inboundFormatId, 789 byte[] globalTransactionId, 790 String recoveryCoord, 791 List preparedXAWorkList, 792 String [] resources, 793 TxCompletionHandler completionHandler, 794 LogRecord.HeurData heurData) 795 { 796 foreignTx = true; 797 GlobalId globalId = new GlobalId(inboundFormatId, globalTransactionId); 798 xid = xidFactory.recreateXid(localId, globalId); 799 recoveryCoordinator = stringToRecoveryCoordinator(recoveryCoord); 800 if (heurData == null) 801 status = Status.STATUS_PREPARED; 802 else 803 { 804 status = heurData.transactionStatus; 805 heuristicCode = heurData.heuristicStatusCode; 806 heuristicHazard = heurData.locallyDetectedHeuristicHazard; 807 } 808 this.completionHandler = completionHandler; 809 for (Iterator it = preparedXAWorkList.iterator(); it.hasNext(); ) 810 { 811 XAWork preparedXAWork = (XAWork) it.next(); 812 EnlistedXAResource r = new EnlistedXAResource(preparedXAWork); 813 xaResources.add(r); 814 } 815 for (int i = 0; i < resources.length; i++) 816 { 817 EnlistedRemoteResource r = 818 new EnlistedRemoteResource(stringToResource(resources[i]), true); 819 remoteResources.add(r); 820 } 821 822 if (Proxy.isProxyClass(recoveryCoordinator.getClass())) 824 { 825 if (dtmResourceFactory != null) 827 registeredResource = dtmResourceFactory.createResource(localId); 828 else 829 log.warn("Error reconstructing TransactionImpl instance for tx=" 830 + toString() + " -- DTM resource factory missing." ); 831 } 832 else 833 { 834 if (otsResourceFactory != null) 836 registeredResource = otsResourceFactory.createResource(localId); 837 else 838 log.warn("Error reconstructing TransactionImpl instance for tx=" + 839 toString() + " -- OTS resource factory missing." ); 840 } 841 842 if (status == Status.STATUS_PREPARED) 843 { 844 if (registeredResource != null) 845 { 846 createPreparedTimeout(); 847 if (trace) 848 log.trace("Calling replayCompletion " + 849 "on the recovery coordinator, tx=" + toString()); 850 try 851 { 852 recoveryCoordinator.replayCompletion(registeredResource); 853 } 854 catch (NoSuchObjectException noCoordinator) 855 { 856 if (trace) 857 { 858 log.trace("Exception in replayCompletion: no coordinator for tx=" 859 + toString(), noCoordinator); 860 log.trace("Rolling back transaction branch, tx=" + toString()); 861 } 862 try 863 { 864 rollbackBranch(); 865 } 866 catch (Exception e) 867 { 868 if (trace) 869 log.trace("Exception in transaction branch rollback, tx=" + 870 toString(), e); 871 } 872 } 873 catch (Exception ignore) 874 { 875 if (trace) 876 log.trace("Ignoring exception in replayCompletion, tx=" + 877 toString(), ignore); 878 } 879 } 880 else 881 log.warn("Error reconstructing TransactionImpl instance for tx=" + 882 toString() + " -- registeredResource not set.\n" + 883 "The remote coordinator will NOT be contacted."); 884 } 885 else if (status == Status.STATUS_COMMITTING) 886 { 887 lock(); 888 try 889 { 890 retryCommitRemoteResources(); 891 892 if (preparedXAWorkList.size() > 0) 893 { 894 commitXAResourcesAfterTimeout(); 897 } 898 else if (remoteResourcesToRetry == 0 && heuristicCode == HEUR_NONE) 899 { 900 completeTransaction(); 902 } 903 else 904 { 905 } 908 } 909 finally 910 { 911 unlock(); 912 } 913 } 914 |