Coverage Report - org.kuali.rice.core.framework.persistence.jdbc.datasource.RiceXADataSource
 
Classes in this File Line Coverage Branch Coverage Complexity
RiceXADataSource
0%
0/29
0%
0/12
1.667
RiceXADataSource$PreparedStatementCachingConnection
0%
0/6
0%
0/2
1.667
 
 1  
 /*
 2  
  * Copyright 2007-2009 The Kuali Foundation
 3  
  *
 4  
  * Licensed under the Educational Community License, Version 2.0 (the "License");
 5  
  * you may not use this file except in compliance with the License.
 6  
  * You may obtain a copy of the License at
 7  
  *
 8  
  * http://www.opensource.org/licenses/ecl2.php
 9  
  *
 10  
  * Unless required by applicable law or agreed to in writing, software
 11  
  * distributed under the License is distributed on an "AS IS" BASIS,
 12  
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 13  
  * See the License for the specific language governing permissions and
 14  
  * limitations under the License.
 15  
  */
 16  
 package org.kuali.rice.core.framework.persistence.jdbc.datasource;
 17  
 
 18  
 import java.sql.Connection;
 19  
 import java.sql.SQLException;
 20  
 
 21  
 import org.apache.commons.dbcp.PoolingConnection;
 22  
 import org.apache.commons.pool.KeyedObjectPool;
 23  
 import org.apache.commons.pool.KeyedObjectPoolFactory;
 24  
 import org.apache.commons.pool.impl.GenericKeyedObjectPool;
 25  
 import org.apache.commons.pool.impl.GenericKeyedObjectPoolFactory;
 26  
 import org.enhydra.jdbc.standard.StandardXADataSource;
 27  
 import org.enhydra.jdbc.standard.StandardXAStatefulConnection;
 28  
 import org.springframework.util.Assert;
 29  
 
 30  
 import javax.sql.DataSource;
 31  
 
 32  
 /**
 33  
  * This is a description of what this class does - wliang don't forget to fill this in. 
 34  
  * 
 35  
  * Portions of this code were copied from Apache DBCP 1.2.1
 36  
  * 
 37  
  * @author Kuali Rice Team (rice.collab@kuali.org)
 38  
  *
 39  
  */
 40  
 public class RiceXADataSource extends StandardXADataSource {
 41  
         private KeyedObjectPoolFactory _stmtPoolFactory;
 42  
         private int preparedStatementCacheSize;
 43  
 
 44  0
         public RiceXADataSource() {
 45  
                 // the built-in XAPool prepared statement caching is broken, and it was enabled by calling this method with a non-zero value.
 46  
                 // so we set it to 0, which effectively disables the built-in caching
 47  0
                 super.setPreparedStmtCacheSize(0);
 48  0
         }
 49  
         
 50  
         @Override
 51  
         public synchronized Connection getConnection(String arg0, String arg1)
 52  
                         throws SQLException {
 53  0
                 Connection conn = super.getConnection(arg0, arg1);
 54  
                 
 55  
                 // wrap the connection with another connection that can pool prepared statements
 56  0
                 if (getPreparedStatementCacheSize() > 0) {
 57  0
                         conn = wrapConnection(conn);
 58  
                 }
 59  0
                 return conn;
 60  
         }
 61  
 
 62  
         @Override
 63  
         public synchronized StandardXAStatefulConnection getFreeConnection() throws SQLException {
 64  0
                 StandardXAStatefulConnection conn = super.getFreeConnection();
 65  0
                 if (getPreparedStatementCacheSize() > 0) {
 66  0
                         if (conn != null && !(conn.con instanceof PreparedStatementCachingConnection)) {
 67  0
                                 conn.con = wrapConnection(conn.con);
 68  
                         }
 69  
                 }
 70  0
                 return conn;
 71  
         }
 72  
         
 73  
         public int getPreparedStatementCacheSize() {
 74  0
                 return preparedStatementCacheSize;
 75  
         }
 76  
 
 77  
         public void setPreparedStatementCacheSize(int preparedStmtCacheSize) {
 78  0
                 this.preparedStatementCacheSize = preparedStmtCacheSize;
 79  0
         }
 80  
 
 81  
         /**
 82  
          * This method calls {@link #setPreparedStatementCacheSize(int)} instead of setting this property.
 83  
          * The reason 2 properties exist is because preparedStmtCacheSize is used by XAPool to enable PreparedStatement caching, but
 84  
          * its implementation seems to cause max cursors to be exceeded under oracle.  Therefore, this class defines a new property, preparedStatementCacheSize,
 85  
          * that will instead be used to turn on caching
 86  
          * 
 87  
          * @see org.enhydra.jdbc.standard.StandardConnectionPoolDataSource#setPreparedStmtCacheSize(int)
 88  
          */
 89  
         @Override
 90  
         public void setPreparedStmtCacheSize(int preparedStmtCacheSize) {
 91  
                 // the built-in XAPool prepared statement caching is broken, and it was enabled by calling this method with a non-zero value.
 92  
                 // so we override it not to call the super's method and instead set the size of the cache that's implemented in this class
 93  0
                 setPreparedStatementCacheSize(preparedStmtCacheSize);
 94  0
         }
 95  
         
 96  
         protected KeyedObjectPoolFactory createStatementPoolFactory() {
 97  0
                 return new GenericKeyedObjectPoolFactory(null, 
 98  
                 -1, // unlimited maxActive (per key)
 99  
                 GenericKeyedObjectPool.WHEN_EXHAUSTED_GROW, 
 100  
                 0, // maxWait
 101  
                 1, // maxIdle (per key) 
 102  
                 getPreparedStatementCacheSize()); 
 103  
         }
 104  
         
 105  
         protected PreparedStatementCachingConnection wrapConnection(Connection realConnection) {
 106  
                 // can't initialize the following variable in the constructor because the prepared statement cache size won't be available
 107  0
                 if (_stmtPoolFactory == null) {
 108  0
                         _stmtPoolFactory = createStatementPoolFactory();
 109  
                 }
 110  
                 
 111  0
         KeyedObjectPool stmtpool = _stmtPoolFactory.createPool();
 112  0
         PreparedStatementCachingConnection wrappedConnection = new PreparedStatementCachingConnection(realConnection, stmtpool);
 113  
         
 114  0
         stmtpool.setFactory(wrappedConnection);
 115  0
         return wrappedConnection;
 116  
         }
 117  
 
 118  
         public <T> T  unwrap(Class<T> iface) throws SQLException {
 119  0
                 Assert.notNull(iface, "Interface argument must not be null");
 120  0
                 if (!DataSource.class.equals(iface)) {
 121  0
                         throw new SQLException("DataSource of type [" + getClass().getName() +
 122  
                                         "] can only be unwrapped as [javax.sql.DataSource], not as [" + iface.getName());
 123  
                 }
 124  0
                 return (T) this;
 125  
         }
 126  
 
 127  
         public boolean isWrapperFor(Class<?> iface) throws SQLException {
 128  0
                 return DataSource.class.equals(iface);
 129  
         }
 130  
 
 131  
     /**
 132  
      * A subclass of Apache DBCP's PoolingConnection class.  This class generates a unique
 133  
      * toString value for each instance of this class, because XApool relies on such behavior
 134  
      *
 135  
      * @author Kuali Rice Team (rice.collab@kuali.org)
 136  
      *
 137  
      */
 138  
     private static class PreparedStatementCachingConnection extends PoolingConnection {
 139  
         private String stringRepresentation;
 140  
 
 141  
         public PreparedStatementCachingConnection(Connection conn, KeyedObjectPool preparedStatementCache) {
 142  0
             super(conn, preparedStatementCache);
 143  0
             stringRepresentation = null;
 144  0
         }
 145  
 
 146  
         @Override
 147  
         public String toString() {
 148  
             // for some reason, XAPool uses the connection's toString as a unique identifier for the connection
 149  
             // this method should provide that unique identifier
 150  0
             if (stringRepresentation == null) {
 151  0
                 stringRepresentation = "PreparedStatementCachingConnection: " + System.identityHashCode(this);
 152  
             }
 153  0
             return stringRepresentation;
 154  
         }
 155  
     }
 156  
 }