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 018package org.apache.commons.dbcp2; 019 020import java.sql.CallableStatement; 021import java.sql.Connection; 022import java.sql.ResultSet; 023import java.sql.SQLException; 024import java.util.List; 025 026import org.apache.commons.pool2.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: 1572242 $ $Date: 2014-02-26 20:34:39 +0000 (Wed, 26 Feb 2014) $ 036 * @since 2.0 037 */ 038public class PoolableCallableStatement extends DelegatingCallableStatement { 039 040 /** 041 * The {@link KeyedObjectPool} from which this CallableStatement was obtained. 042 */ 043 private final KeyedObjectPool<PStmtKey,DelegatingPreparedStatement> _pool; 044 045 /** 046 * Key for this statement in the containing {@link KeyedObjectPool}. 047 */ 048 private final PStmtKey _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 DelegatingConnection} that created this CallableStatement 057 */ 058 public PoolableCallableStatement(CallableStatement stmt, PStmtKey key, 059 KeyedObjectPool<PStmtKey,DelegatingPreparedStatement> pool, 060 DelegatingConnection<Connection> conn) { 061 super(conn, stmt); 062 _pool = pool; 063 _key = key; 064 065 // Remove from trace now because this statement will be 066 // added by the activate method. 067 if(getConnectionInternal() != null) { 068 getConnectionInternal().removeTrace(this); 069 } 070 } 071 072 /** 073 * Returns the CallableStatement to the pool. If {{@link #isClosed()}, this is a No-op. 074 */ 075 @Override 076 public void close() throws SQLException { 077 // calling close twice should have no effect 078 if (!isClosed()) { 079 try { 080 _pool.returnObject(_key,this); 081 } catch(SQLException e) { 082 throw e; 083 } catch(RuntimeException e) { 084 throw e; 085 } catch(Exception e) { 086 throw new SQLException("Cannot close CallableStatement (return to pool failed)", e); 087 } 088 } 089 } 090 091 /** 092 * Activates after retrieval from the pool. Adds a trace for this CallableStatement to the Connection 093 * that created it. 094 */ 095 @Override 096 protected void activate() throws SQLException { 097 setClosedInternal(false); 098 if( getConnectionInternal() != null ) { 099 getConnectionInternal().addTrace( this ); 100 } 101 super.activate(); 102 } 103 104 /** 105 * Passivates to prepare for return to the pool. Removes the trace associated with this CallableStatement 106 * from the Connection that created it. Also closes any associated ResultSets. 107 */ 108 @Override 109 protected void passivate() throws SQLException { 110 setClosedInternal(true); 111 if( getConnectionInternal() != null ) { 112 getConnectionInternal().removeTrace(this); 113 } 114 115 // The JDBC spec requires that a statment close any open 116 // ResultSet's when it is closed. 117 // FIXME The PreparedStatement we're wrapping should handle this for us. 118 // See DBCP-10 for what could happen when ResultSets are closed twice. 119 List<AbandonedTrace> resultSets = getTrace(); 120 if(resultSets != null) { 121 ResultSet[] set = resultSets.toArray(new ResultSet[resultSets.size()]); 122 for (ResultSet element : set) { 123 element.close(); 124 } 125 clearTrace(); 126 } 127 128 super.passivate(); 129 } 130 131}