| 1 54 55 package org.objectweb.jotm; 56 57 import java.rmi.RemoteException ; 58 59 import java.util.List ; 60 import java.util.Vector ; 61 import java.nio.ByteBuffer ; 62 import javax.transaction.*; 63 import javax.transaction.xa.XAException ; 64 import javax.transaction.xa.XAResource ; 65 import javax.rmi.PortableRemoteObject ; 67 68 import org.objectweb.howl.log.xa.XACommittingTx; 69 70 73 class SLog { 74 75 private Vector loggedResources = new Vector (); 76 77 private Vector loggedXids = new Vector (); 78 79 int decision; 80 static final int DECISION_TO_COMMIT = 1; 81 static final int DECISION_TO_ROLLBACK = 2; 82 83 public void addResource( XAResource res, Xid xid ) 84 { 85 if (TraceTm.jta.isDebugEnabled()) { 86 TraceTm.jta.debug("res= "+ res); 87 TraceTm.jta.debug("xid= "+ xid); 88 } 89 loggedResources.addElement(res); 90 loggedXids.addElement(xid); 91 } 92 93 96 public List getLoggedResources() { 97 if (TraceTm.jta.isDebugEnabled()) { 98 TraceTm.jta.debug("logged resources="+ loggedResources); 99 } 100 return loggedResources; 101 } 102 103 public List getLoggedXids() { 104 return loggedXids; 105 } 106 107 public void flushLog(int decide) { 108 if (TraceTm.jta.isDebugEnabled()) { 109 TraceTm.jta.debug("decide="+ decide); 110 } 111 decision = decide; 112 113 } 115 116 public void forgetLog() { 117 if (TraceTm.jta.isDebugEnabled()) { 118 TraceTm.jta.debug("forget log"); 119 } 120 } 122 } 123 124 129 public class SubCoordinator extends PortableRemoteObject implements Resource { 130 131 135 138 private TransactionImpl tx = null; 139 140 144 private Vector synchroList = new Vector (); 145 146 150 private Vector resourceList = new Vector (); 151 private Vector javaxxidList = new Vector (); 152 153 157 private TransactionManager tm; 158 159 162 private Xid xid = null; 163 164 167 private SLog log = null; 168 169 186 private int status = Status.STATUS_ACTIVE; 187 188 191 private boolean beforeCompletionDone = false; 192 193 197 200 201 SubCoordinator(TransactionImpl tx, Xid xid) throws RemoteException { 202 203 if (TraceTm.jta.isDebugEnabled()) { 204 TraceTm.jta.debug("tx="+ tx +", xid="+ xid); 205 } 206 207 this.tx = tx; 208 this.xid = xid; 209 this.tm = Current.getTransactionManager(); 210 211 Current.getCurrent().incrementBeginCounter(); 213 beforeCompletionDone = false; 214 } 215 216 220 225 226 public int prepare() throws RemoteException { 227 228 if (TraceTm.jta.isDebugEnabled()) { 229 TraceTm.jta.debug("status="+ StatusHelper.getStatusName(status)); 230 } 231 232 try { 233 tx.doDetach(XAResource.TMSUCCESS); 234 } catch (SystemException e) { 235 236 if (TraceTm.jta.isDebugEnabled()) { 237 String error = 238 "Error when detaching XAResource:" 239 + e 240 + "--" 241 + e.getMessage(); 242 TraceTm.jta.debug(error); 243 } 244 } 245 246 switch (status) { 247 case Status.STATUS_MARKED_ROLLBACK : 248 doBeforeCompletion(false); 249 doRollback(); 250 return Resource.VOTE_ROLLBACK; 251 case Status.STATUS_COMMITTED : 252 return Resource.VOTE_COMMIT; 253 default : 254 doBeforeCompletion(true); 255 break; 256 } 257 258 260 if (status == Status.STATUS_MARKED_ROLLBACK) { 261 TraceTm.jotm.info( 262 "Rollback during beforeCompletion in SubCoordinator.prepare"); 263 doRollback(); 264 return Resource.VOTE_ROLLBACK; 265 } 266 267 int ret = doPrepare(); 268 269 if (ret == Resource.VOTE_READONLY) { 270 doAfterCompletion(); 272 } 273 274 if (TraceTm.jta.isDebugEnabled()) { 275 TraceTm.jta.debug("vote = " + ret); 276 } 277 278 return ret; 279 } 280 281 284 285 public void rollback() throws RemoteException { 286 287 if (TraceTm.jta.isDebugEnabled()) { 288 TraceTm.jta.debug("status="+ StatusHelper.getStatusName(status)); 289 } 290 291 try { 292 tx.doDetach(XAResource.TMSUCCESS); 293 } catch (SystemException e) { 294 if (TraceTm.jta.isDebugEnabled()) { 295 String error = 296 "Error when detaching XAResource:" 297 + e 298 + "--" 299 + e.getMessage(); 300 TraceTm.jta.debug(error); 301 } 302 } 303 304 switch (status) { 305 case Status.STATUS_ACTIVE : 306 case Status.STATUS_MARKED_ROLLBACK : 307 case Status.STATUS_ROLLING_BACK: 308 if (TraceTm.jotm.isDebugEnabled()) { 309 TraceTm.jotm.debug("transaction rolling back"); 310 } 311 break; 312 case Status.STATUS_PREPARED: 313 if (TraceTm.jotm.isDebugEnabled()) { 314 TraceTm.jotm.debug("should not rollback a prepared transaction"); 315 } 316 break; 317 case Status.STATUS_ROLLEDBACK : 318 if (TraceTm.jotm.isDebugEnabled()) { 319 TraceTm.jotm.debug("already rolledback"); 320 } 321 return; 322 default : 323 TraceTm.jotm.error( 324 "rollback: bad status: " 325 + StatusHelper.getStatusName(status)); 326 return; 327 } 328 329 doBeforeCompletion(false); 330 doRollback(); 331 } 332 333 336 337 public void commit() throws RemoteException { 338 339 if (TraceTm.jta.isDebugEnabled()) { 340 TraceTm.jta.debug("status="+ StatusHelper.getStatusName(status)); 341 } 342 343 switch (status) { 344 case Status.STATUS_PREPARED : 345 break; 346 default : 347 TraceTm.jotm.error( 348 "commit: bad status: " 349 + StatusHelper.getStatusName(status)); 350 return; 351 } 352 353 doCommit(); 354 } 355 356 360 361 public void commit_one_phase() throws RemoteException { 362 363 if (TraceTm.jta.isDebugEnabled()) { 364 TraceTm.jta.debug("status="+ StatusHelper.getStatusName(status)); 365 } 366 367 switch (status) { 368 case Status.STATUS_ROLLEDBACK : 369 try { 370 tx.doDetach(XAResource.TMSUCCESS); 371 } catch (SystemException e) { 372 373 if (TraceTm.jta.isDebugEnabled()) { 374 String error = 375 "Error when detaching XAResource:" 376 + e 377 + "--" 378 + e.getMessage(); 379 TraceTm.jta.debug(error); 380 } 381 } 382 throw new TransactionRolledbackException(); 383 case Status.STATUS_MARKED_ROLLBACK : 384 doBeforeCompletion(false); 385 try { 386 tx.doDetach(XAResource.TMSUCCESS); 387 } catch (SystemException e) { 388 389 if (TraceTm.jta.isDebugEnabled()) { 390 String error = 391 "Error when detaching XAResource:" 392 + e 393 + "--" 394 + e.getMessage(); 395 TraceTm.jta.debug(error); 396 } 397 } 398 doRollback(); 399 throw new TransactionRolledbackException(); 400 case Status.STATUS_COMMITTED : 401 try { 402 tx.doDetach(XAResource.TMSUCCESS); 403 } catch (SystemException e) { 404 405 if (TraceTm.jta.isDebugEnabled()) { 406 String error = 407 "Error when detaching XAResource:" 408 + e 409 + "--" 410 + e.getMessage(); 411 TraceTm.jta.debug(error); 412 } 413 } 414 return; 415 default : 416 doBeforeCompletion(true); 417 try { 418 tx.doDetach(XAResource.TMSUCCESS); 419 } catch (SystemException e) { 420 421 if (TraceTm.jta.isDebugEnabled()) { 422 String error = 423 "Error when detaching XAResource:" 424 + e 425 + "--" 426 + e.getMessage(); 427 TraceTm.jta.debug(error); 428 } 429 } 430 break; 431 } 432 433 435 if (TraceTm.jta.isDebugEnabled()) { 436 TraceTm.jta.debug("status="+ StatusHelper.getStatusName(status)); 437 } 438 439 441 if (status == Status.STATUS_MARKED_ROLLBACK) { 442 TraceTm.jotm.info( 443 "Rollback during beforeCompletion in SubCoordinator.commit_one_phase"); 444 doRollback(); 445 throw new TransactionRolledbackException(); 446 } 447 448 450 if (resourceList.size() == 1) { 451 doOnePhaseCommit(); 452 return; 453 } 454 455 457 int vote = doPrepare(); 458 459 switch (vote) { 460 case Resource.VOTE_COMMIT : 461 doCommit(); 462 break; 463 case Resource.VOTE_READONLY : 464 doAfterCompletion(); 465 break; 466 case Resource.VOTE_ROLLBACK : 467 doRollback(); 468 throw new TransactionRolledbackException(); 469 } 470 } 471 472 475 476 public void forget() throws RemoteException { 477 if (TraceTm.jta.isDebugEnabled()) { 478 TraceTm.jta.debug("SubCoordinator.forget()"); 479 } 480 doForget(); 481 } 482 483 487 500 501 public void addSynchronization(Synchronization synchro) 502 throws RollbackException, IllegalStateException { 503 504 if (TraceTm.jta.isDebugEnabled()) { 505 TraceTm.jta.debug("synchro="+ synchro); 506 TraceTm.jta.debug("status="+ StatusHelper.getStatusName(status)); 507 } 508 509 511 boolean markedRollback = false; 512 513 switch (status) { 514 case Status.STATUS_MARKED_ROLLBACK : 515 case Status.STATUS_ROLLEDBACK : 516 markedRollback = true; 517 break; 518 case Status.STATUS_ACTIVE : 519 break; 520 default : 521 String errorMsg = 522 "addSynchronization: bad status = " 523 + StatusHelper.getStatusName(status); 524 TraceTm.jotm.error(errorMsg); 525 throw new IllegalStateException (errorMsg); 526 } 527 528 530 synchroList.addElement(synchro); 531 532 537 if (markedRollback) { 538 if (TraceTm.jta.isDebugEnabled()) { 539 TraceTm.jta.debug("SubCoordinator.addSynchronization: transaction rollback only"); 540 } 541 throw new RollbackException(); 542 } 543 544 } 545 546 556 557 public synchronized boolean addResource(XAResource xares) 558 throws IllegalStateException { 559 560 if (TraceTm.jta.isDebugEnabled()) { 561 TraceTm.jta.debug("xares="+ xares); 562 TraceTm.jta.debug("status="+ StatusHelper.getStatusName(status)); 563 } 564 565 567 boolean markedRollback = false; 568 569 switch (status) { 570 case Status.STATUS_MARKED_ROLLBACK : 571 markedRollback = true; 572 break; 573 case Status.STATUS_ACTIVE : 574 break; 575 default : 576 String errorMsg = 577 "SubCoordinator.addResource: bad status= " 578 + StatusHelper.getStatusName(status); 579 TraceTm.jotm.error(errorMsg); 580 throw new IllegalStateException (errorMsg); 581 } 582 583 586 boolean found = false; 587 588 for (int i = 0; i < resourceList.size(); i++) { 589 XAResource res = (XAResource ) resourceList.elementAt(i); 590 591 try { 592 if (res.isSameRM(xares)) { 593 found = true; 594 break; 595 } 596 } catch (XAException e) { 597 String error = 598 "Cannot send res.isSameRM:" 599 + e 600 + " (error code = " 601 + e.errorCode 602 + ") --" 603 + e.getMessage(); 604 TraceTm.jotm.error( 605 "Exception on resource.isSameRM: "+ error); 606 } 607 } 608 609 611 if (found == false) { 612 if (TraceTm.jta.isDebugEnabled()) { 613 TraceTm.jta.debug("new XAResource added to the list"); 614 } 615 resourceList.addElement(xares); 616 } 617 618 623 if (markedRollback) { 624 if (TraceTm.jta.isDebugEnabled()) { 625 TraceTm.jta.debug("SubCoordinator.addResource: transaction set rollback only"); 626 } 627 } 628 629 return found; 630 } 631 632 public synchronized void addJavaxXid(javax.transaction.xa.Xid javaxxid) { 633 634 if (TraceTm.jta.isDebugEnabled()) { 635 TraceTm.jta.debug("addJavaxXid javaxxid="+ javaxxid); 636 } 637 638 640 javaxxidList.addElement(javaxxid); 641 642 if (TraceTm.jta.isDebugEnabled()) { 643 TraceTm.jta.debug("new JavaxXid added to the list"); 644 } 645 646 } 647 648 651 652 public int getStatus() { 653 654 if (TraceTm.jta.isDebugEnabled()) { 655 TraceTm.jta.debug("status="+ StatusHelper.getStatusName(status)); 656 } 657 658 return status; 659 } 660 661 public javax.transaction.xa.Xid getJavaxXid(int xaresindex) { 662 javax.transaction.xa.Xid myjavaxxid = (javax.transaction.xa.Xid ) javaxxidList.elementAt(xaresindex); 663 return myjavaxxid; 664 } 665 666 669 670 public void setRollbackOnly() { 671 672 if (TraceTm.jta.isDebugEnabled()) { 673 TraceTm.jta.debug("status="+ StatusHelper.getStatusName(status)); 674 } 675 676 switch (status) { 677 case Status.STATUS_ACTIVE : 678 case Status.STATUS_UNKNOWN : 679 case Status.STATUS_PREPARING : 680 status = Status.STATUS_MARKED_ROLLBACK; 681 break; 682 case Status.STATUS_MARKED_ROLLBACK : 683 case Status.STATUS_ROLLING_BACK : 684 break; 685 case Status.STATUS_PREPARED : 686 case Status.STATUS_COMMITTED : 687 case Status.STATUS_ROLLEDBACK : 688 case Status.STATUS_NO_TRANSACTION : 689 case Status.STATUS_COMMITTING : 690 TraceTm.jotm.error("Cannot set transaction as rollback only"); 691 TraceTm.jotm.error("Bad status="+ StatusHelper.getStatusName(status)); 692 break; 693 } 694 } 695 696 700 703 704 private void doForget() throws RemoteException { 705 if (TraceTm.jta.isDebugEnabled()) { 706 TraceTm.jta.debug("SubCoordinator.doForget()"); 707 } 708 709 boolean exception = false; 710 711 for (int i = 0; i < resourceList.size(); i++) { 712 XAResource xar = (XAResource ) resourceList.elementAt(i); 715 716 javax.transaction.xa.Xid myjavaxxid = (javax.transaction.xa.Xid )javaxxidList.elementAt(i); 717 Xid xid = new XidImpl( this.xid, i ); 718 719 if (TraceTm.jta.isDebugEnabled()) { 720 TraceTm.jta.debug("xid= " + xid); 721 TraceTm.jta.debug("myjavaxxid= " + myjavaxxid); 722 TraceTm.jta.debug("forgotten with resource= " + xar); 723 } 724 725 try { 726 xar.forget(myjavaxxid); 727 } catch (XAException e) { 729 String error = 730 "Cannot send xar.forget:" 731 + e 732 + " (error code = " 733 + e.errorCode 734 + ") --" 735 + e.getMessage(); 736 TraceTm.jotm.error( 737 "Got XAException from xar.forget: "+ error); 738 exception = true; 739 } 740 } 741 742 if (exception) { 743 throw new RemoteException ("XAException on forget"); 744 } 745 746 unexportObject(this); 747 } 748 749 754 755 private synchronized int doPrepare() throws RemoteException { 756 if (TraceTm.jta.isDebugEnabled()) { 757 TraceTm.jta.debug("SubCoordinator.doPrepare()"); 758 } 759 760 String jotmPrepareRecord = "PREPARE"; 761 762 int ret = VOTE_READONLY; 763 int errors = 0; 764 765 767 if (resourceList.size() == 0) { 768 Current.getCurrent().incrementCommitCounter(); 770 status = Status.STATUS_COMMITTED; 771 return ret; 772 } 773 774 778 log = new SLog(); 779 780 783 status = Status.STATUS_PREPARING; 784 785 for (int i = 0; i < resourceList.size(); i++) { 786 XAResource res = (XAResource ) resourceList.elementAt(i); 787 javax.transaction.xa.Xid myjavaxxid = (javax.transaction.xa.Xid ) javaxxidList.elementAt(i); 788 789 Xid xid = new XidImpl( this.xid, i ); 790 791 if (errors > 0) { 792 793 if (TraceTm.jta.isDebugEnabled()) { 794 TraceTm.jta.debug("xid= " + xid); 795 TraceTm.jta.debug("myjavaxxid= " + myjavaxxid); 796 TraceTm.jta.debug("rolled back with resource= " + res); 797 } 798 799 try { 800 res.rollback(myjavaxxid); 801 } catch (XAException e) { 803 String error = 804 "Cannot send res.rollback:" 805 + e 806 + " (error code = " 807 + e.errorCode 808 + ") --" 809 + e.getMessage(); 810 TraceTm.jotm.error( 811 "Got XAException from res.rollback: "+ error); 812 } 814 } else { 815 if (TraceTm.jta.isDebugEnabled()) { 816 TraceTm.jta.debug("xid= " + xid); 817 TraceTm.jta.debug("myjavaxxid= " + myjavaxxid); 818 TraceTm.jta.debug("prepared with resource= " + res); 819 } 820 821 try { 822 switch (res.prepare(myjavaxxid)) { 823 case XAResource.XA_OK : 825 log.addResource(res,xid); 826 ret = VOTE_COMMIT; 827 break; 828 case XAResource.XA_RDONLY : 829 break; 830 } 831 } catch (XAException e) { 832 String error = 833 "Cannot send res.prepare:" 834 + e 835 + " (error code = " 836 + e.errorCode 837 + ") --" 838 + e.getMessage(); 839 TraceTm.jotm.error( 840 "Got XAException from res.prepare: "+ error); 841 ret = VOTE_ROLLBACK; 842 errors++; 843 } 844 } 845 } 846 847 850 switch (ret) { 851 case VOTE_READONLY : 852 Current.getCurrent().incrementCommitCounter(); 854 status = Status.STATUS_COMMITTED; 855 break; 856 case VOTE_COMMIT : 857 status = Status.STATUS_PREPARED; 858 break; 859 case VOTE_ROLLBACK : 860 status = Status.STATUS_ROLLING_BACK; 861 break; 862 } 863 864  
|