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.Connection; 021 import java.sql.PreparedStatement; 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 DelegatingPreparedStatement} that cooperates with 030 * {@link PoolingConnection} to implement a pool of {@link PreparedStatement}s. 031 * <p> 032 * My {@link #close} method returns me to my containing pool. (See {@link PoolingConnection}.) 033 * 034 * @see PoolingConnection 035 * @author Rodney Waldhoff 036 * @author Glenn L. Nielsen 037 * @author James House 038 * @author Dirk Verbeeck 039 * @version $Revision: 892307 $ $Date: 2013-12-31 23:27:28 +0000 (Tue, 31 Dec 2013) $ 040 */ 041 public class PoolablePreparedStatement extends DelegatingPreparedStatement implements PreparedStatement { 042 /** 043 * The {@link KeyedObjectPool} from which I was obtained. 044 */ 045 protected KeyedObjectPool _pool = null; 046 047 /** 048 * My "key" as used by {@link KeyedObjectPool}. 049 */ 050 protected Object _key = null; 051 052 private volatile boolean batchAdded = false; 053 054 /** 055 * Constructor 056 * @param stmt my underlying {@link PreparedStatement} 057 * @param key my key" as used by {@link KeyedObjectPool} 058 * @param pool the {@link KeyedObjectPool} from which I was obtained. 059 * @param conn the {@link Connection} from which I was created 060 */ 061 public PoolablePreparedStatement(PreparedStatement stmt, Object key, KeyedObjectPool pool, Connection conn) { 062 super((DelegatingConnection) conn, stmt); 063 _pool = pool; 064 _key = key; 065 066 // Remove from trace now because this statement will be 067 // added by the activate method. 068 if(_conn != null) { 069 _conn.removeTrace(this); 070 } 071 } 072 073 /** 074 * Add batch. 075 */ 076 public void addBatch() throws SQLException { 077 super.addBatch(); 078 batchAdded = true; 079 } 080 081 /** 082 * Clear Batch. 083 */ 084 public void clearBatch() throws SQLException { 085 batchAdded = false; 086 super.clearBatch(); 087 } 088 089 /** 090 * Return me to my pool. 091 */ 092 public void close() throws SQLException { 093 // calling close twice should have no effect 094 if (!isClosed()) { 095 try { 096 _pool.returnObject(_key,this); 097 } catch(SQLException e) { 098 throw e; 099 } catch(RuntimeException e) { 100 throw e; 101 } catch(Exception e) { 102 throw new SQLNestedException("Cannot close preparedstatement (return to pool failed)", e); 103 } 104 } 105 } 106 107 protected void activate() throws SQLException{ 108 _closed = false; 109 if(_conn != null) { 110 _conn.addTrace(this); 111 } 112 super.activate(); 113 } 114 115 protected void passivate() throws SQLException { 116 _closed = true; 117 if(_conn != null) { 118 _conn.removeTrace(this); 119 } 120 121 // The JDBC spec requires that a statment close any open 122 // ResultSet's when it is closed. 123 // FIXME The PreparedStatement we're wrapping should handle this for us. 124 // See bug 17301 for what could happen when ResultSets are closed twice. 125 List resultSets = getTrace(); 126 if( resultSets != null) { 127 ResultSet[] set = (ResultSet[]) resultSets.toArray(new ResultSet[resultSets.size()]); 128 for (int i = 0; i < set.length; i++) { 129 set[i].close(); 130 } 131 clearTrace(); 132 } 133 if (batchAdded) { 134 clearBatch(); 135 } 136 137 super.passivate(); 138 } 139 140 }