| 1 49 package org.objectweb.jotm; 50 51 import java.io.Serializable ; 52 import java.util.Collections ; 53 import java.util.Date ; 54 import java.util.EmptyStackException ; 55 import java.util.HashMap ; 56 import java.util.Iterator ; 57 import java.util.List ; 58 import java.util.Map ; 59 import java.util.Set ; 60 import java.util.Stack ; 61 import java.util.Vector ; 62 63 import javax.naming.NamingException ; 64 import javax.naming.Reference ; 65 import javax.naming.Referenceable ; 66 import javax.naming.StringRefAddr ; 67 import javax.resource.spi.XATerminator ; 68 import javax.transaction.HeuristicMixedException ; 69 import javax.transaction.HeuristicRollbackException ; 70 import javax.transaction.InvalidTransactionException ; 71 import javax.transaction.NotSupportedException ; 72 import javax.transaction.RollbackException ; 73 import javax.transaction.Status ; 74 import javax.transaction.SystemException ; 75 import javax.transaction.Transaction ; 76 import javax.transaction.UserTransaction ; 77 import javax.transaction.xa.XAException ; 78 import javax.transaction.xa.XAResource ; 79 80 import org.objectweb.transaction.jta.ResourceManagerEvent; 81 import org.objectweb.transaction.jta.TransactionManager; 82 import org.objectweb.howl.log.xa.XACommittingTx; 83 84 100 101 public class Current implements UserTransaction , TransactionManager, Referenceable , Serializable { 102 103 private transient static ThreadLocal threadTx = new ThreadLocal (); 106 107 111 private transient static Map txXids = Collections.synchronizedMap(new HashMap ()); 113 114 private transient static Current unique = null; 116 117 private transient static TimerManager timermgr = null; private transient static TransactionFactory tm = null; private transient static TransactionRecovery tr = null; 122 private static final String JOTM_VERSION = "JOTM 2.0.10"; 123 private static final int DEFAULT_TIMEOUT = 60; 124 private int defaultTimeout = DEFAULT_TIMEOUT; 125 private int transactionTimeout = DEFAULT_TIMEOUT; 126 private static final boolean DEFAULT_RECOVERY = false; 127 private static boolean transactionRecovery = DEFAULT_RECOVERY; 128 129 private transient int nb_bg_tx = 0; 131 private transient int nb_rb_tx = 0; 132 private transient int nb_cm_tx = 0; 133 private transient int nb_to = 0; 134 135 139 143 144 public Current(){ 145 TraceTm.jta.info(JOTM_VERSION); 146 147 if (TraceTm.jta.isDebugEnabled()) { 148 TraceTm.jta.debug("no args constructor"); 149 } 150 151 unique = this; 152 timermgr = TimerManager.getInstance(); 153 154 try { 155 tr = new TransactionRecoveryImpl (); 156 } catch (Exception e) { 157 setDefaultRecovery(false); 158 TraceTm.recovery.error("Cannot open Howl Log"); 159 TraceTm.recovery.error("JOTM Recovery is being disabled"); 160 } 161 } 162 163 171 172 public Current(TransactionFactory tmfact){ 173 TraceTm.jta.info(JOTM_VERSION); 174 175 if (TraceTm.jta.isDebugEnabled()) { 176 TraceTm.jta.debug("TransactionFactory="+ tmfact); 177 } 178 179 unique = this; 180 tm = tmfact; 181 182 timermgr = TimerManager.getInstance(); 183 184 try { 185 tr = new TransactionRecoveryImpl (); 186 } catch (Exception e) { 187 setDefaultRecovery(false); 188 TraceTm.recovery.error("Cannot open Howl Log"); 189 TraceTm.recovery.error("JOTM Recovery is being disabled"); 190 } 191 } 192 193 198 199 public static TransactionManager getTransactionManager() { 200 return (TransactionManager) unique; 201 } 202 203 207 217 218 public void begin() throws NotSupportedException , SystemException { 219 220 if (TraceTm.jta.isDebugEnabled()) { 221 TraceTm.jta.debug("begin transaction"); 222 } 223 224 TransactionImpl tx = (TransactionImpl) threadTx.get(); 226 227 if (TraceTm.jta.isDebugEnabled()) { 228 TraceTm.jta.debug("threadTx.get= " + threadTx.toString()); 229 } 230 231 if (tx != null) { 232 if (txXids.containsValue(tx)) { 233 throw new NotSupportedException ("Nested transactions not supported"); 234 } else { 235 if (TraceTm.jta.isDebugEnabled()) { 236 TraceTm.jta.debug("Resetting current tx = " + tx + " since it is already completed."); 237 } 238 } 239 } 240 241 XidImpl otid = new XidImpl(); 244 245 tx = new TransactionImpl(otid, transactionTimeout); 248 249 if (TraceTm.jta.isDebugEnabled()) { 250 TraceTm.jta.debug("tx=" + tx); 251 } 252 253 try { 255 tx.doAttach(XAResource.TMJOIN); 256 } catch (RollbackException e) { 257 TraceTm.jotm.error("doAttach: RollbackException"); 259 throw new SystemException ("RollbackException in occured in begin() " + e.getMessage()); 260 } 261 262 threadTx.set(tx); 264 265 if (TraceTm.jta.isDebugEnabled()) { 266 TraceTm.jta.debug("threadTx.set= " + threadTx.toString()); 267 } 268 269 putTxXid(otid, tx); 271 272 if (timermgr != null) { 274 tx.setTimer(timermgr.addTimer(tx, transactionTimeout, null, false)); 275 } 276 277 Date myDate = new Date (); 279 tx.setTxDate(myDate.toString()); 280 281 Stack curStack = (Stack ) eventListStack.get(); 284 285 if (curStack != null) { 287 try { 288 List list = (List ) curStack.peek(); 289 290 if (list != null) { 291 292 for (Iterator it = list.iterator(); it.hasNext();) { 293 ((ResourceManagerEvent) it.next()).enlistConnection(tx); 294 } 295 } else { 296 297 if (TraceTm.jta.isDebugEnabled()) { 298 TraceTm.jta.debug("Current.begin called with null list"); 299 } 300 } 301 } catch (EmptyStackException e) { 302 if (TraceTm.jta.isDebugEnabled()) { 303 TraceTm.jta.debug("Current.begin called with empty stack"); 304 } 305 } 306 } 307 } 308 309 313 325 326 public void begin(javax.transaction.xa.Xid passxid) throws NotSupportedException , SystemException { 327 begin(passxid, (long) transactionTimeout); 328 } 329 330 345 346 public void begin(javax.transaction.xa.Xid passxid, long timeout) throws NotSupportedException , SystemException { 347 348 if (TraceTm.jta.isDebugEnabled()) { 349 TraceTm.jta.debug("begin inflow transaction, timeout = " + timeout); 350 } 351 352 if (timeout <= 0) { 353 timeout = defaultTimeout; 354 } 355 356 TransactionImpl tx = (TransactionImpl) threadTx.get(); 358 359 if (TraceTm.jta.isDebugEnabled()) { 360 TraceTm.jta.debug("threadTx.get= " + threadTx.toString()); 361 } 362 363 if (tx != null) { 364 if (txXids.containsValue(tx)) { 365 throw new NotSupportedException ("Nested transactions not supported"); 366 } else { 367 if (TraceTm.jta.isDebugEnabled()) { 368 TraceTm.jta.debug("Resetting current tx = " + tx + " since it is already completed."); 369 } 370 } 371 } 372 373 XidImpl pxid = new XidImpl(passxid); 375 376 tx = new TransactionImpl(pxid, (int) timeout); 379 380 if (TraceTm.jta.isDebugEnabled()) { 381 TraceTm.jta.debug("tx=" + tx); 382 } 383 384 threadTx.set(tx); 386 387 if (TraceTm.jta.isDebugEnabled()) { 388 TraceTm.jta.debug("threadTx.set= " + threadTx.toString()); 389 } 390 391 putTxXid(pxid, tx); 393 394 if (timermgr != null) { 396 tx.setTimer(timermgr.addTimer(tx, (int) timeout, null, false)); 397 } 398 399 Date myDate = new Date (); 401 tx.setTxDate(myDate.toString()); 402 } 403 404 416 417 public XATerminator getXATerminator() throws XAException { 418 419 XATerminator xaterm = null; 420 421 try { 422 xaterm = new XATerminatorImpl(); 423 } catch (XAException e) { 424 if (TraceTm.jta.isDebugEnabled()) { 425 TraceTm.jta.debug("Cannot create XATerminatorImpl"+ e); 426 } 427 } 428 429 return xaterm; 430 } 431 432 436 437 461 462 public void commit() 463 throws 464 RollbackException , 465 HeuristicMixedException , 466 HeuristicRollbackException , 467 SecurityException , 468 IllegalStateException , 469 SystemException { 470 471 if (TraceTm.jta.isDebugEnabled()) { 472 TraceTm.jta.debug("commit transaction "); 473 } 474 475 TransactionImpl tx = (TransactionImpl) getTransaction(); 477 478 if (tx == null) { 479 throw new IllegalStateException ("Cannot get Transaction for commit"); 480 } 481 482 if (TraceTm.jta.isDebugEnabled()) { 483 TraceTm.jta.debug("tx=" + tx); 484 } 485 486 try { 488 tx.commit(); 489 } finally { 490 threadTx.set(null); 494 495 transactionTimeout = defaultTimeout; 497 498 if (TraceTm.jta.isDebugEnabled()) { 499 TraceTm.jta.debug("threadTx.set= null"); 500 TraceTm.jta.debug("reset timeout= " + defaultTimeout); 501 } 502 } 503 } 504 505 518 public void rollback() throws IllegalStateException , SecurityException , SystemException { 519 520 if (TraceTm.jta.isDebugEnabled()) { 521 TraceTm.jta.debug("Current.rollback()"); 522 } 523 524 TransactionImpl tx = (TransactionImpl) getTransaction(); 526 527 if (tx == null) { 528 throw new IllegalStateException ("Cannot get Transaction for rollback"); 529 } 530 531 threadTx.set(null); 532 533 if (TraceTm.jta.isDebugEnabled()) { 534 TraceTm.jta.debug("threadTx.set= null"); 535 } 536 537 tx.rollback(); 539 540 if (TraceTm.jta.isDebugEnabled()) { 541 TraceTm.jta.debug("reset timeout= " + defaultTimeout); 542 } 543 544 transactionTimeout = defaultTimeout; 545 546 } 547 548 558 559 public void setRollbackOnly() throws IllegalStateException , SystemException { 560 561 if (TraceTm.jta.isDebugEnabled()) { 562 TraceTm.jta.debug("Current.setRollbackOnly()"); 563 } 564 TransactionImpl tx = (TransactionImpl) getTransaction(); 566 567 if (tx == null) { 568 throw new IllegalStateException ("Cannot get Transaction for setRollbackOnly"); 569 } 570 571 tx.setRollbackOnly(); 573 } 574 575 585 586 public int getStatus() throws SystemException { 587 588 if (TraceTm.jta.isDebugEnabled()) { 589 TraceTm.jta.debug("Current.getStatus()"); 590 } 591 592 TransactionImpl tx = (TransactionImpl) getTransaction(); 594 595 if (tx == null) { 596 return Status.STATUS_NO_TRANSACTION; 597 } 598 599 return tx.getStatus(); 601 } 602 603 616 617 public void setTransactionTimeout(int timeout) throws SystemException { 618 619 if (TraceTm.jta.isDebugEnabled()) { 620 TraceTm.jta.debug("timeout= "+ timeout); 621 } 622 623 627 TransactionImpl tx = (TransactionImpl) threadTx.get(); 628 629 if (tx != null) { 630 if (txXids.containsValue(tx)) { 631 if (TraceTm.jta.isDebugEnabled()) { 632 TraceTm.jta.debug("Cannot reset transaction timeout, tx in execution"); 633 } 634 return; 636 } 637 } 638 639 if (timeout > 0) { 640 transactionTimeout = timeout; 641 } else { 642 transactionTimeout = defaultTimeout; 643 } 644 645 if (TraceTm.jta.isDebugEnabled()) { 646 TraceTm.jta.debug("Resetting transaction timeout= " + transactionTimeout); 647 } 648 } 649 650 663 664 public void setTransactionRecovery(boolean recovery) throws SystemException { 665 666 if (TraceTm.recovery.isDebugEnabled()) { 667 TraceTm.recovery.debug("recovery="+ recovery); 668 } 669 670 if (recovery) { 671 transactionRecovery = recovery; 672 } else { 673 transactionRecovery = DEFAULT_RECOVERY; 674 } 675 } 676 677 682 694 695 public Transaction getTransaction() throws SystemException { 696 Transaction ret = (Transaction ) threadTx.get(); 697 698 if (TraceTm.jta.isDebugEnabled()) { 699 TraceTm.jta.debug("threadTx.get= " + threadTx.toString()); 700 TraceTm.jta.debug("Transaction ret= " + ret); 701 } 702 703 return ret; 704 } 705 706 732 733 public void resume(Transaction tobj) throws InvalidTransactionException , IllegalStateException , SystemException { 734 735 if (TraceTm.jta.isDebugEnabled()) { 736 TraceTm.jta.debug("resume transaction"); 737 } 738 739 if (tobj == null) { 741 TraceTm.jotm.error("resume: null arg."); 742 throw new InvalidTransactionException ("resume(null) is not valid"); 743 } 744 745 if (TraceTm.jta.isDebugEnabled()) { 746 TraceTm.jta.debug("tx="+ tobj); 747 } 748 749 Transaction mytx = (Transaction ) threadTx.get(); 751 752 if (TraceTm.jta.isDebugEnabled()) { 753 TraceTm.jta.debug("threadTx.get= " + threadTx.toString()); 754 } 755 756 if (mytx != null) { 757 if (mytx.equals(tobj)) { 758 if (TraceTm.jta.isDebugEnabled()) { 759 TraceTm.jta.debug("nothing to do"); 760 } 761 return; 762 } 763 TraceTm.jotm.error("resume: already associated with another transaction."); 764 throw new IllegalStateException ("the thread is already associated with another transaction."); 765 } 766 767 if (!(tobj instanceof TransactionImpl)) { 769 TraceTm.jotm.error("resume: non TransactionImpl arg."); 770 throw new InvalidTransactionException ("resume(" + tobj.getClass().getName() + ") is not valid"); 771 } 772 773 threadTx.set(tobj); 775 776 if (TraceTm.jta.isDebugEnabled()) { 777 TraceTm.jta.debug("threadTx.set= " + threadTx.toString()); 778 } 779 780 try { 782 ((TransactionImpl) tobj).doAttach(XAResource.TMRESUME); 783 } catch (RollbackException e) { 784 TraceTm.jotm.error("RollbackException occured in resume()"); 786 throw new SystemException ("RollbackException in occured in resume() " + e.getMessage()); 787 } 788 } 789 790 815 816 public Transaction suspend() throws SystemException { 817 818 if (TraceTm.jta.isDebugEnabled()) { 819 TraceTm.jta.debug("suspend transaction"); 820 } 821 822 TransactionImpl tx = (TransactionImpl) threadTx.get(); 824 825 if (TraceTm.jta.isDebugEnabled()) { 826 TraceTm.jta.debug("threadTx.get= " + threadTx.toString()); 827 } 828 829 if (tx != null) { 830 831 if (TraceTm.jta.isDebugEnabled()) { 832 TraceTm.jta.debug("tx="+ tx); 833 } 834 835 tx.doDetach(XAResource.TMSUSPEND); 836 threadTx.set(null); 837 838 if (TraceTm.jta.isDebugEnabled()) { 839 TraceTm.jta.debug("threadTx.set= null"); 840 } 841 } 842 843 return tx; 844 } 845 846 851 854 855 public void connectionOpened(ResourceManagerEvent event) { 856 857 if (TraceTm.jta.isDebugEnabled()) { 858 TraceTm.jta.debug("Current.connectionOpened " + this); 859 } 860 861 List list = null; 862 Stack curStack = (Stack ) eventListStack.get(); 863 865 if (curStack == null) { 866 eventListStack.set(curStack = new Stack ()); 868 } else { try { 870 list = (List ) curStack.pop(); 871 } catch (EmptyStackException e) { 872 } 874 } 875 876 if (list == null) 878 list = new Vector (1); 879 880 list.add(event); 882 883 |