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 }