View Javadoc

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.database;
17  
18  import java.sql.Connection;
19  import java.sql.SQLException;
20  import java.util.Hashtable;
21  
22  import javax.naming.Context;
23  import javax.naming.Name;
24  
25  import org.apache.commons.dbcp.PoolingConnection;
26  import org.apache.commons.pool.KeyedObjectPool;
27  import org.apache.commons.pool.KeyedObjectPoolFactory;
28  import org.apache.commons.pool.impl.GenericKeyedObjectPool;
29  import org.apache.commons.pool.impl.GenericKeyedObjectPoolFactory;
30  import org.enhydra.jdbc.standard.StandardXADataSource;
31  import org.enhydra.jdbc.standard.StandardXAStatefulConnection;
32  
33  /**
34   * This is a description of what this class does - wliang don't forget to fill this in. 
35   * 
36   * Portions of this code were copied from Apache DBCP 1.2.1
37   * 
38   * @author Kuali Rice Team (rice.collab@kuali.org)
39   *
40   */
41  public class RiceXADataSource extends StandardXADataSource {
42  	private KeyedObjectPoolFactory _stmtPoolFactory;
43  	private int preparedStatementCacheSize;
44  
45  	public RiceXADataSource() {
46  		// the built-in XAPool prepared statement caching is broken, and it was enabled by calling this method with a non-zero value.
47  		// so we set it to 0, which effectively disables the built-in caching
48  		super.setPreparedStmtCacheSize(0);
49  	}
50  	
51  	@Override
52  	public synchronized Connection getConnection(String arg0, String arg1)
53  			throws SQLException {
54  		Connection conn = super.getConnection(arg0, arg1);
55  		
56  		// wrap the connection with another connection that can pool prepared statements
57  		if (getPreparedStatementCacheSize() > 0) {
58  			conn = wrapConnection(conn);
59  		}
60  		return conn;
61  	}
62  
63  	@Override
64  	public synchronized StandardXAStatefulConnection getFreeConnection() throws SQLException {
65  		StandardXAStatefulConnection conn = super.getFreeConnection();
66  		if (getPreparedStatementCacheSize() > 0) {
67  			if (conn != null && !(conn.con instanceof PreparedStatementCachingConnection)) {
68  				conn.con = wrapConnection(conn.con);
69  			}
70  		}
71  		return conn;
72  	}
73  	
74  	public int getPreparedStatementCacheSize() {
75  		return preparedStatementCacheSize;
76  	}
77  
78  	public void setPreparedStatementCacheSize(int preparedStmtCacheSize) {
79  		this.preparedStatementCacheSize = preparedStmtCacheSize;
80  	}
81  
82  	/**
83  	 * This method calls {@link #setPreparedStatementCacheSize(int)} instead of setting this property.
84  	 * The reason 2 properties exist is because preparedStmtCacheSize is used by XAPool to enable PreparedStatement caching, but
85  	 * its implementation seems to cause max cursors to be exceeded under oracle.  Therefore, this class defines a new property, preparedStatementCacheSize,
86  	 * that will instead be used to turn on caching
87  	 * 
88  	 * @see org.enhydra.jdbc.standard.StandardConnectionPoolDataSource#setPreparedStmtCacheSize(int)
89  	 */
90  	@Override
91  	public void setPreparedStmtCacheSize(int preparedStmtCacheSize) {
92  		// the built-in XAPool prepared statement caching is broken, and it was enabled by calling this method with a non-zero value.
93  		// 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
94  		setPreparedStatementCacheSize(preparedStmtCacheSize);
95  	}
96  	
97  	protected KeyedObjectPoolFactory createStatementPoolFactory() {
98  		return new GenericKeyedObjectPoolFactory(null, 
99                  -1, // unlimited maxActive (per key)
100                 GenericKeyedObjectPool.WHEN_EXHAUSTED_GROW, 
101                 0, // maxWait
102                 1, // maxIdle (per key) 
103                 getPreparedStatementCacheSize()); 
104 	}
105 	
106 	protected PreparedStatementCachingConnection wrapConnection(Connection realConnection) {
107 		// can't initialize the following variable in the constructor because the prepared statement cache size won't be available
108 		if (_stmtPoolFactory == null) {
109 			_stmtPoolFactory = createStatementPoolFactory();
110 		}
111 		
112         KeyedObjectPool stmtpool = _stmtPoolFactory.createPool();
113         PreparedStatementCachingConnection wrappedConnection = new PreparedStatementCachingConnection(realConnection, stmtpool);
114         
115         stmtpool.setFactory(wrappedConnection);
116         return wrappedConnection;
117 	}
118 }