You are viewing a plain text version of this content. The canonical link for it is here.
Posted to slide-dev@jakarta.apache.org by re...@apache.org on 2001/05/11 05:40:25 UTC

cvs commit: jakarta-slide/src/share/org/apache/slide/transaction SlideTransaction.java SlideTransactionManager.java

remm        01/05/10 20:40:25

  Modified:    src/share/org/apache/slide/transaction SlideTransaction.java
                        SlideTransactionManager.java
  Log:
  - Cleaner handling of status codes + remove entries in the timeout hashtable.
  
    Patch submitted by Erik Olof Stenflo <eRiK at cairnTechnologies.com>
  
  Additional comments by Erik :
  
  I consider the changes to SlideTransactionManager
  a fix to a potential memory problem....
  the Hashtable "timeouts" could have potentially
  grown to be very large, since it's elements were
  never removed upon a commit or rollback.
  
  The changes to SlideTransaction are such, that the
  getStatus() method will now return
  Status.STATUS_MARKED_ROLLBACK when the transaction
  is marked for rollback.
  
  Revision  Changes    Path
  1.9       +116 -123  jakarta-slide/src/share/org/apache/slide/transaction/SlideTransaction.java
  
  Index: SlideTransaction.java
  ===================================================================
  RCS file: /home/cvs/jakarta-slide/src/share/org/apache/slide/transaction/SlideTransaction.java,v
  retrieving revision 1.8
  retrieving revision 1.9
  diff -u -r1.8 -r1.9
  --- SlideTransaction.java	2001/02/12 04:39:58	1.8
  +++ SlideTransaction.java	2001/05/11 03:40:23	1.9
  @@ -1,7 +1,7 @@
   /*
  - * $Header: /home/cvs/jakarta-slide/src/share/org/apache/slide/transaction/SlideTransaction.java,v 1.8 2001/02/12 04:39:58 remm Exp $
  - * $Revision: 1.8 $
  - * $Date: 2001/02/12 04:39:58 $
  + * $Header: /home/cvs/jakarta-slide/src/share/org/apache/slide/transaction/SlideTransaction.java,v 1.9 2001/05/11 03:40:23 remm Exp $
  + * $Revision: 1.9 $
  + * $Date: 2001/05/11 03:40:23 $
    *
    * ====================================================================
    *
  @@ -86,14 +86,14 @@
    * JTA Transaction implementation.
    *
    * @author <a href="mailto:remm@apache.org">Remy Maucherat</a>
  - * @version $Revision: 1.8 $
  + * @version $Revision: 1.9 $
    */
   public final class SlideTransaction implements Transaction {
  -    
  -    
  +
  +
       // ------------------------------------------------------------ Constructor
  -    
  -    
  +
  +
       /**
        * Constructor.
        */
  @@ -107,92 +107,86 @@
                 + currentTransactionNumber).getBytes(),
                0, new byte[0]);
       }
  -    
  -    
  +
  +
       // ----------------------------------------------------- Instance Variables
  -    
  -    
  +
  +
       /**
        * Global transaction id.
        */
       private SlideXid xid;
  -    
  -    
  +
  +
       /**
        * Branches.
        * Keyed : branch xid -> resource manager.
        */
       private Hashtable branches = new Hashtable();
  -    
  -    
  +
  +
       /**
        * Active branches.
        * Keyed : resource manager -> branches xid.
        */
       private Hashtable activeBranches = new Hashtable();
  -    
  -    
  +
  +
       /**
        * Enlisted resources.
        */
       private Vector enlistedResources = new Vector();
  -    
  -    
  +
  +
       /**
        * Suspended resources.
        * Keyed : resource manager -> branches xid.
        */
       private Hashtable suspendedResources = new Hashtable();
  -    
  -    
  +
  +
       /**
        * Transaction status.
        */
       private int status = Status.STATUS_ACTIVE;
  -    
  -    
  -    /**
  -     * Rollback only.
  -     */
  -    private boolean rollbackOnly = false;
  -    
  -    
  +
  +
       /**
        * Synchronization objects.
        */
       private Vector synchronizationObjects = new Vector();
  -    
  -    
  +
  +
       /**
        * Branch counter.
        */
       private int branchCounter = 1;
  -    
  -    
  +
  +
       /**
        * Number of transactions created.
        */
       private static int globalCreatedTransactions = 0;
  -    
  -    
  +
  +
       /**
        * Transaction number.
        */
       private int currentTransactionNumber = 0;
  -    
  -    
  +
  +
       /**
        * Name of the thread bound to the transaction.
        */
       private String currentThreadName = null;
  -    
  -    
  +
  +
       // ------------------------------------------------------------- Properties
  -    
  -    
  +
  +
       // ---------------------------------------------------- Transaction Methods
  -    
  -    
  +
  +
       /**
        * Complete the transaction represented by this Transaction object.
        *
  @@ -217,31 +211,31 @@
           SystemException {
   
   //System.out.println(this + "  COMMIT ");
  -            
  -        
  -        // Check status ACTIVE
  -        if (status != Status.STATUS_ACTIVE)
  -            throw new IllegalStateException();
  -        
  -        if (rollbackOnly) {
  +
  +
  +        if (status == Status.STATUS_MARKED_ROLLBACK) {
               rollback();
               return;
           }
  -        
  +
  +        // Check status ACTIVE
  +        if (status != Status.STATUS_ACTIVE)
  +            throw new IllegalStateException();
  +
           // Call synchronized objects beforeCompletion
           Enumeration syncList = synchronizationObjects.elements();
           while (syncList.hasMoreElements()) {
               Synchronization sync = (Synchronization) syncList.nextElement();
               sync.beforeCompletion();
           }
  -        
  +
           Vector exceptions = new Vector();
           boolean fail = false;
  -        
  +
           Enumeration enum = branches.keys();
  -        
  +
           if (enlistedResources.size() == 1) {
  -            
  +
               // One phase commit
               status = Status.STATUS_COMMITTING;
               while (enum.hasMoreElements()) {
  @@ -267,9 +261,9 @@
               } else {
                   status = Status.STATUS_ROLLEDBACK;
               }
  -            
  +
           } else if (enlistedResources.size() != 0) {
  -            
  +
               // Prepare each enlisted resource
               status = Status.STATUS_PREPARING;
               while ((!fail) && (enum.hasMoreElements())) {
  @@ -287,10 +281,10 @@
                       status = Status.STATUS_MARKED_ROLLBACK;
                   }
               }
  -            
  +
               if (!fail)
                   status = Status.STATUS_PREPARED;
  -            
  +
               // If fail, rollback
               if (fail) {
                   status = Status.STATUS_ROLLING_BACK;
  @@ -326,9 +320,9 @@
                   }
                   status = Status.STATUS_COMMITTED;
               }
  -            
  +
           }
  -        
  +
           // Call synchronized objects afterCompletion
           syncList = synchronizationObjects.elements();
           while (syncList.hasMoreElements()) {
  @@ -336,7 +330,7 @@
                   (Synchronization) syncList.nextElement();
               sync.afterCompletion(status);
           }
  -        
  +
           // Parsing exception and throwing an appropriate exception
           enum = exceptions.elements();
           if (enum.hasMoreElements()) {
  @@ -347,10 +341,10 @@
               if ((status == Status.STATUS_COMMITTED) && (fail))
                   throw new HeuristicMixedException();
           }
  -        
  +
       }
  -    
  -    
  +
  +
       /**
        * Delist the resource specified from the current transaction associated
        * with the calling thread.
  @@ -366,42 +360,42 @@
           throws IllegalStateException, SystemException {
   
   //System.out.println(this + "  DELIST " + xaRes);
  -        
  +
           // Check status ACTIVE
           if (status != Status.STATUS_ACTIVE)
               throw new IllegalStateException();
  -        
  +
           Xid xid = (Xid) activeBranches.get(xaRes);
  -        
  +
           if (xid == null)
               throw new IllegalStateException();
  -        
  +
           activeBranches.remove(xaRes);
  -        
  +
           XAException exception = null;
  -        
  +
           try {
               xaRes.end(xid, flag);
           } catch (XAException e) {
               exception = e;
           }
  -        
  +
           if (exception != null) {
               // FIXME
   System.out.println("Delistment failed(" + this + ") = " + xaRes + " xid: " + xid);
               return false;
           }
  -        
  +
           if (flag == XAResource.TMSUSPEND)
               suspendedResources.put(xaRes, xid);
  -        
  +
   //System.out.println("Delisted ok(" + this + ") = " + xaRes + " xid: " + xid);
  -        
  +
           return true;
  -        
  +
       }
  -    
  -    
  +
  +
       /**
        * Enlist the resource specified with the current transaction context of
        * the calling thread.
  @@ -419,26 +413,25 @@
           throws RollbackException, IllegalStateException, SystemException {
   
   //System.out.println(this + "  ENLIST " + xaRes);
  -            
  -        
  +
  +        if (status == Status.STATUS_MARKED_ROLLBACK)
  +            throw new RollbackException();
  +
           // Check status ACTIVE
           if (status != Status.STATUS_ACTIVE)
               throw new IllegalStateException();
  -        
  -        if (rollbackOnly)
  -            throw new RollbackException();
  -        
  +
           // Preventing two branches from being active at the same time on the
           // same resource manager
           Xid activeXid = (Xid) activeBranches.get(xaRes);
           if (activeXid != null)
               return false;
  -        
  +
           boolean alreadyEnlisted = false;
           int flag = XAResource.TMNOFLAGS;
  -        
  +
           Xid branchXid = (Xid) suspendedResources.get(xaRes);
  -        
  +
           if (branchXid == null) {
               Enumeration enum = enlistedResources.elements();
               while ((!alreadyEnlisted) && (enum.hasMoreElements())) {
  @@ -454,34 +447,34 @@
               branchXid = this.xid.newBranch(branchCounter++);
   
   //System.out.println(this + "  Creating new branch for " + xaRes);
  -            
  +
           } else {
               alreadyEnlisted = true;
               flag = XAResource.TMRESUME;
               suspendedResources.remove(xaRes);
           }
  -        
  +
           if (!alreadyEnlisted) {
               enlistedResources.addElement(xaRes);
           }
  -        
  +
           try {
   //System.out.println("Starting(" + this + ") = " + xaRes + " Branch: " + branchXid + " Flag: " + flag);
  -            
  +
               xaRes.start(branchXid, flag);
           } catch (XAException e) {
   System.out.println("Enlist error(" + this + ") = " + e.errorCode + "  " + xaRes+ " Branch: " + branchXid + " Flag: " + flag);
               return false;
           }
  -        
  +
           branches.put(branchXid, xaRes);
           activeBranches.put(xaRes, branchXid);
  -        
  +
           return true;
  -        
  +
       }
  -    
  -    
  +
  +
       /**
        * Roll back the transaction associated with the current thread. When
        * this method completes, the thread becomes associated with no
  @@ -496,17 +489,17 @@
        */
       public void rollback()
           throws SecurityException, IllegalStateException, SystemException {
  -        
  +
   //System.out.println(this + "  ROLLBACK ");
  -        
  +
           // Check status ACTIVE
  -        if (status != Status.STATUS_ACTIVE)
  +        if (status != Status.STATUS_ACTIVE && status != Status.STATUS_MARKED_ROLLBACK)
               throw new IllegalStateException();
  -        
  +
           Vector exceptions = new Vector();
  -        
  +
           Enumeration enum = branches.keys();
  -        
  +
           status = Status.STATUS_ROLLING_BACK;
           while (enum.hasMoreElements()) {
               Xid xid = (Xid) enum.nextElement();
  @@ -518,10 +511,10 @@
               }
           }
           status = Status.STATUS_ROLLEDBACK;
  -        
  +
       }
  -    
  -    
  +
  +
       /**
        * Modify the transaction associated with the current thread such that
        * the only possible outcome of the transaction is to roll back the
  @@ -534,10 +527,10 @@
        */
       public void setRollbackOnly()
           throws IllegalStateException, SystemException {
  -        rollbackOnly = true;
  +        status = Status.STATUS_MARKED_ROLLBACK;
       }
  -    
  -    
  +
  +
       /**
        * Obtain the status of the transaction associated with the current thread.
        *
  @@ -550,8 +543,8 @@
           throws SystemException {
           return status;
       }
  -    
  -    
  +
  +
       /**
        * Register a synchronization object for the transaction currently
        * associated with the calling thread. The transction manager invokes the
  @@ -570,21 +563,21 @@
        */
       public void registerSynchronization(Synchronization sync)
           throws RollbackException, IllegalStateException, SystemException {
  -        
  -        if (rollbackOnly)
  +
  +        if (status == Status.STATUS_MARKED_ROLLBACK)
               throw new RollbackException();
  -        
  -        if (getStatus() != Status.STATUS_ACTIVE)
  +
  +        if (status != Status.STATUS_ACTIVE)
               throw new IllegalStateException();
  -        
  +
           synchronizationObjects.addElement(sync);
  -        
  +
       }
  -    
  -    
  +
  +
       // --------------------------------------------------------- Public Methods
  -    
  -    
  +
  +
       /**
        * Print the Transaction object in a debugger friendly manner
        */
  @@ -594,8 +587,8 @@
               (currentThreadName.equals(Thread.currentThread().getName())?"":
                " current= " + Thread.currentThread().getName());
       }
  -    
  -    
  +
  +
   }
   
   
  
  
  
  1.3       +133 -126  jakarta-slide/src/share/org/apache/slide/transaction/SlideTransactionManager.java
  
  Index: SlideTransactionManager.java
  ===================================================================
  RCS file: /home/cvs/jakarta-slide/src/share/org/apache/slide/transaction/SlideTransactionManager.java,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- SlideTransactionManager.java	2001/02/12 04:39:59	1.2
  +++ SlideTransactionManager.java	2001/05/11 03:40:24	1.3
  @@ -1,13 +1,13 @@
   /*
  - * $Header: /home/cvs/jakarta-slide/src/share/org/apache/slide/transaction/SlideTransactionManager.java,v 1.2 2001/02/12 04:39:59 remm Exp $
  - * $Revision: 1.2 $
  - * $Date: 2001/02/12 04:39:59 $
  + * $Header: /home/cvs/jakarta-slide/src/share/org/apache/slide/transaction/SlideTransactionManager.java,v 1.3 2001/05/11 03:40:24 remm Exp $
  + * $Revision: 1.3 $
  + * $Date: 2001/05/11 03:40:24 $
    *
    * ====================================================================
    *
    * The Apache Software License, Version 1.1
    *
  - * Copyright (c) 1999 The Apache Software Foundation.  All rights 
  + * Copyright (c) 1999 The Apache Software Foundation.  All rights
    * reserved.
    *
    * Redistribution and use in source and binary forms, with or without
  @@ -15,7 +15,7 @@
    * are met:
    *
    * 1. Redistributions of source code must retain the above copyright
  - *    notice, this list of conditions and the following disclaimer. 
  + *    notice, this list of conditions and the following disclaimer.
    *
    * 2. Redistributions in binary form must reproduce the above copyright
    *    notice, this list of conditions and the following disclaimer in
  @@ -23,15 +23,15 @@
    *    distribution.
    *
    * 3. The end-user documentation included with the redistribution, if
  - *    any, must include the following acknowlegement:  
  - *       "This product includes software developed by the 
  + *    any, must include the following acknowlegement:
  + *       "This product includes software developed by the
    *        Apache Software Foundation (http://www.apache.org/)."
    *    Alternately, this acknowlegement may appear in the software itself,
    *    if and wherever such third-party acknowlegements normally appear.
    *
    * 4. The names "The Jakarta Project", "Tomcat", and "Apache Software
    *    Foundation" must not be used to endorse or promote products derived
  - *    from this software without prior written permission. For written 
  + *    from this software without prior written permission. For written
    *    permission, please contact apache@apache.org.
    *
    * 5. Products derived from this software may not be called "Apache"
  @@ -59,7 +59,7 @@
    *
    * [Additional notices, if required by prior licensing conditions]
    *
  - */ 
  + */
   
   package org.apache.slide.transaction;
   
  @@ -85,176 +85,180 @@
    * <li>Does not support nested transactions</li>
    * <li>No security</li>
    * </ul>
  - * 
  + *
    * @author <a href="mailto:remm@apache.org">Remy Maucherat</a>
  - * @version $Revision: 1.2 $
  + * @version $Revision: 1.3 $
    */
   public final class SlideTransactionManager implements TransactionManager {
  -    
  -    
  +
  +
       // -------------------------------------------------------------- Constants
  -    
  -    
  +
  +
       public static final int DEFAULT_TRANSACTION_TIMEOUT = 30;
  -    
  -    
  +
  +
       // ------------------------------------------------------------ Constructor
  -    
  -    
  +
  +
       // ----------------------------------------------------- Instance Variables
  -    
  -    
  +
  +
       /**
        * Transaction bindings thread id <-> transaction object.
        */
       private Hashtable bindings = new Hashtable();
  -    
  -    
  +
  +
       /**
        * Transaction bindings thread id <-> transaction timeout.
        */
       private Hashtable timeouts = new Hashtable();
  -    
  -    
  +
  +
       // ------------------------------------------------------------- Properties
  -    
  -    
  +
  +
       // --------------------------------------------------------- Public Methods
  -    
  -    
  +
  +
       // --------------------------------------------- TransactionManager Methods
  -    
  -    
  +
  +
       /**
        * Create a new transaction and associate it with the current thread.
  -     * 
  -     * @exception NotSupportedException Thrown if the thread is already 
  -     * associated with a transaction and the Transaction Manager 
  +     *
  +     * @exception NotSupportedException Thrown if the thread is already
  +     * associated with a transaction and the Transaction Manager
        * implementation does not support nested transactions.
        * @exception SystemException Thrown if the transaction manager encounters
        * an unexpected error condition.
        */
       public void begin()
           throws NotSupportedException, SystemException {
  -        
  +
           Transaction currentTransaction = getTransaction();
           if (currentTransaction != null)
               throw new NotSupportedException();
  -        
  +
           currentTransaction = new SlideTransaction();
           bindings.put(Thread.currentThread(), currentTransaction);
  -        
  +
       }
  -    
  -    
  +
  +
       /**
  -     * Complete the transaction associated with the current thread. When this 
  +     * Complete the transaction associated with the current thread. When this
        * method completes, the thread becomes associated with no transaction.
  -     * 
  -     * @exception RollbackException Thrown to indicate that the transaction 
  +     *
  +     * @exception RollbackException Thrown to indicate that the transaction
        * has been rolled back rather than committed.
  -     * @exception HeuristicMixedException Thrown to indicate that a heuristic 
  -     * decision was made and that some relevant updates have been committed 
  +     * @exception HeuristicMixedException Thrown to indicate that a heuristic
  +     * decision was made and that some relevant updates have been committed
        * while others have been rolled back.
  -     * @exception HeuristicRollbackException Thrown to indicate that a 
  -     * heuristic decision was made and that some relevant updates have been 
  +     * @exception HeuristicRollbackException Thrown to indicate that a
  +     * heuristic decision was made and that some relevant updates have been
        * rolled back.
  -     * @exception SecurityException Thrown to indicate that the thread is not 
  +     * @exception SecurityException Thrown to indicate that the thread is not
        * allowed to commit the transaction.
  -     * @exception IllegalStateException Thrown if the current thread is not 
  +     * @exception IllegalStateException Thrown if the current thread is not
        * associated with a transaction.
        * @exception SystemException Thrown if the transaction manager encounters
        * an unexpected error condition.
        */
       public void commit()
  -        throws RollbackException, HeuristicMixedException, 
  +        throws RollbackException, HeuristicMixedException,
           HeuristicRollbackException, SecurityException, IllegalStateException,
           SystemException {
  -        
  -        Transaction currentTransaction = getTransaction();
  +
  +        Thread currentThread = Thread.currentThread();
  +        Transaction currentTransaction = 
  +            (Transaction) bindings.remove(currentThread);
           if (currentTransaction == null)
               throw new IllegalStateException();
  -        
  -        bindings.remove(Thread.currentThread());
  -        
  +
  +        timeouts.remove(currentThread);
  +
           currentTransaction.commit();
  -        
  +
       }
  -    
  -    
  +
  +
       /**
  -     * Roll back the transaction associated with the current thread. When 
  -     * this method completes, the thread becomes associated with no 
  +     * Roll back the transaction associated with the current thread. When
  +     * this method completes, the thread becomes associated with no
        * transaction.
  -     * 
  -     * @exception SecurityException Thrown to indicate that the thread is not 
  +     *
  +     * @exception SecurityException Thrown to indicate that the thread is not
        * allowed to commit the transaction.
  -     * @exception IllegalStateException Thrown if the current thread is not 
  +     * @exception IllegalStateException Thrown if the current thread is not
        * associated with a transaction.
        * @exception SystemException Thrown if the transaction manager encounters
        * an unexpected error condition.
        */
       public void rollback()
           throws SecurityException, IllegalStateException, SystemException {
  -        
  -        Transaction currentTransaction = getTransaction();
  +
  +        Thread currentThread = Thread.currentThread();
  +        Transaction currentTransaction = 
  +            (Transaction) bindings.remove(currentThread);
           if (currentTransaction == null)
               throw new IllegalStateException();
  -        
  -        bindings.remove(Thread.currentThread());
  -        
  +
  +        timeouts.remove(currentThread);
  +
           currentTransaction.rollback();
  -        
  +
       }
  -    
  -    
  +
  +
       /**
  -     * Modify the transaction associated with the current thread such that 
  -     * the only possible outcome of the transaction is to roll back the 
  +     * Modify the transaction associated with the current thread such that
  +     * the only possible outcome of the transaction is to roll back the
        * transaction.
  -     * 
  -     * @exception IllegalStateException Thrown if the current thread is not 
  +     *
  +     * @exception IllegalStateException Thrown if the current thread is not
        * associated with a transaction.
        * @exception SystemException Thrown if the transaction manager encounters
        * an unexpected error condition.
        */
       public void setRollbackOnly()
           throws IllegalStateException, SystemException {
  -        
  +
           Transaction currentTransaction = getTransaction();
           if (currentTransaction == null)
               throw new IllegalStateException();
  -        
  +
           currentTransaction.setRollbackOnly();
  -        
  +
       }
  -    
  -    
  +
  +
       /**
        * Obtain the status of the transaction associated with the current thread.
  -     * 
  +     *
        * @exception SystemException Thrown if the transaction manager encounters
        * an unexpected error condition.
  -     * @return The transaction status. If no transaction is associated with 
  +     * @return The transaction status. If no transaction is associated with
        * the current thread, this method returns the Status.NoTransaction value.
        */
       public int getStatus()
           throws SystemException {
  -        
  +
           Transaction currentTransaction = getTransaction();
           if (currentTransaction == null)
               return Status.STATUS_NO_TRANSACTION;
  -        
  +
           return currentTransaction.getStatus();
  -        
  +
       }
  -    
  -    
  +
  +
       /**
  -     * Get the transaction object that represents the transaction context of 
  +     * Get the transaction object that represents the transaction context of
        * the calling thread.
  -     * 
  -     * @return the Transaction object representing the transaction associated 
  +     *
  +     * @return the Transaction object representing the transaction associated
        * with the calling thread.
        * @exception SystemException Thrown if the transaction manager encounters
        * an unexpected error condition.
  @@ -263,19 +267,19 @@
           throws SystemException {
           return (Transaction) bindings.get(Thread.currentThread());
       }
  -    
  -    
  +
  +
       /**
  -     * Resume the transaction context association of the calling thread with 
  -     * the transaction represented by the supplied Transaction object. When 
  -     * this method returns, the calling thread is associated with the 
  +     * Resume the transaction context association of the calling thread with
  +     * the transaction represented by the supplied Transaction object. When
  +     * this method returns, the calling thread is associated with the
        * transaction context specified.
  -     * 
  -     * @param tobj The Transaction object that represents the transaction to 
  +     *
  +     * @param tobj The Transaction object that represents the transaction to
        * be resumed.
  -     * @exception InvalidTransactionException Thrown if the parameter 
  +     * @exception InvalidTransactionException Thrown if the parameter
        * transaction object contains an invalid transaction.
  -     * @exception IllegalStateException Thrown if the thread is already 
  +     * @exception IllegalStateException Thrown if the thread is already
        * associated with another transaction.
        * @exception SystemException Thrown if the transaction manager encounters
        * an unexpected error condition.
  @@ -283,60 +287,63 @@
       public void resume(Transaction tobj)
           throws InvalidTransactionException, IllegalStateException,
           SystemException {
  -        
  +
           if (getTransaction() != null)
               throw new IllegalStateException();
  -        
  +
           if (tobj == null)
               throw new InvalidTransactionException();
  -        
  +
           bindings.put(Thread.currentThread(), tobj);
  -        
  +
       }
  -    
  -    
  +
  +
       /**
  -     * Suspend the transaction currently associated with the calling thread 
  -     * and return a Transaction object that represents the transaction 
  -     * context being suspended. If the calling thread is not associated with 
  -     * a transaction, the method returns a null object reference. When this 
  +     * Suspend the transaction currently associated with the calling thread
  +     * and return a Transaction object that represents the transaction
  +     * context being suspended. If the calling thread is not associated with
  +     * a transaction, the method returns a null object reference. When this
        * method returns, the calling thread is associated with no transaction.
  -     * 
  +     *
        * @return Transaction object representing the suspended transaction.
        * @exception SystemException Thrown if the transaction manager encounters
        * an unexpected error condition.
        */
       public Transaction suspend()
           throws SystemException {
  -        
  +
           Transaction currentTransaction = getTransaction();
  -        
  -        if (currentTransaction != null)
  -            bindings.remove(Thread.currentThread());
  -        
  +
  +        if (currentTransaction != null) {
  +			Thread currentThread = Thread.currentThread();
  +            bindings.remove(currentThread);
  +            timeouts.remove(currentThread);
  +        }
  +
           return currentTransaction;
  -        
  +
       }
  -    
  -    
  +
  +
       /**
  -     * Modify the value of the timeout value that is associated with the 
  -     * transactions started by the current thread with the begin method. 
  +     * Modify the value of the timeout value that is associated with the
  +     * transactions started by the current thread with the begin method.
        * <p>
  -     * If an application has not called this method, the transaction service 
  +     * If an application has not called this method, the transaction service
        * uses some default value for the transaction timeout.
  -     * 
  -     * @param seconds The value of the timeout in seconds. If the value is 
  +     *
  +     * @param seconds The value of the timeout in seconds. If the value is
        * zero, the transaction service restores the default value.
        * @exception SystemException Thrown if the transaction manager encounters
        * an unexpected error condition.
        */
       public void setTransactionTimeout(int seconds)
           throws SystemException {
  -        
  +
           timeouts.put(Thread.currentThread(), new Integer(seconds));
  -        
  +
       }
  -    
  -    
  +
  +
   }