Coverage report

  %line %branch
org.apache.jetspeed.components.rdbms.ojb.ConnectionManagerImpl
0% 
0% 

 1  
 package org.apache.jetspeed.components.rdbms.ojb;
 2  
 
 3  
 /* 
 4  
  * Licensed to the Apache Software Foundation (ASF) under one or more
 5  
  * contributor license agreements.  See the NOTICE file distributed with
 6  
  * this work for additional information regarding copyright ownership.
 7  
  * The ASF licenses this file to You under the Apache License, Version 2.0
 8  
  * (the "License"); you may not use this file except in compliance with
 9  
  * the License.  You may obtain a copy of the License at
 10  
  *
 11  
  *     http://www.apache.org/licenses/LICENSE-2.0
 12  
  *
 13  
  * Unless required by applicable law or agreed to in writing, software
 14  
  * distributed under the License is distributed on an "AS IS" BASIS,
 15  
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 16  
  * See the License for the specific language governing permissions and
 17  
  * limitations under the License.
 18  
  */
 19  
 
 20  
 import java.sql.Connection;
 21  
 import java.sql.SQLException;
 22  
 import java.util.Collections;
 23  
 import java.util.HashMap;
 24  
 import java.util.Map;
 25  
 
 26  
 import org.apache.ojb.broker.OJBRuntimeException;
 27  
 import org.apache.ojb.broker.PBKey;
 28  
 import org.apache.ojb.broker.PersistenceBroker;
 29  
 import org.apache.ojb.broker.PersistenceBrokerException;
 30  
 import org.apache.ojb.broker.TransactionAbortedException;
 31  
 import org.apache.ojb.broker.TransactionInProgressException;
 32  
 import org.apache.ojb.broker.TransactionNotInProgressException;
 33  
 import org.apache.ojb.broker.accesslayer.ConnectionFactory;
 34  
 import org.apache.ojb.broker.accesslayer.ConnectionFactoryFactory;
 35  
 import org.apache.ojb.broker.accesslayer.ConnectionManagerIF;
 36  
 import org.apache.ojb.broker.accesslayer.LookupException;
 37  
 import org.apache.ojb.broker.accesslayer.OJBBatchUpdateException;
 38  
 import org.apache.ojb.broker.metadata.ConnectionPoolDescriptor;
 39  
 import org.apache.ojb.broker.metadata.JdbcConnectionDescriptor;
 40  
 import org.apache.ojb.broker.metadata.MetadataManager;
 41  
 import org.apache.ojb.broker.platforms.Platform;
 42  
 import org.apache.ojb.broker.platforms.PlatformFactory;
 43  
 import org.apache.ojb.broker.util.ClassHelper;
 44  
 import org.apache.ojb.broker.util.batch.BatchConnection;
 45  
 import org.apache.ojb.broker.util.logging.Logger;
 46  
 import org.apache.ojb.broker.util.logging.LoggerFactory;
 47  
 
 48  
 /**
 49  
  * Manages Connection ressources. This class is a replacement for the default
 50  
  * ConnectionManagerImpl that comes with OJB. It differs from this class only
 51  
  * in its way to get a connection factory. The default OJB class always uses
 52  
  * the class configured in OJB.properties. This implementation looks up the
 53  
  * factory configured for the given JCD first and uses the default factory
 54  
  * class only if no class is configured in the JCD.
 55  
  *
 56  
  * @see ConnectionManagerIF
 57  
  * @author Thomas Mahler
 58  
  * @version $Id$
 59  
  */
 60  
 public class ConnectionManagerImpl implements ConnectionManagerIF
 61  
 {
 62  
     // We cannot derive from OBJ's ConnectionManagerIF because member
 63  
     // variables are private
 64  
     
 65  0
     private Logger log = LoggerFactory.getLogger(ConnectionManagerImpl.class);
 66  
 
 67  0
     private PersistenceBroker broker = null;
 68  
     private ConnectionFactory connectionFactory;
 69  
     private JdbcConnectionDescriptor jcd;
 70  
     private Platform platform;
 71  0
     private Connection con = null;
 72  
     private PBKey pbKey;
 73  
     private boolean originalAutoCommitState;
 74  
     private boolean isInLocalTransaction;
 75  
     private boolean batchMode;
 76  0
     private BatchConnection batchCon = null;
 77  
 
 78  0
     private static Map connectionFactories = Collections.synchronizedMap(new HashMap());
 79  
     
 80  
     public ConnectionManagerImpl(PersistenceBroker broker)
 81  0
     {
 82  0
         this.broker = broker;
 83  0
         this.pbKey = broker.getPBKey();
 84  0
         this.jcd = MetadataManager.getInstance().connectionRepository().getDescriptor(pbKey);        
 85  0
         ConnectionPoolDescriptor cpd = jcd.getConnectionPoolDescriptor();        
 86  0
         if (cpd != null && cpd.getConnectionFactory() != class="keyword">null)
 87  
         {
 88  0
             connectionFactory = (ConnectionFactory)connectionFactories.get(cpd.getConnectionFactory());
 89  0
             if ( connectionFactory == null )
 90  
             {
 91  
                 try
 92  
                 {
 93  0
                     if (Boolean.valueOf(this.jcd.getAttribute("org.apache.jetspeed.engineScoped", "false")).booleanValue()) {
 94  0
                         ClassLoader cl = Thread.currentThread().getContextClassLoader();                
 95  
                         try
 96  
                         {
 97  0
                             Thread.currentThread().setContextClassLoader(this.getClass().getClassLoader());
 98  0
                             connectionFactory = (ConnectionFactory)
 99  
                                 ClassHelper.newInstance (cpd.getConnectionFactory(), true);
 100  0
                             connectionFactories.put(cpd.getConnectionFactory(), connectionFactory);
 101  
                         }
 102  
                         finally
 103  
                         {
 104  0
                             Thread.currentThread().setContextClassLoader(cl);
 105  0
                             connectionFactories.put(cpd.getConnectionFactory(), connectionFactory);
 106  0
                         }
 107  0
                     }
 108  
                     else
 109  
                     {
 110  0
                         connectionFactory = (ConnectionFactory)
 111  
                         ClassHelper.newInstance (cpd.getConnectionFactory(), true);
 112  
                     }
 113  
                 }
 114  0
                 catch (InstantiationException e)
 115  
                 {
 116  0
                     String err = "Can't instantiate class " + cpd.getConnectionFactory();
 117  0
                     log.error(err, e);
 118  0
                     throw (IllegalStateException)(new IllegalStateException(err)).initCause(e);
 119  
                 }
 120  0
                 catch (IllegalAccessException e)
 121  
                 {
 122  0
                     String err = "Can't instantiate class " + cpd.getConnectionFactory();
 123  0
                     log.error(err, e);
 124  0
                     throw (IllegalStateException)(new IllegalStateException(err)).initCause(e);
 125  0
                 }
 126  
             }
 127  
         }
 128  
         else 
 129  
         {                
 130  0
             this.connectionFactory = ConnectionFactoryFactory.getInstance().createConnectionFactory();
 131  
         }
 132  0
         this.platform = PlatformFactory.getPlatformFor(jcd);
 133  
         /*
 134  
         by default batch mode is not enabled and after use of a PB
 135  
         instance, before instance was returned to pool, batch mode
 136  
         was set to false again (PB implementation close method)
 137  
         Be carefully in modify this behaviour, changes could cause
 138  
         unexpected behaviour
 139  
         */
 140  0
         setBatchMode(false);
 141  0
     }
 142  
 
 143  
     /**
 144  
      * Returns the associated {@link org.apache.ojb.broker.metadata.JdbcConnectionDescriptor}
 145  
      */
 146  
     public JdbcConnectionDescriptor getConnectionDescriptor()
 147  
     {
 148  0
         return jcd;
 149  
     }
 150  
 
 151  
     public Platform getSupportedPlatform()
 152  
     {
 153  0
         return this.platform;
 154  
     }
 155  
 
 156  
     /**
 157  
      * Returns the underlying connection, requested from
 158  
      * {@link org.apache.ojb.broker.accesslayer.ConnectionFactory}.
 159  
      * <p>
 160  
      * PB#beginTransaction() opens a single jdbc connection via
 161  
 	 * PB#serviceConnectionManager().localBegin().
 162  
 	 * If you call PB#serviceConnectionManager().getConnection() later
 163  
 	 * it returns the already opened connection.
 164  
 	 * The PB instance will release the used connection during
 165  
 	 * PB#commitTransaction() or PB#abortTransaction() or PB#close().
 166  
      * </p>
 167  
      * <p>
 168  
      * NOTE: Never call Connection.close() on the connection requested from the ConnectionManager.
 169  
      * Cleanup of used connection is done by OJB itself. If you need to release a used connection
 170  
      * call {@link #releaseConnection()}.
 171  
      * </p>
 172  
      */
 173  
     public Connection getConnection() throws LookupException
 174  
     {
 175  
         /*
 176  
         if the connection is not null and we are not in a local tx, we check
 177  
         the connection state and release "dead" connections.
 178  
         if connection is in local tx we do nothing, the dead connection will cause
 179  
         an exception and PB instance have to handle rollback
 180  
         */
 181  0
         if(con != null && !isInLocalTransaction() && !isAlive(con))
 182  
         {
 183  0
             releaseConnection();
 184  
         }
 185  0
         if (con == null)
 186  
         {
 187  0
             if (Boolean.valueOf(this.jcd.getAttribute("org.apache.jetspeed.engineScoped", "false")).booleanValue()) {
 188  0
                 ClassLoader cl = Thread.currentThread().getContextClassLoader();
 189  
                 try
 190  
                 {
 191  0
                     Thread.currentThread().setContextClassLoader(this.getClass().getClassLoader());
 192  0
                     con = this.connectionFactory.lookupConnection(jcd);
 193  
                 }
 194  
                 finally
 195  
                 {
 196  0
                     Thread.currentThread().setContextClassLoader(cl);
 197  0
                 }
 198  0
             }
 199  
             else
 200  
             {
 201  0
                 con = this.connectionFactory.lookupConnection(jcd);
 202  
             }
 203  
             
 204  0
             if (con == null) throw new PersistenceBrokerException("Cannot get connection for " + jcd);
 205  0
             if (jcd.getUseAutoCommit() == JdbcConnectionDescriptor.AUTO_COMMIT_SET_TRUE_AND_TEMPORARY_FALSE)
 206  
             {
 207  
                 try
 208  
                 {
 209  0
                     this.originalAutoCommitState = con.getAutoCommit();
 210  
                 }
 211  0
                 catch (SQLException e)
 212  
                 {
 213  0
                     throw new PersistenceBrokerException("Cannot request autoCommit state on the connection", e);
 214  0
                 }
 215  
             }
 216  0
             if (log.isDebugEnabled()) log.debug("Request new connection from ConnectionFactory: " + con);
 217  
         }
 218  
 
 219  0
         if (isBatchMode())
 220  
         {
 221  0
             if (batchCon == null)
 222  
             {
 223  0
                 batchCon = new BatchConnection(con, broker);
 224  
             }
 225  0
             return batchCon;
 226  
         }
 227  
         else
 228  
         {
 229  0
             return con;
 230  
         }
 231  
     }
 232  
 
 233  
     /**
 234  
      * Start transaction on the underlying connection.
 235  
      */
 236  
     public void localBegin()
 237  
     {
 238  0
         if (this.isInLocalTransaction)
 239  
         {
 240  0
             throw new TransactionInProgressException("Connection is already in transaction");
 241  
         }
 242  0
         Connection connection = null;
 243  
         try
 244  
         {
 245  0
             connection = this.getConnection();
 246  
         }
 247  0
         catch (LookupException e)
 248  
         {
 249  
             /**
 250  
              * must throw to notify user that we couldn't start a connection
 251  
              */
 252  0
             throw new PersistenceBrokerException("Can't lookup a connection", e);
 253  0
         }
 254  0
         if (log.isDebugEnabled()) log.debug("localBegin was called for con " + connection);
 255  0
         if (jcd.getUseAutoCommit() == JdbcConnectionDescriptor.AUTO_COMMIT_SET_TRUE_AND_TEMPORARY_FALSE)
 256  
         {
 257  0
             if (log.isDebugEnabled()) log.debug("Try to change autoCommit state to 'false'");
 258  0
             platform.changeAutoCommitState(jcd, connection, false);
 259  
         }
 260  0
         this.isInLocalTransaction = true;
 261  0
     }
 262  
 
 263  
     /**
 264  
      * Call commit on the underlying connection.
 265  
      */
 266  
     public void localCommit()
 267  
     {
 268  0
         if (log.isDebugEnabled()) log.debug("commit was called");
 269  0
         if (!this.isInLocalTransaction)
 270  
         {
 271  0
             throw new TransactionNotInProgressException("Not in transaction, call begin() before commit()");
 272  
         }
 273  
         try
 274  
         {
 275  0
             if (batchCon != null)
 276  
             {
 277  0
                 batchCon.commit();
 278  
             }
 279  0
             else if (con != null)
 280  
             {
 281  0
                 con.commit();
 282  
             }
 283  
         }
 284  0
         catch (SQLException e)
 285  
         {
 286  0
             log.error("Commit on underlying connection failed, try to rollback connection", e);
 287  0
             this.localRollback();
 288  0
             throw new TransactionAbortedException("Commit on connection failed", e);
 289  
         }
 290  
         finally
 291  
         {
 292  0
             this.isInLocalTransaction = false;
 293  0
             restoreAutoCommitState();
 294  0
             this.releaseConnection();
 295  0
         }
 296  0
     }
 297  
 
 298  
     /**
 299  
      * Call rollback on the underlying connection.
 300  
      */
 301  
     public void localRollback()
 302  
     {
 303  0
         log.info("Rollback was called, do rollback on current connection " + con);
 304  0
         if (!this.isInLocalTransaction)
 305  
         {
 306  0
             throw new PersistenceBrokerException("Not in transaction, cannot abort");
 307  
         }
 308  
         try
 309  
         {
 310  
             //truncate the local transaction
 311  0
             this.isInLocalTransaction = false;
 312  0
             if (batchCon != null)
 313  
             {
 314  0
                 batchCon.rollback();
 315  
             }
 316  0
             else if (con != null && !con.isClosed())
 317  
             {
 318  0
                 con.rollback();
 319  
             }
 320  
         }
 321  0
         catch (SQLException e)
 322  
         {
 323  0
             log.error("Rollback on the underlying connection failed", e);
 324  
         }
 325  
         finally
 326  
         {
 327  0
             try
 328  
             {
 329  0
             	restoreAutoCommitState();
 330  
 		    }
 331  0
             catch(OJBRuntimeException ignore)
 332  
             {
 333  
 			    // Ignore or log exception
 334  0
 		    }
 335  0
             releaseConnection();
 336  0
         }
 337  0
     }
 338  
 
 339  
     /**
 340  
      * Reset autoCommit state.
 341  
      */
 342  
     protected void restoreAutoCommitState()
 343  
     {
 344  
         try
 345  
         {
 346  0
             if (jcd.getUseAutoCommit() == JdbcConnectionDescriptor.AUTO_COMMIT_SET_TRUE_AND_TEMPORARY_FALSE
 347  
                     && originalAutoCommitState == true && con != null && !con.isClosed())
 348  
             {
 349  0
                 platform.changeAutoCommitState(jcd, con, true);
 350  
             }
 351  
         }
 352  0
         catch (SQLException e)
 353  
         {
 354  
             // should never be reached
 355  0
             throw new OJBRuntimeException("Restore of connection autocommit state failed", e);
 356  0
         }
 357  0
     }
 358  
 
 359  
     /**
 360  
      * Check if underlying connection was alive.
 361  
      */
 362  
     public boolean isAlive(Connection conn)
 363  
     {
 364  
         try
 365  
         {
 366  0
             return con != null ? !con.isClosed() : false;
 367  
         }
 368  0
         catch (SQLException e)
 369  
         {
 370  0
             log.error("IsAlive check failed, running connection was invalid!!", e);
 371  0
             return false;
 372  
         }
 373  
     }
 374  
 
 375  
     public boolean isInLocalTransaction()
 376  
     {
 377  0
         return this.isInLocalTransaction;
 378  
     }
 379  
 
 380  
     /**
 381  
      * Release connection to the {@link org.apache.ojb.broker.accesslayer.ConnectionFactory}, make
 382  
      * sure that you call the method in either case, it's the only way to free the connection.
 383  
      */
 384  
     public void releaseConnection()
 385  
     {
 386  0
         if (this.con == null)
 387  
         {
 388  0
             return;
 389  
         }
 390  0
         if(isInLocalTransaction())
 391  
         {
 392  0
             log.error("Release connection: connection is in local transaction, missing 'localCommit' or" +
 393  
                     " 'localRollback' call - try to rollback the connection");
 394  0
             localRollback();
 395  
         }
 396  
         else
 397  
         {
 398  0
             this.connectionFactory.releaseConnection(class="keyword">this.jcd, class="keyword">this.con);
 399  0
             this.con = null;
 400  0
             this.batchCon = null;
 401  
         }
 402  0
     }
 403  
 
 404  
     /**
 405  
      * Returns the underlying used {@link org.apache.ojb.broker.accesslayer.ConnectionFactory}
 406  
      * implementation.
 407  
      */
 408  
     public ConnectionFactory getUnderlyingConnectionFactory()
 409  
     {
 410  0
         return connectionFactory;
 411  
     }
 412  
 
 413  
     /**
 414  
      * Sets the batch mode on or off - this
 415  
      * switch only works if you set attribute <code>batch-mode</code>
 416  
      * in <code>jdbc-connection-descriptor</code> true and your database
 417  
      * support batch mode.
 418  
      *
 419  
      * @param mode the batch mode
 420  
      */
 421  
     public void setBatchMode(boolean mode)
 422  
     {
 423  
         /*
 424  
         arminw:
 425  
         if batch mode was set 'false' in repository,
 426  
         never enable it.
 427  
         There are many users having weird problems
 428  
         when batch mode was enabled behind the scenes
 429  
         */
 430  0
         batchMode = mode && jcd.getBatchMode();
 431  0
     }
 432  
 
 433  
     /**
 434  
      * @return the batch mode.
 435  
      */
 436  
     public boolean isBatchMode()
 437  
     {
 438  0
         return batchMode && platform.supportsBatchOperations();
 439  
     }
 440  
 
 441  
     /**
 442  
      * Execute batch (if the batch mode where used).
 443  
      */
 444  
     public void executeBatch() throws OJBBatchUpdateException
 445  
     {
 446  0
         if (batchCon != null)
 447  
         {
 448  
             try
 449  
             {
 450  0
                 batchCon.executeBatch();
 451  
             }
 452  0
             catch (Throwable th)
 453  
             {
 454  0
                 throw new OJBBatchUpdateException(th);
 455  0
             }
 456  
         }
 457  0
     }
 458  
 
 459  
     /**
 460  
      * Execute batch if the number of statements in it
 461  
      * exceeded the limit (if the batch mode where used).
 462  
      */
 463  
     public void executeBatchIfNecessary() throws OJBBatchUpdateException
 464  
     {
 465  0
         if (batchCon != null)
 466  
         {
 467  
             try
 468  
             {
 469  0
                 batchCon.executeBatchIfNecessary();
 470  
             }
 471  0
             catch (Throwable th)
 472  
             {
 473  0
                 throw new OJBBatchUpdateException(th);
 474  0
             }
 475  
         }
 476  0
     }
 477  
 
 478  
     /**
 479  
      * Clear batch (if the batch mode where used).
 480  
      */
 481  
     public void clearBatch()
 482  
     {
 483  0
         if (batchCon != null)
 484  
         {
 485  0
             batchCon.clearBatch();
 486  
         }
 487  0
     }
 488  
 }

This report is generated by jcoverage, Maven and Maven JCoverage Plugin.