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  package org.apache.commons.dbcp2;
18  
19  import java.sql.PreparedStatement;
20  import java.sql.SQLException;
21  
22  import org.apache.commons.pool2.KeyedObjectPool;
23  
24  /**
25   * A {@link DelegatingPreparedStatement} that cooperates with {@link PoolingConnection} to implement a pool of
26   * {@link PreparedStatement}s.
27   * <p>
28   * My {@link #close} method returns me to my containing pool. (See {@link PoolingConnection}.)
29   * </p>
30   *
31   * @param <K>
32   *            the key type
33   *
34   * @see PoolingConnection
35   * @since 2.0
36   */
37  public class PoolablePreparedStatement<K> extends DelegatingPreparedStatement {
38  
39      /**
40       * The {@link KeyedObjectPool} from which I was obtained.
41       */
42      private final KeyedObjectPool<K, PoolablePreparedStatement<K>> pool;
43  
44      /**
45       * My "key" as used by {@link KeyedObjectPool}.
46       */
47      private final K key;
48  
49      private volatile boolean batchAdded;
50  
51      /**
52       * Constructs a new instance.
53       *
54       * @param stmt
55       *            my underlying {@link PreparedStatement}
56       * @param key
57       *            my key as used by {@link KeyedObjectPool}
58       * @param pool
59       *            the {@link KeyedObjectPool} from which I was obtained.
60       * @param conn
61       *            the {@link java.sql.Connection Connection} from which I was created
62       */
63      public PoolablePreparedStatement(final PreparedStatement stmt, final K key,
64              final KeyedObjectPool<K, PoolablePreparedStatement<K>> pool, final DelegatingConnection<?> conn) {
65          super(conn, stmt);
66          this.pool = pool;
67          this.key = key;
68  
69          // Remove from trace now because this statement will be
70          // added by the activate method.
71          removeThisTrace(conn);
72      }
73  
74      @Override
75      public void activate() throws SQLException {
76          setClosedInternal(false);
77          AbandonedTrace.add(getConnectionInternal(), this);
78          super.activate();
79      }
80  
81      /**
82       * Add batch.
83       */
84      @Override
85      public void addBatch() throws SQLException {
86          super.addBatch();
87          batchAdded = true;
88      }
89  
90      /**
91       * Clear Batch.
92       */
93      @Override
94      public void clearBatch() throws SQLException {
95          batchAdded = false;
96          super.clearBatch();
97      }
98  
99      /**
100      * Return me to my pool.
101      */
102     @Override
103     public void close() throws SQLException {
104         // calling close twice should have no effect
105         if (!isClosed()) {
106             try {
107                 pool.returnObject(key, this);
108             } catch (final SQLException | RuntimeException e) {
109                 throw e;
110             } catch (final Exception e) {
111                 throw new SQLException("Cannot close preparedstatement (return to pool failed)", e);
112             }
113         }
114     }
115 
116     /**
117      * Package-protected for tests.
118      *
119      * @return The key.
120      */
121     K getKey() {
122         return key;
123     }
124 
125     @Override
126     public void passivate() throws SQLException {
127         // DBCP-372. clearBatch with throw an exception if called when the
128         // connection is marked as closed.
129         if (batchAdded) {
130             clearBatch();
131         }
132         prepareToReturn();
133     }
134 }