1 53 package org.objectweb.jotm; 54 55 import java.rmi.RemoteException ; 56 import java.util.ArrayList ; 57 import java.util.Collections ; 58 import java.util.List ; 59 import javax.transaction.*; 60 import javax.transaction.xa.XAException ; 61 import javax.transaction.xa.XAResource ; 62 63 71 72 public class TransactionImpl implements Transaction, TimerEventListener { 73 74 private SubCoordinator subcoord = null; 78 private TransactionContext myCtx = null; 79 private Xid myXid = null; 80 private boolean genXidhashcode = false; 81 private boolean genXidtostring = false; 82 private int myXidhashcode = 0; 83 private String myXidtostring = null; 84 private String txDate = null; 85 private boolean interpose = false; 86 private int ucount = 0; private TimerEvent timer = null; private RecoveryCoordinator recoveryCoord = null; 89 private List enlistedXARes = Collections.synchronizedList(new ArrayList ()); 91 private List delistedXARes = null; 93 private boolean propagateCtx = true; 95 private List enlistedJavaxXid = Collections.synchronizedList(new ArrayList ()); 96 100 106 107 public TransactionImpl(Xid xid, int timeout) throws SystemException { 108 if (TraceTm.jta.isDebugEnabled()) { 109 TraceTm.jta.debug("xid= " + xid); 110 TraceTm.jta.debug("timeout= " + timeout); 111 } 112 113 myXid = xid; 115 myCtx = new InternalTransactionContext(timeout, null, (javax.transaction.xa.Xid ) xid); 118 } 119 120 126 127 public TransactionImpl(TransactionContext pctx) { 128 129 if (pctx == null) { 130 TraceTm.jotm.error("TransactionImpl: null PropagationContext"); 131 } 132 myCtx = pctx; 133 myXid = pctx.getXid(); 134 interpose = true; 138 } 139 140 144 169 170 public void commit() 171 throws 172 RollbackException, 173 HeuristicMixedException, 174 HeuristicRollbackException, 175 SecurityException , 176 SystemException { 177 178 if (TraceTm.jta.isDebugEnabled()) { 179 TraceTm.jta.debug("TransactionImpl.commit (tx= " + this +")"); 180 } 181 182 Terminator term = myCtx.getTerminator(); 184 185 if (term != null) { 186 try { 188 propagateCtx = false; 189 term.commit(true); 190 propagateCtx = true; 191 } catch (TransactionRolledbackException e) { 192 Current.getCurrent().forgetTx(getXid()); 193 if (TraceTm.jta.isDebugEnabled()) { 194 TraceTm.jta.debug("Commit distributed transaction -> rolled back!"); 195 } 196 throw new RollbackException(); 197 } catch (RemoteException e) { 198 199 if (TraceTm.jta.isWarnEnabled()) { 200 TraceTm.jta.warn("got a RemoteException", e); 201 } 202 203 if (e.detail instanceof TransactionRolledbackException) { 204 Current.getCurrent().forgetTx(getXid()); 205 if (TraceTm.jta.isDebugEnabled()) { 206 TraceTm.jta.debug("Commit distributed transaction -> rolled back!"); 207 } 208 throw new RollbackException(); 209 } 210 211 if (e.detail instanceof HeuristicMixed) { 212 TraceTm.jotm.info( 213 "Commit distributed transaction -> Heuristic mixed!"); 214 throw new HeuristicMixedException(); 215 } else { 216 throw new SystemException( 217 "Unexpected RemoteException on commit:" 218 + e.detail.getMessage()); 219 } 220 } catch (Exception e) { 221 TraceTm.jotm.error("Unexpected Exception on commit:", e); 222 throw new SystemException("Unexpected Exception on commit"); 223 } 224 225 if (subcoord == null) { 226 unsetTimer(); 228 } 229 230 Current.getCurrent().forgetTx(getXid()); 231 return; 232 } 233 234 237 if (subcoord != null) { 238 try { 239 subcoord.commit_one_phase(); 240 } catch (TransactionRolledbackException e) { 241 if (TraceTm.jta.isDebugEnabled()) { 242 TraceTm.jta.debug("Commit local transaction -> rolled back!"); 243 } 244 Current.getCurrent().forgetTx(getXid()); 245 throw new RollbackException(); 246 } catch (RemoteException e) { 247 TraceTm.jotm.error( 248 "Unexpected Exception on commit_one_phase:", 249 e); 250 Current.getCurrent().forgetTx(getXid()); 251 throw new SystemException("Unexpected Exception on commit_one_phase"); 252 } 253 } else { 254 unsetTimer(); 256 Current.getCurrent().forgetTx(getXid()); 257 } 258 } 259 260 277 278 public boolean delistResource(XAResource xares, int flag) 279 throws IllegalStateException , SystemException { 280 281 if (TraceTm.jta.isDebugEnabled()) { 282 TraceTm.jta.debug("TransactionImpl.delistResource"); 283 TraceTm.jta.debug("xares= " + xares + ", flag= " + flag); 284 } 285 286 if (enlistedXARes == null) { 287 if (TraceTm.jta.isDebugEnabled()) { 288 TraceTm.jta.error("No XA resources enlisted by JOTM"); 289 } 290 return false; 291 } 292 293 295 if (!enlistedXARes.contains(xares)) { 296 if (TraceTm.jta.isDebugEnabled()) { 297 TraceTm.jta.error("XAResouce " + xares + " not enlisted by JOTM"); 298 } 299 return false; 300 } 301 302 Xid resXid = new XidImpl( getXid(),subcoord.getXaresIndex(xares) ); 303 304 javax.transaction.xa.Xid javaxxid = subcoord.getJavaxXid(subcoord.getXaresIndex(xares)); 305 306 if (!enlistedJavaxXid.contains(javaxxid)) { 307 if (TraceTm.jta.isDebugEnabled()) { 308 TraceTm.jta.error("XAResouce " + xares + " not enlisted by JOTM"); 309 } 310 return false; 311 } 312 313 int javaxxidindex = enlistedJavaxXid.indexOf(javaxxid); 314 javax.transaction.xa.Xid myjavaxxid = (javax.transaction.xa.Xid ) enlistedJavaxXid.get(javaxxidindex); 315 316 if (TraceTm.jta.isDebugEnabled()) { 317 TraceTm.jta.debug("resXid= " + resXid); 318 TraceTm.jta.debug("delisted with resource= " + xares); 319 TraceTm.jta.debug("end myjavaxxid= " + myjavaxxid); 320 } 321 322 try { 324 xares.end (myjavaxxid, flag); 325 } catch (XAException e) { 327 String error = 328 "Cannot send XA end:" 329 + e 330 + " (error code = " 331 + e.errorCode 332 + ") --" 333 + e.getMessage(); 334 TraceTm.jotm.error(error); 335 if (TraceTm.jta.isDebugEnabled()) { 336 TraceTm.jotm.debug("xares.end= " + xares); 337 } 338 throw new SystemException(error); 339 } 340 341 if (TraceTm.jta.isDebugEnabled()) { 342 TraceTm.jta.debug("enlistedXAres.remove xares= " + xares); 343 } 344 345 enlistedXARes.remove(xares); 347 enlistedJavaxXid.remove(javaxxid); 348 return true; 349 } 350 351 370 371 public boolean enlistResource(XAResource xares) 372 throws RollbackException, IllegalStateException , SystemException { 373 374 if (TraceTm.jta.isDebugEnabled()) { 375 TraceTm.jta.debug("TransactionImpl.enlistResource"); 376 TraceTm.jta.debug("xares= " + xares); 377 } 378 379 if (xares == null) { 381 TraceTm.jotm.error("enlistResource: null argument"); 382 throw new SystemException("enlistResource: null argument"); 383 } 384 385 if (myCtx == null) { 386 throw new SystemException("enlistResource: no Transactional Context"); 387 } 388 389 if (subcoord == null) { 391 makeSubCoord(); 392 if (subcoord == null) { 393 TraceTm.jotm.error( 394 "enlistResource: could not create subcoordinator"); 395 throw new SystemException("enlistResource: could not create subcoordinator"); 396 } 397 } 398 399 boolean found = false; 400 401 try{ 402 found = subcoord.addResource(xares); 403 } catch (IllegalStateException e) { 404 throw new IllegalStateException ("enlistResource: could not addResource " + xares); 405 } 406 407 boolean rollbackOnly = false; 408 409 int flag = found ? XAResource.TMJOIN : XAResource.TMNOFLAGS; 413 414 if ((delistedXARes != null) && delistedXARes.contains(xares)) { 415 flag = XAResource.TMRESUME; 416 } 417 418 Xid resXid = new XidImpl( getXid(),subcoord.getXaresIndex(xares) ); 419 javax.transaction.xa.Xid javaxxid = new JavaXidImpl(resXid); 420 421 if (TraceTm.jta.isDebugEnabled()) { 422 TraceTm.jta.debug("resXid= " + resXid); 423 TraceTm.jta.debug("enlisted with resource= " + xares); 424 TraceTm.jta.debug("start javaxxid= " + javaxxid); 425 } 426 427 if (!found) { 428 subcoord.addJavaxXid(javaxxid); 429 } 430 431 try { 432 xares.start (javaxxid, flag); 433 } catch (XAException e) { 435 String error = 436 "Cannot send XA(" 437 +xares 438 + ") start:" 439 + e 440 + " (error code = " 441 + e.errorCode 442 + ") --" 443 + e.getMessage(); 444 TraceTm.jotm.error(error); 445 throw new SystemException(error); 446 } 447 448 if (rollbackOnly) { 449 throw new RollbackException(); 450 } 451 452 if (!enlistedXARes.contains(xares)) { 453 enlistedXARes.add(xares); 455 enlistedJavaxXid.add(javaxxid); 456 } 457 458 int status = this.getStatus(); 459 460 switch (status) { 461 case Status.STATUS_ACTIVE : 462 case Status.STATUS_PREPARING : 463 break; 464 case Status.STATUS_PREPARED : 465 throw new IllegalStateException ("Transaction already prepared."); 466 case Status.STATUS_COMMITTING : 467 break; 469 case Status.STATUS_COMMITTED : 470 throw new IllegalStateException ("Transaction already committed."); 471 case Status.STATUS_MARKED_ROLLBACK : 472 throw new RollbackException("Transaction already marked for rollback"); 473 case Status.STATUS_ROLLING_BACK : 474 throw new RollbackException("Transaction already started rolling back."); 475 case Status.STATUS_ROLLEDBACK : 476 throw new RollbackException("Transaction already rolled back."); 477 case Status.STATUS_NO_TRANSACTION : 478 throw new IllegalStateException ("No current transaction."); 479 case Status.STATUS_UNKNOWN : 480 throw new IllegalStateException ("Unknown transaction status"); 481 default : 482 throw new IllegalStateException ("Illegal transaction status: " + status); 483 } 484 485 return true; 486 } 487 488 490 public void doDetach(int flag) throws SystemException { 491 if (TraceTm.jta.isDebugEnabled()) { 492 TraceTm.jta.debug("TransactionImpl.doDetach flag= " + XAResourceHelper.getFlagName(flag)); 493 TraceTm.jta.debug("number of enlisted= " + enlistedXARes.size()); 494 } 495 496 499 delistedXARes = new ArrayList (enlistedXARes); 500 501 for (int i = 0; i < delistedXARes.size(); i++) { 502 delistResource((XAResource ) delistedXARes.get(i), flag); 503 } 504 } 505 506 508 public void doAttach(int flag) throws SystemException, RollbackException { 509 if (TraceTm.jta.isDebugEnabled()) { 510 TraceTm.jta.debug("TransactionImpl.doAttach flag= " + XAResourceHelper.getFlagName(flag)); 511 TraceTm.jta.debug("number of enlisted= " + enlistedXARes.size()); 512 } 513 514 516 if (flag == XAResource.TMRESUME) { 517 519 for (int i = 0; 520 (delistedXARes != null) && (i < delistedXARes.size()); 521 i++) { 522 523 enlistResource((XAResource ) delistedXARes.get(i)); 524 } 525 } 526 527 delistedXARes = null; 528 } 529 530 532 public List getEnlistedXAResource() { 533 if (TraceTm.jta.isDebugEnabled()) { 534 TraceTm.jta.debug("getEnlistedXAResource size= " + enlistedXARes.size()); 535 } 536 return new ArrayList (enlistedXARes); 537 } 538 539 550 551 public int getStatus() throws SystemException { 552 if (TraceTm.jta.isDebugEnabled()) { 553 TraceTm.jta.debug("TransactionImpl.getStatus()"); 554 } 555 556 Coordinator coord = myCtx.getCoordinator(); 558 559 if (coord != null) { 560 int ret; 562 try { 563 ret = coord.get_status(); 564 } catch (Exception e) { 565 TraceTm.jotm.error("cannot reach JTM:", e); 566 return Status.STATUS_NO_TRANSACTION; 567 } 568 return ret; 569 } 570 571 574 if (subcoord == null) { 575 return Status.STATUS_ACTIVE; 578 } 579 580 return subcoord.getStatus(); 581 } 582 583 602 603 public void registerSynchronization(Synchronization sync) 604 throws RollbackException, IllegalStateException , SystemException { 605 if (TraceTm.jta.isDebugEnabled()) { 606 TraceTm.jta.debug("TransactionImpl.registerSynchronization(Synchronization sync)"); 607 } 608 609 if (subcoord == null) { 611 makeSubCoord(); 612 } 613 614 subcoord.addSynchronization(sync); 617 } 618 619 629 630 public void rollback() throws IllegalStateException , SystemException { 631 if (TraceTm.jta.isDebugEnabled()) { 632 TraceTm.jta.debug("TransactionImpl.rollback(tx= " + this +")"); 633 } 634 635 Terminator term = myCtx.getTerminator(); 637 638 if (term != null) { 639 try { 641 propagateCtx = false; 642 term.rollback(); 643 propagateCtx = true; 644 } catch (java.rmi.ServerException e) { 645 throw new IllegalStateException ( 647 "Exception on rollback:" + e.detail); 648 } catch (Exception e) { 649 Current.getCurrent().forgetTx(getXid()); 650 throw new SystemException("Unexpected Exception on rollback"); 651 } 652 653 if (subcoord == null) { 654 unsetTimer(); 656 } 657 658 Current.getCurrent().forgetTx(getXid()); 660 return; 661 } 662 663 666 if (subcoord != null) { 667 try { 668 subcoord.rollback(); 669 } catch (RemoteException e) { 670 Current.getCurrent().forgetTx(getXid()); 671 throw new IllegalStateException ("Exception on rollback:" + e); 672 } 673 674 } else { 675 unsetTimer(); 677 } 678 679 Current.getCurrent().forgetTx(getXid()); 681 } 682 683 693 694 public int prepare() throws IllegalStateException , SystemException { 695 if (TraceTm.jta.isDebugEnabled()) { 696 TraceTm.jta.debug("TransactionImpl.prepare(tx= " + this +")"); 697 } 698 699 int ret = 0; 700 if (subcoord != null) { 701 try { 702 ret = subcoord.prepare(); 703 } catch (RemoteException e) { 704 TraceTm.jotm.error( 705 "Unexpected Exception on prepare:", 706 e); 707 throw new SystemException("Unexpected Exception on prepare"); 708 } 709 } 710 711 return ret; 712 } 713 714 726 727 public void setRollbackOnly() throws IllegalStateException , SystemException { 728 if (TraceTm.jta.isDebugEnabled()) { 729 TraceTm.jta.debug("TransactionImpl.setRollbackOnly(tx= " + this +")"); 730 } 731 732 Coordinator coord = myCtx.getCoordinator(); 734 735 if (coord != null) { 736 try { 737 coord.rollback_only(); 738 } catch (RemoteException e) { 739 TraceTm.jotm.error("Cannot perform coordinator rollback only", e); 740 } 741 } 742 743 750 if (subcoord == null) { 751 makeSubCoord(); 753 } 754 755 subcoord.setRollbackOnly(); 756 } 758 759 763 766 767 public void timeoutExpired(Object arg) { 768 if (TraceTm.jta.isDebugEnabled()) { 769 TraceTm.jta.debug("TransactionImpl.timeoutExpired"); 770 } 771 772 Current.getCurrent().incrementExpiredCounter(); 774 775 777 if (subcoord == null) { 778 Terminator term = myCtx.getTerminator(); 781 782 if (term != null) { 783 TraceTm.jotm.info("forget tx (tx=" + this +")"); 784 Current.getCurrent().forgetTx(getXid()); 785 return; 786 } 787 788 makeSubCoord(); 789 } 790 791 TraceTm.jotm.info("set rollback only (tx=" + this +")"); 794 795 try { 796 subcoord.setRollbackOnly(); 797 } catch (Exception e) { 798 TraceTm.jotm.error("cannot rollbackonly:" + e); 799 return; 800 } 801 } 802 803 807 810 811 public boolean equals(Object obj2) { 812 TransactionImpl tx2 = (TransactionImpl) obj2; 813 814 if (tx2 == this) { 816 return true; 817 } 818 if (tx2 == null) { 819 return false; 820 } 821 822 return getXid().equals(tx2.getXid()); 824 } 825 826 829 830 public int hashCode() { 831 if (!genXidhashcode) { 832 genXidhashcode = true; 833 myXidhashcode = getXid().hashCode(); 834 } 835 836 return myXidhashcode; 837 } 839 840 844 847 848 public String toString() { 849 if (!genXidtostring) { 850 genXidtostring = true; 851 myXidtostring = getXid().toString(); 852 } 853 854 return myXidtostring; 855 } 857 858 864 865 public synchronized TransactionContext getPropagationContext(boolean hold) { 866 867 if (propagateCtx) { 868 if (hold) { 869 ucount++; 870 } 871 return myCtx; 872 } else { 873 return null; 874 } 875 } 876 877 880 881 public void setTimer(TimerEvent timer) { 882 if (TraceTm.jta.isDebugEnabled()) { 883 TraceTm.jta.debug("set timer for tx (timer=" + timer + ", tx=" + this +")"); 884 } 885 this.timer = timer; 886 } 887 888 891 892 public void unsetTimer() { 893 if (TraceTm.jta.isDebugEnabled()) { 894 TraceTm.jta.debug("unset timer for tx (timer=" + timer + ", tx=" + this +")"); 895 } 896 if (timer != null) { 897 timer.unset(); 898 timer = null; 899 } 900 } 901 902 905 906 public void setTxDate(String date) { 907 if (TraceTm.jta.isDebugEnabled()) { 908 TraceTm.jta.debug("set date for tx (data=" + date + ", tx=" + this +")"); 909 } 910 txDate = date; 911 } 912 913 916 917 public String getTxDate() { 918 if (TraceTm.jta.isDebugEnabled()) { 919 TraceTm.jta.debug("get date for tx (date=" + txDate + ", tx=" + this +")"); 920 } 921 return txDate; 922 } 923 924 928 929 public synchronized void updatePropagationContext(TransactionContext pctx) { 930 if (TraceTm.jta.isDebugEnabled()) { 931 TraceTm.jta.debug("TransactionImpl.updatePropagationContext"); 932 } 933 934 Coordinator remoteCoord = pctx.getCoordinator(); 935 936 if (remoteCoord == null && myCtx.getCoordinator() != null) { 937 TraceTm.jotm.error("setPropagationContext: Bad Coordinator"); 938 TraceTm.jotm.error("remoteCoord = " + remoteCoord); 939 TraceTm.jotm.error("myCtx.getCoordinator()= " + myCtx.getCoordinator()); 940 return; 941 } 942 943 ucount--; 945 946 if (remoteCoord != null && myCtx.getCoordinator() == null) { 948 myCtx.setCoordinator(pctx.getCoordinator()); 949 950 if (subcoord != null) { 951 try { 953 recoveryCoord = remoteCoord.register_resource(subcoord); 954 } catch (RemoteException e) { 955 TraceTm.jotm.error("Cannot make interposition:", e); 956 return; 957 } 958 } 959 } 960 961 if ( pctx.getTerminator() != null ) { 962 myCtx.setTerminator(pctx.getTerminator()); 963 } 964 } 965 966 969 970 public Xid getXid() { 971 return myXid; 972 } 973 974 977 978 private void makeSubCoord() { 979 if (TraceTm.jta.isDebugEnabled()) { 980 TraceTm.jta.debug("make subcoordinator"); 981 } 982 983 try { 985 subcoord = new SubCoordinator(this, getXid()); 986 } catch (RemoteException e) { 987 TraceTm.jotm.error("new SubCoordinator raised exception: ", e); 989 return; 990 } 991 992 Coordinator remoteCoord = myCtx.getCoordinator(); 995 996 999 if (interpose && remoteCoord == null) { 1000 try { 1001 if (TraceTm.jta.isDebugEnabled()) { 1004 TraceTm.jta.debug("Creating a remote Control on JTM for a distributed transaction"); 1005 } 1006 1007 remoteCoord = 1008 (Coordinator) javax.rmi.PortableRemoteObject.narrow( 1009 Current.getJTM().create(myCtx.getTimeout()), 1010 Coordinator.class); 1011 1012 } catch (RemoteException e) { 1013 TraceTm.jotm.error("Cannot create distributed transaction:", e); 1014 return; 1015 } 1016 1017 myCtx.setCoordinator(remoteCoord); 1018 1019 1022 if (myCtx.getTerminator() == null) { 1023 myCtx.setTerminator((Terminator ) remoteCoord); 1024 } 1025 } 1026 1027 if (remoteCoord != null && recoveryCoord == null) { 1030 try { 1031 recoveryCoord = remoteCoord.register_resource(subcoord); 1032 } catch (RemoteException e) { 1033 TraceTm.jotm.error("Cannot make interposition:", e); 1034 return; 1035 } 1036 } 1037 } 1038 1039 1042 1043 public boolean isRemovable() { 1044 return (ucount == 0 && subcoord == null); 1045 } 1046 1047} 1048 | Popular Tags |