View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    * 
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   * 
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  
18  package org.apache.commons.dbcp;
19  
20  import java.sql.Connection;
21  import java.sql.PreparedStatement;
22  import java.sql.ResultSet;
23  import java.sql.SQLException;
24  import java.util.List;
25  
26  import org.apache.commons.pool.KeyedObjectPool;
27  
28  /**
29   * A {@link DelegatingPreparedStatement} that cooperates with
30   * {@link PoolingConnection} to implement a pool of {@link PreparedStatement}s.
31   * <p>
32   * My {@link #close} method returns me to my containing pool. (See {@link PoolingConnection}.)
33   *
34   * @see PoolingConnection
35   * @author Rodney Waldhoff
36   * @author Glenn L. Nielsen
37   * @author James House
38   * @author Dirk Verbeeck
39   * @version $Revision: 1023401 $ $Date: 2010-10-16 21:54:24 -0400 (Sat, 16 Oct 2010) $
40   */
41  public class PoolablePreparedStatement extends DelegatingPreparedStatement implements PreparedStatement {
42      /**
43       * The {@link KeyedObjectPool} from which I was obtained.
44       */
45      protected KeyedObjectPool _pool = null;
46  
47      /**
48       * My "key" as used by {@link KeyedObjectPool}.
49       */
50      protected Object _key = null;
51  
52      private volatile boolean batchAdded = false;
53  
54      /**
55       * Constructor
56       * @param stmt my underlying {@link PreparedStatement}
57       * @param key my key" as used by {@link KeyedObjectPool}
58       * @param pool the {@link KeyedObjectPool} from which I was obtained.
59       * @param conn the {@link Connection} from which I was created
60       */
61      public PoolablePreparedStatement(PreparedStatement stmt, Object key, KeyedObjectPool pool, Connection conn) {
62          super((DelegatingConnection) conn, stmt);
63          _pool = pool;
64          _key = key;
65  
66          // Remove from trace now because this statement will be 
67          // added by the activate method.
68          if(_conn != null) {
69              _conn.removeTrace(this);
70          }
71      }
72  
73      /**
74       * Add batch.
75       */
76      public void addBatch() throws SQLException {
77          super.addBatch();
78          batchAdded = true;
79      }
80  
81      /**
82       * Clear Batch.
83       */
84      public void clearBatch() throws SQLException {
85          batchAdded = false;
86          super.clearBatch();
87      }
88  
89      /**
90       * Return me to my pool.
91       */
92      public void close() throws SQLException {
93          // calling close twice should have no effect
94          if (!isClosed()) {
95              try {
96                  _pool.returnObject(_key,this);
97              } catch(SQLException e) {
98                  throw e;
99              } 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 }