Coverage Report - org.apache.ojb.odmg.JTATxManager
 
Classes in this File Line Coverage Branch Coverage Complexity
JTATxManager
N/A
N/A
4.125
JTATxManager$TxBuffer
N/A
N/A
4.125
 
 1  
 package org.apache.ojb.odmg;
 2  
 
 3  
 /* Copyright 2002-2005 The Apache Software Foundation
 4  
  *
 5  
  * Licensed under the Apache License, Version 2.0 (the "License");
 6  
  * you may not use this file except in compliance with the License.
 7  
  * You may obtain a copy of the License at
 8  
  *
 9  
  *     http://www.apache.org/licenses/LICENSE-2.0
 10  
  *
 11  
  * Unless required by applicable law or agreed to in writing, software
 12  
  * distributed under the License is distributed on an "AS IS" BASIS,
 13  
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 14  
  * See the License for the specific language governing permissions and
 15  
  * limitations under the License.
 16  
  */
 17  
 
 18  
 import org.apache.ojb.broker.OJBRuntimeException;
 19  
 import org.apache.ojb.broker.util.configuration.Configuration;
 20  
 import org.apache.ojb.broker.util.logging.Logger;
 21  
 import org.apache.ojb.broker.util.logging.LoggerFactory;
 22  
 import org.apache.ojb.broker.transaction.tm.TransactionManagerFactoryException;
 23  
 import org.apache.ojb.broker.transaction.tm.TransactionManagerFactoryFactory;
 24  
 import org.apache.commons.lang.SystemUtils;
 25  
 import org.odmg.TransactionNotInProgressException;
 26  
 
 27  
 import javax.transaction.Status;
 28  
 import javax.transaction.SystemException;
 29  
 import javax.transaction.Transaction;
 30  
 import javax.transaction.TransactionManager;
 31  
 import java.lang.ref.WeakReference;
 32  
 
 33  
 /**
 34  
  * @author <a href="mailto:mattbaird@yahoo.com">Matthew Baird</a>
 35  
  *
 36  
  * In an app server environment, where we have a transaction manager, we
 37  
  * use the transactionmanager and it's associated JTA transaction to associate
 38  
  * with the ODMG transaction. So the key is retrieved by calling getTransaction
 39  
  * on the transactionManager
 40  
  */
 41  
 public class JTATxManager implements OJBTxManager
 42  
 {
 43  
     private Logger log = LoggerFactory.getLogger(JTATxManager.class);
 44  
     private static ThreadLocal txRepository = new ThreadLocal();
 45  
 
 46  
     /**
 47  
      * Remove the ODMG transaction from the transaction buffer
 48  
      * ODMG transactions are associated with JTA transactions via a map
 49  
      */
 50  
     public void deregisterTx(Object transaction)
 51  
     {
 52  
 //        TxBuffer buf = (TxBuffer) txRepository.get();
 53  
 //        if (buf != null)
 54  
 //        {
 55  
 //            buf.setInternTx(null);
 56  
 //        }
 57  
         txRepository.set(null);
 58  
     }
 59  
 
 60  
     public void registerTx(TransactionImpl odmgTrans)
 61  
     {
 62  
         if (log.isDebugEnabled()) log.debug("registerSynchronization was called");
 63  
         Transaction transaction = null;
 64  
         try
 65  
         {
 66  
             transaction = getJTATransaction();
 67  
         }
 68  
         catch (SystemException e)
 69  
         {
 70  
             log.error("Obtain current transaction from container failed", e);
 71  
         }
 72  
         if (transaction == null)
 73  
         {
 74  
             log.error("Cannot get the external transaction from the external TM");
 75  
             throw new TransactionNotInProgressException("No external transaction found");
 76  
         }
 77  
         if (log.isDebugEnabled())
 78  
         {
 79  
             log.debug("registerSynchronization was called with parameters"
 80  
                     + SystemUtils.LINE_SEPARATOR +"J2EETransactionImpl: " + odmgTrans
 81  
                     + SystemUtils.LINE_SEPARATOR + "Transaction: " + transaction);
 82  
         }
 83  
         registerSynchronization(odmgTrans, transaction);
 84  
     }
 85  
 
 86  
     /**
 87  
      * Do synchronization of the given J2EE ODMG Transaction
 88  
      */
 89  
     private void registerSynchronization(TransactionImpl odmgTrans, Transaction transaction)
 90  
     {
 91  
         // todo only need for development
 92  
         if (odmgTrans == null || transaction == null)
 93  
         {
 94  
             log.error("One of the given parameters was null --> cannot do synchronization!" +
 95  
                     " omdg transaction was null: " + (odmgTrans == null) +
 96  
                     ", external transaction was null: " + (transaction == null));
 97  
             return;
 98  
         }
 99  
 
 100  
         int status = -1; // default status.
 101  
         try
 102  
         {
 103  
             status = transaction.getStatus();
 104  
             if (status != Status.STATUS_ACTIVE)
 105  
             {
 106  
                 throw new OJBRuntimeException(
 107  
                         "Transaction synchronization failed - wrong status of external container tx: " +
 108  
                         getStatusString(status));
 109  
             }
 110  
         }
 111  
         catch (SystemException e)
 112  
         {
 113  
             throw new OJBRuntimeException("Can't read status of external tx", e);
 114  
         }
 115  
 
 116  
         try
 117  
         {
 118  
             //Sequence of the following method calls is significant
 119  
             // 1. register the synchronization with the ODMG notion of a transaction.
 120  
             transaction.registerSynchronization((J2EETransactionImpl) odmgTrans);
 121  
             // 2. mark the ODMG transaction as being in a JTA Transaction
 122  
             // Associate external transaction with the odmg transaction.
 123  
             txRepository.set(new TxBuffer(odmgTrans, transaction));
 124  
         }
 125  
         catch (Exception e)
 126  
         {
 127  
             log.error("Cannot associate PersistenceBroker with running Transaction", e);
 128  
             throw new OJBRuntimeException(
 129  
                     "Transaction synchronization failed - wrong status of external container tx", e);
 130  
         }
 131  
     }
 132  
 
 133  
     private static String getStatusString(int status)
 134  
     {
 135  
         switch (status)
 136  
         {
 137  
             case Status.STATUS_ACTIVE:
 138  
                 return "STATUS_ACTIVE";
 139  
             case Status.STATUS_COMMITTED:
 140  
                 return "STATUS_COMMITTED";
 141  
             case Status.STATUS_COMMITTING:
 142  
                 return "STATUS_COMMITTING";
 143  
             case Status.STATUS_MARKED_ROLLBACK:
 144  
                 return "STATUS_MARKED_ROLLBACK";
 145  
             case Status.STATUS_NO_TRANSACTION:
 146  
                 return "STATUS_NO_TRANSACTION";
 147  
             case Status.STATUS_PREPARED:
 148  
                 return "STATUS_PREPARED";
 149  
             case Status.STATUS_PREPARING:
 150  
                 return "STATUS_PREPARING";
 151  
             case Status.STATUS_ROLLEDBACK:
 152  
                 return "STATUS_ROLLEDBACK";
 153  
             case Status.STATUS_ROLLING_BACK:
 154  
                 return "STATUS_ROLLING_BACK";
 155  
             case Status.STATUS_UNKNOWN:
 156  
                 return "STATUS_UNKNOWN";
 157  
             default:
 158  
                 return "NO STATUS FOUND";
 159  
         }
 160  
     }
 161  
 
 162  
     /**
 163  
      * Return the TransactionManager of the external app
 164  
      */
 165  
     private TransactionManager getTransactionManager()
 166  
     {
 167  
         TransactionManager retval = null;
 168  
         try
 169  
         {
 170  
             if (log.isDebugEnabled()) log.debug("getTransactionManager called");
 171  
             retval = TransactionManagerFactoryFactory.instance().getTransactionManager();
 172  
         }
 173  
         catch (TransactionManagerFactoryException e)
 174  
         {
 175  
             log.warn("Exception trying to obtain TransactionManager from Factory", e);
 176  
             e.printStackTrace();
 177  
         }
 178  
         return retval;
 179  
     }
 180  
 
 181  
     public Transaction getJTATransaction() throws SystemException
 182  
     {
 183  
         if (log.isDebugEnabled()) log.debug("getTransaction called");
 184  
         if (getTransactionManager() == null)
 185  
         {
 186  
             log.warn("TransactionManager was null");
 187  
             return null;
 188  
         }
 189  
         return getTransactionManager().getTransaction();
 190  
     }
 191  
 
 192  
     /**
 193  
      * Returns the current transaction based on the JTA Transaction.
 194  
      * @throws org.odmg.TransactionNotInProgressException if no transaction was found.
 195  
      */
 196  
     public TransactionImpl getCurrentTransaction()
 197  
     {
 198  
         TransactionImpl retval = getTransaction();
 199  
         if (null == retval)
 200  
         {
 201  
             throw new TransactionNotInProgressException(
 202  
                     "Calling method needed transaction, but no transaction found via TransactionManager");
 203  
         }
 204  
         return retval;
 205  
     }
 206  
 
 207  
     /**
 208  
      * Returns the current transaction based on the JTA Transaction or <code>null</code>
 209  
      * if no transaction was found.
 210  
      */
 211  
     public TransactionImpl getTransaction()
 212  
     {
 213  
         TxBuffer buf = (TxBuffer) txRepository.get();
 214  
         return buf != null ? buf.getInternTx() : null;
 215  
     }
 216  
 
 217  
     /**
 218  
      * Abort an active extern transaction associated with the given PB.
 219  
      */
 220  
     public void abortExternalTx(TransactionImpl odmgTrans)
 221  
     {
 222  
         if (log.isDebugEnabled()) log.debug("abortExternTransaction was called");
 223  
         if (odmgTrans == null) return;
 224  
         TxBuffer buf = (TxBuffer) txRepository.get();
 225  
         Transaction extTx = buf != null ? buf.getExternTx() : null;
 226  
         try
 227  
         {
 228  
             if (extTx != null && extTx.getStatus() == Status.STATUS_ACTIVE)
 229  
             {
 230  
                 if(log.isDebugEnabled())
 231  
                 {
 232  
                     log.debug("Set extern transaction to rollback");
 233  
                 }
 234  
                 extTx.setRollbackOnly();
 235  
             }
 236  
         }
 237  
         catch (Exception ignore)
 238  
         {
 239  
         }
 240  
         txRepository.set(null);
 241  
     }
 242  
 
 243  
     public void configure(Configuration config)
 244  
     {
 245  
         /**
 246  
          * no-op
 247  
          */
 248  
     }
 249  
 
 250  
 
 251  
     //************************************************************************
 252  
     // inner class
 253  
     //************************************************************************
 254  
     private static final class TxBuffer
 255  
     {
 256  
         private WeakReference externTx = null;
 257  
         private WeakReference internTx = null;
 258  
 
 259  
         public TxBuffer()
 260  
         {
 261  
         }
 262  
 
 263  
         /*
 264  
         arminw:
 265  
         use WeakReference to make sure that closed Transaction objects can be
 266  
         immediately reclaimed by the garbage collector.
 267  
         */
 268  
 
 269  
         public TxBuffer(TransactionImpl internTx, Transaction externTx)
 270  
         {
 271  
             this.internTx = new WeakReference(internTx);
 272  
             this.externTx = new WeakReference(externTx);
 273  
         }
 274  
 
 275  
         public Transaction getExternTx()
 276  
         {
 277  
             return (Transaction) externTx.get();
 278  
         }
 279  
 
 280  
         public void setExternTx(Transaction externTx)
 281  
         {
 282  
             this.externTx = new WeakReference(externTx);
 283  
         }
 284  
 
 285  
         public TransactionImpl getInternTx()
 286  
         {
 287  
             return (TransactionImpl) internTx.get();
 288  
         }
 289  
 
 290  
         public void setInternTx(TransactionImpl internTx)
 291  
         {
 292  
             this.internTx = new WeakReference(internTx);
 293  
         }
 294  
     }
 295  
 }