Coverage Report - org.apache.ojb.odmg.J2EETransactionImpl
 
Classes in this File Line Coverage Branch Coverage Complexity
J2EETransactionImpl
N/A
N/A
4
 
 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 javax.transaction.Status;
 19  
 import javax.transaction.Synchronization;
 20  
 
 21  
 import org.apache.ojb.broker.PersistenceBroker;
 22  
 import org.apache.ojb.broker.accesslayer.ConnectionManagerIF;
 23  
 import org.apache.ojb.broker.util.logging.Logger;
 24  
 import org.apache.ojb.broker.util.logging.LoggerFactory;
 25  
 import org.odmg.LockNotGrantedException;
 26  
 import org.odmg.ODMGRuntimeException;
 27  
 import org.odmg.TransactionAbortedException;
 28  
 
 29  
 /**
 30  
  * Implementation for use in managed environments.
 31  
  *
 32  
  * @author <a href="mailto:mattbaird@yahoo.com">Matthew Baird</a>
 33  
  * @version $Id: J2EETransactionImpl.java,v 1.1 2007-08-24 22:17:37 ewestfal Exp $
 34  
  */
 35  
 public class J2EETransactionImpl extends TransactionImpl implements Synchronization
 36  
 {
 37  
     private Logger log = LoggerFactory.getLogger(J2EETransactionImpl.class);
 38  
     private boolean isInExternTransaction;
 39  
 
 40  
     /**
 41  
      * beforeCompletion is being called twice in JBoss, so this
 42  
      * isPrepared flag prevents code from executing twice.
 43  
      * todo: find out why it's being called twice and fix it.
 44  
      */
 45  
     private boolean beforeCompletionCall = false;
 46  
     private boolean afterCompletionCall = false;
 47  
 
 48  
     public J2EETransactionImpl(ImplementationImpl implementation)
 49  
     {
 50  
         super(implementation);
 51  
         isInExternTransaction = false;
 52  
     }
 53  
 
 54  
     public void setInExternTransaction(boolean mode)
 55  
     {
 56  
         isInExternTransaction = mode;
 57  
         }
 58  
 
 59  
     public boolean isInExternTransaction()
 60  
     {
 61  
         return isInExternTransaction;
 62  
     }
 63  
 
 64  
     public void join()
 65  
     {
 66  
             throw new UnsupportedOperationException("Not supported in managed enviroment");
 67  
         }
 68  
 
 69  
     public void leave()
 70  
     {
 71  
             throw new UnsupportedOperationException("Not supported in managed enviroment");
 72  
         }
 73  
 
 74  
     public void checkpoint()
 75  
     {
 76  
             throw new UnsupportedOperationException("Not supported in managed enviroment");
 77  
         }
 78  
 
 79  
     /**
 80  
      * FOR internal use. This method was called after the external transaction was completed.
 81  
      *
 82  
      * @see javax.transaction.Synchronization
 83  
      */
 84  
     public void afterCompletion(int status)
 85  
     {
 86  
         if(afterCompletionCall) return;
 87  
 
 88  
         log.info("Method afterCompletion was called");
 89  
         try
 90  
         {
 91  
             switch(status)
 92  
             {
 93  
                 case Status.STATUS_COMMITTED:
 94  
                     if(log.isDebugEnabled())
 95  
                     {
 96  
                         log.debug("Method afterCompletion: Do commit internal odmg-tx, status of JTA-tx is " + TxUtil.getStatusString(status));
 97  
                     }
 98  
                     commit();
 99  
                     break;
 100  
                 default:
 101  
                     log.error("Method afterCompletion: Do abort call on internal odmg-tx, status of JTA-tx is " + TxUtil.getStatusString(status));
 102  
                     abort();
 103  
             }
 104  
         }
 105  
         finally
 106  
         {
 107  
             afterCompletionCall = true;
 108  
             log.info("Method afterCompletion finished");
 109  
         }
 110  
     }
 111  
 
 112  
     /**
 113  
      * FOR internal use. This method was called before the external transaction was completed.
 114  
      *
 115  
      * This method was called by the JTA-TxManager before the JTA-tx prepare call. Within this method
 116  
      * we prepare odmg for commit and pass all modified persistent objects to DB and release/close the used
 117  
      * connection. We have to close the connection in this method, because the TxManager does prepare for commit
 118  
      * after this method and all used DataSource-connections have to be closed before.
 119  
      *
 120  
      * @see javax.transaction.Synchronization
 121  
      */
 122  
     public void beforeCompletion()
 123  
     {
 124  
         // avoid redundant calls
 125  
         if(beforeCompletionCall) return;
 126  
 
 127  
         log.info("Method beforeCompletion was called");
 128  
         int status = Status.STATUS_UNKNOWN;
 129  
         try
 130  
         {
 131  
             JTATxManager mgr = (JTATxManager) getImplementation().getTxManager();
 132  
             status = mgr.getJTATransaction().getStatus();
 133  
             // ensure proper work, check all possible status
 134  
             // normally only check for 'STATUS_MARKED_ROLLBACK' is necessary
 135  
             if(status == Status.STATUS_MARKED_ROLLBACK
 136  
                     || status == Status.STATUS_ROLLEDBACK
 137  
                     || status == Status.STATUS_ROLLING_BACK
 138  
                     || status == Status.STATUS_UNKNOWN
 139  
                     || status == Status.STATUS_NO_TRANSACTION)
 140  
             {
 141  
                 log.error("Synchronization#beforeCompletion: Can't prepare for commit, because tx status was "
 142  
                         + TxUtil.getStatusString(status) + ". Do internal cleanup only.");
 143  
             }
 144  
             else
 145  
             {
 146  
                 if(log.isDebugEnabled())
 147  
                 {
 148  
                     log.debug("Synchronization#beforeCompletion: Prepare for commit");
 149  
                 }
 150  
                 // write objects to database
 151  
                 prepareCommit();
 152  
             }
 153  
         }
 154  
         catch(Exception e)
 155  
         {
 156  
             log.error("Synchronization#beforeCompletion: Error while prepare for commit", e);
 157  
             if(e instanceof LockNotGrantedException)
 158  
             {
 159  
                 throw (LockNotGrantedException) e;
 160  
             }
 161  
             else if(e instanceof TransactionAbortedException)
 162  
             {
 163  
                 throw (TransactionAbortedException) e;
 164  
             }
 165  
             else if(e instanceof ODMGRuntimeException)
 166  
             {
 167  
                 throw (ODMGRuntimeException) e;
 168  
             }
 169  
             else
 170  
             { 
 171  
                 throw new ODMGRuntimeException("Method beforeCompletion() fails, status of JTA-tx was "
 172  
                         + TxUtil.getStatusString(status) + ", message: " + e.getMessage());
 173  
             }
 174  
 
 175  
         }
 176  
         finally
 177  
         {
 178  
             beforeCompletionCall = true;
 179  
             setInExternTransaction(false);
 180  
             internalCleanup();
 181  
         }
 182  
     }
 183  
 
 184  
     /**
 185  
      * In managed environment do internal close the used connection
 186  
      */
 187  
     private void internalCleanup()
 188  
     {
 189  
         if(hasBroker())
 190  
         {
 191  
             PersistenceBroker broker = getBroker();
 192  
             if(log.isDebugEnabled())
 193  
             {
 194  
                 log.debug("Do internal cleanup and close the internal used connection without" +
 195  
                         " closing the used broker");
 196  
             }
 197  
             ConnectionManagerIF cm = broker.serviceConnectionManager();
 198  
             if(cm.isInLocalTransaction())
 199  
             {
 200  
                 /*
 201  
                 arminw:
 202  
                 in managed environment this call will be ignored because, the JTA transaction
 203  
                 manager control the connection status. But to make connectionManager happy we
 204  
                 have to complete the "local tx" of the connectionManager before release the
 205  
                 connection
 206  
                 */
 207  
                 cm.localCommit();
 208  
             }
 209  
             cm.releaseConnection();
 210  
         }
 211  
     }
 212  
 
 213  
     public void commit()
 214  
     {
 215  
         try
 216  
         {
 217  
             // prepare for commit was done before on 'beforeCompleation' call
 218  
             if(log.isDebugEnabled()) log.debug("Commit transaction " + this + ", commit on broker " + broker);
 219  
             if(hasBroker())
 220  
             {
 221  
                 getBroker().commitTransaction();
 222  
                 doClose();
 223  
             }
 224  
             setStatus(Status.STATUS_COMMITTED);
 225  
             // Now, we notify everything the commit is done.
 226  
             performTransactionAwareAfterCommit();
 227  
         }
 228  
         catch(Exception ex)
 229  
         {
 230  
             // We should not reach this block
 231  
             log.error("Unexpected error while do commit on used PB-Instance and close resources", ex);
 232  
             abort();
 233  
         }
 234  
     }
 235  
 
 236  
     public void abort()
 237  
     {
 238  
         if(getStatus() == Status.STATUS_ROLLEDBACK) return;
 239  
 
 240  
         try
 241  
         {
 242  
             try
 243  
             {
 244  
                 doAbort();
 245  
             }
 246  
             catch(Exception ignore)
 247  
             {
 248  
                 log.error("Failure while do abort call", ignore);
 249  
             }
 250  
 
 251  
             getImplementation().getTxManager().abortExternalTx(this);
 252  
 
 253  
             try
 254  
             {
 255  
                 doClose();
 256  
             }
 257  
             catch(Exception e)
 258  
             {
 259  
                 log.error("Failure while do abort call", e);
 260  
             }
 261  
             setStatus(Status.STATUS_ROLLEDBACK);
 262  
         }
 263  
         finally
 264  
         {
 265  
             setInExternTransaction(false);
 266  
         }
 267  
     }
 268  
 }