001 /* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 018 package org.apache.commons.dbcp; 019 020 import java.sql.CallableStatement; 021 import java.sql.Connection; 022 import java.sql.ResultSet; 023 import java.sql.SQLException; 024 import java.util.List; 025 026 import org.apache.commons.pool.KeyedObjectPool; 027 028 /** 029 * A {@link DelegatingCallableStatement} that cooperates with 030 * {@link PoolingConnection} to implement a pool of {@link CallableStatement}s. 031 * <p> 032 * The {@link #close} method returns this statement to its containing pool. (See {@link PoolingConnection}.) 033 * 034 * @see PoolingConnection 035 * @version $Revision: 892307 $ $Date: 2013-12-31 23:27:28 +0000 (Tue, 31 Dec 2013) $ 036 * @since 1.3 037 */ 038 public class PoolableCallableStatement extends DelegatingCallableStatement implements CallableStatement { 039 040 /** 041 * The {@link KeyedObjectPool} from which this CallableStatement was obtained. 042 */ 043 private final KeyedObjectPool _pool; 044 045 /** 046 * Key for this statement in the containing {@link KeyedObjectPool}. 047 */ 048 private final Object _key; 049 050 /** 051 * Constructor. 052 * 053 * @param stmt the underlying {@link CallableStatement} 054 * @param key the key for this statement in the {@link KeyedObjectPool} 055 * @param pool the {@link KeyedObjectPool} from which this CallableStatement was obtained 056 * @param conn the {@link Connection} that created this CallableStatement 057 */ 058 public PoolableCallableStatement(CallableStatement stmt, Object key, KeyedObjectPool pool, Connection conn) { 059 super((DelegatingConnection)conn, stmt); 060 _pool = pool; 061 _key = key; 062 063 // Remove from trace now because this statement will be 064 // added by the activate method. 065 if(_conn != null) { 066 _conn.removeTrace(this); 067 } 068 } 069 070 /** 071 * Returns the CallableStatement to the pool. If {{@link #isClosed()}, this is a No-op. 072 */ 073 public void close() throws SQLException { 074 // calling close twice should have no effect 075 if (!isClosed()) { 076 try { 077 _pool.returnObject(_key,this); 078 } catch(SQLException e) { 079 throw e; 080 } catch(RuntimeException e) { 081 throw e; 082 } catch(Exception e) { 083 throw new SQLNestedException("Cannot close CallableStatement (return to pool failed)", e); 084 } 085 } 086 } 087 088 /** 089 * Activates after retrieval from the pool. Adds a trace for this CallableStatement to the Connection 090 * that created it. 091 */ 092 protected void activate() throws SQLException { 093 _closed = false; 094 if( _conn != null ) { 095 _conn.addTrace( this ); 096 } 097 super.activate(); 098 } 099 100 /** 101 * Passivates to prepare for return to the pool. Removes the trace associated with this CallableStatement 102 * from the Connection that created it. Also closes any associated ResultSets. 103 */ 104 protected void passivate() throws SQLException { 105 _closed = true; 106 if( _conn != null ) { 107 _conn.removeTrace(this); 108 } 109 110 // The JDBC spec requires that a statment close any open 111 // ResultSet's when it is closed. 112 // FIXME The PreparedStatement we're wrapping should handle this for us. 113 // See DBCP-10 for what could happen when ResultSets are closed twice. 114 List resultSets = getTrace(); 115 if(resultSets != null) { 116 ResultSet[] set = (ResultSet[])resultSets.toArray(new ResultSet[resultSets.size()]); 117 for(int i = 0; i < set.length; i++) { 118 set[i].close(); 119 } 120 clearTrace(); 121 } 122 123 super.passivate(); 124 } 125 126 }