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.cpdsadapter;
18
19 import java.sql.CallableStatement;
20 import java.sql.Connection;
21 import java.sql.PreparedStatement;
22 import java.sql.SQLException;
23
24 import org.apache.commons.dbcp2.DelegatingCallableStatement;
25 import org.apache.commons.dbcp2.DelegatingConnection;
26 import org.apache.commons.dbcp2.DelegatingPreparedStatement;
27
28 /**
29 * This class is the {@code Connection} that will be returned from
30 * {@code PooledConnectionImpl.getConnection()}. Most methods are wrappers around the JDBC 1.x
31 * {@code Connection}. A few exceptions include preparedStatement and close. In accordance with the JDBC
32 * specification this Connection cannot be used after closed() is called. Any further usage will result in an
33 * SQLException.
34 * <p>
35 * ConnectionImpl extends DelegatingConnection to enable access to the underlying connection.
36 * </p>
37 *
38 * @since 2.0
39 */
40 final class ConnectionImpl extends DelegatingConnection<Connection> {
41
42 private final boolean accessToUnderlyingConnectionAllowed;
43
44 /** The object that instantiated this object */
45 private final PooledConnectionImpl pooledConnection;
46
47 /**
48 * Creates a {@code ConnectionImpl}.
49 *
50 * @param pooledConnection
51 * The PooledConnection that is calling the ctor.
52 * @param connection
53 * The JDBC 1.x Connection to wrap.
54 * @param accessToUnderlyingConnectionAllowed
55 * if true, then access is allowed to the underlying connection
56 */
57 ConnectionImpl(final PooledConnectionImpl pooledConnection, final Connection connection,
58 final boolean accessToUnderlyingConnectionAllowed) {
59 super(connection);
60 this.pooledConnection = pooledConnection;
61 this.accessToUnderlyingConnectionAllowed = accessToUnderlyingConnectionAllowed;
62 }
63
64 /**
65 * Marks the Connection as closed, and notifies the pool that the pooled connection is available.
66 * <p>
67 * In accordance with the JDBC specification this Connection cannot be used after closed() is called. Any further
68 * usage will result in an SQLException.
69 * </p>
70 *
71 * @throws SQLException
72 * The database connection couldn't be closed.
73 */
74 @Override
75 public void close() throws SQLException {
76 if (!isClosedInternal()) {
77 try {
78 passivate();
79 } finally {
80 setClosedInternal(true);
81 pooledConnection.notifyListeners();
82 }
83 }
84 }
85
86 /**
87 * Gets the delegated connection, if allowed.
88 *
89 * @return the internal connection, or null if access is not allowed.
90 * @see #isAccessToUnderlyingConnectionAllowed()
91 */
92 @Override
93 public Connection getDelegate() {
94 if (isAccessToUnderlyingConnectionAllowed()) {
95 return getDelegateInternal();
96 }
97 return null;
98 }
99
100 /**
101 * Gets the innermost connection, if allowed.
102 *
103 * @return the innermost internal connection, or null if access is not allowed.
104 * @see #isAccessToUnderlyingConnectionAllowed()
105 */
106 @Override
107 public Connection getInnermostDelegate() {
108 if (isAccessToUnderlyingConnectionAllowed()) {
109 return super.getInnermostDelegateInternal();
110 }
111 return null;
112 }
113
114 /**
115 * Package-private for tests.
116 *
117 * @return the PooledConnectionImpl.
118 */
119 PooledConnectionImpl getPooledConnectionImpl() {
120 return pooledConnection;
121 }
122
123 /**
124 * If false, getDelegate() and getInnermostDelegate() will return null.
125 *
126 * @return true if access is allowed to the underlying connection
127 * @see ConnectionImpl
128 */
129 public boolean isAccessToUnderlyingConnectionAllowed() {
130 return accessToUnderlyingConnectionAllowed;
131 }
132
133 /**
134 * If pooling of {@code CallableStatement}s is turned on in the {@link DriverAdapterCPDS}, a pooled object may
135 * be returned, otherwise delegate to the wrapped JDBC 1.x {@link java.sql.Connection}.
136 *
137 * @param sql
138 * an SQL statement that may contain one or more '?' parameter placeholders. Typically, this statement is
139 * specified using JDBC call escape syntax.
140 * @return a default {@code CallableStatement} object containing the pre-compiled SQL statement.
141 * @throws SQLException
142 * Thrown if a database access error occurs or this method is called on a closed connection.
143 * @since 2.4.0
144 */
145 @Override
146 public CallableStatement prepareCall(final String sql) throws SQLException {
147 checkOpen();
148 try {
149 return new DelegatingCallableStatement(this, pooledConnection.prepareCall(sql));
150 } catch (final SQLException e) {
151 handleException(e); // Does not return
152 return null;
153 }
154 }
155
156 /**
157 * If pooling of {@code CallableStatement}s is turned on in the {@link DriverAdapterCPDS}, a pooled object may
158 * be returned, otherwise delegate to the wrapped JDBC 1.x {@link java.sql.Connection}.
159 *
160 * @param sql
161 * a {@code String} object that is the SQL statement to be sent to the database; may contain on or
162 * more '?' parameters.
163 * @param resultSetType
164 * a result set type; one of {@code ResultSet.TYPE_FORWARD_ONLY},
165 * {@code ResultSet.TYPE_SCROLL_INSENSITIVE}, or {@code ResultSet.TYPE_SCROLL_SENSITIVE}.
166 * @param resultSetConcurrency
167 * a concurrency type; one of {@code ResultSet.CONCUR_READ_ONLY} or
168 * {@code ResultSet.CONCUR_UPDATABLE}.
169 * @return a {@code CallableStatement} object containing the pre-compiled SQL statement that will produce
170 * {@code ResultSet} objects with the given type and concurrency.
171 * @throws SQLException
172 * Thrown if a database access error occurs, this method is called on a closed connection or the given
173 * parameters are not {@code ResultSet} constants indicating type and concurrency.
174 * @since 2.4.0
175 */
176 @Override
177 public CallableStatement prepareCall(final String sql, final int resultSetType, final int resultSetConcurrency)
178 throws SQLException {
179 checkOpen();
180 try {
181 return new DelegatingCallableStatement(this,
182 pooledConnection.prepareCall(sql, resultSetType, resultSetConcurrency));
183 } catch (final SQLException e) {
184 handleException(e); // Does not return
185 return null;
186 }
187 }
188
189 /**
190 * If pooling of {@code CallableStatement}s is turned on in the {@link DriverAdapterCPDS}, a pooled object may
191 * be returned, otherwise delegate to the wrapped JDBC 1.x {@link java.sql.Connection}.
192 *
193 * @param sql
194 * a {@code String} object that is the SQL statement to be sent to the database; may contain on or
195 * more '?' parameters.
196 * @param resultSetType
197 * one of the following {@code ResultSet} constants: {@code ResultSet.TYPE_FORWARD_ONLY},
198 * {@code ResultSet.TYPE_SCROLL_INSENSITIVE}, or {@code ResultSet.TYPE_SCROLL_SENSITIVE}.
199 * @param resultSetConcurrency
200 * one of the following {@code ResultSet} constants: {@code ResultSet.CONCUR_READ_ONLY} or
201 * {@code ResultSet.CONCUR_UPDATABLE}.
202 * @param resultSetHoldability
203 * one of the following {@code ResultSet} constants: {@code ResultSet.HOLD_CURSORS_OVER_COMMIT}
204 * or {@code ResultSet.CLOSE_CURSORS_AT_COMMIT}.
205 * @return a new {@code CallableStatement} object, containing the pre-compiled SQL statement, that will
206 * generate {@code ResultSet} objects with the given type, concurrency, and holdability.
207 * @throws SQLException
208 * Thrown if a database access error occurs, this method is called on a closed connection or the given
209 * parameters are not {@code ResultSet} constants indicating type, concurrency, and holdability.
210 * @since 2.4.0
211 */
212 @Override
213 public CallableStatement prepareCall(final String sql, final int resultSetType, final int resultSetConcurrency,
214 final int resultSetHoldability) throws SQLException {
215 checkOpen();
216 try {
217 return new DelegatingCallableStatement(this,
218 pooledConnection.prepareCall(sql, resultSetType, resultSetConcurrency, resultSetHoldability));
219 } catch (final SQLException e) {
220 handleException(e); // Does not return
221 return null;
222 }
223 }
224
225 /**
226 * If pooling of {@code PreparedStatement}s is turned on in the {@link DriverAdapterCPDS}, a pooled object may
227 * be returned, otherwise delegate to the wrapped JDBC 1.x {@link java.sql.Connection}.
228 *
229 * @param sql
230 * SQL statement to be prepared
231 * @return the prepared statement
232 * @throws SQLException
233 * if this connection is closed or an error occurs in the wrapped connection.
234 */
235 @Override
236 public PreparedStatement prepareStatement(final String sql) throws SQLException {
237 checkOpen();
238 try {
239 return new DelegatingPreparedStatement(this, pooledConnection.prepareStatement(sql));
240 } catch (final SQLException e) {
241 handleException(e); // Does not return
242 return null;
243 }
244 }
245
246 @Override
247 public PreparedStatement prepareStatement(final String sql, final int autoGeneratedKeys) throws SQLException {
248 checkOpen();
249 try {
250 return new DelegatingPreparedStatement(this, pooledConnection.prepareStatement(sql, autoGeneratedKeys));
251 } catch (final SQLException e) {
252 handleException(e);
253 return null;
254 }
255 }
256
257 //
258 // Methods for accessing the delegate connection
259 //
260
261 /**
262 * If pooling of {@code PreparedStatement}s is turned on in the {@link DriverAdapterCPDS}, a pooled object may
263 * be returned, otherwise delegate to the wrapped JDBC 1.x {@link java.sql.Connection}.
264 *
265 * @throws SQLException
266 * if this connection is closed or an error occurs in the wrapped connection.
267 */
268 @Override
269 public PreparedStatement prepareStatement(final String sql, final int resultSetType, final int resultSetConcurrency)
270 throws SQLException {
271 checkOpen();
272 try {
273 return new DelegatingPreparedStatement(this,
274 pooledConnection.prepareStatement(sql, resultSetType, resultSetConcurrency));
275 } catch (final SQLException e) {
276 handleException(e);
277 return null;
278 }
279 }
280
281 @Override
282 public PreparedStatement prepareStatement(final String sql, final int resultSetType, final int resultSetConcurrency,
283 final int resultSetHoldability) throws SQLException {
284 checkOpen();
285 try {
286 return new DelegatingPreparedStatement(this,
287 pooledConnection.prepareStatement(sql, resultSetType, resultSetConcurrency, resultSetHoldability));
288 } catch (final SQLException e) {
289 handleException(e);
290 return null;
291 }
292 }
293
294 @Override
295 public PreparedStatement prepareStatement(final String sql, final int[] columnIndexes) throws SQLException {
296 checkOpen();
297 try {
298 return new DelegatingPreparedStatement(this, pooledConnection.prepareStatement(sql, columnIndexes));
299 } catch (final SQLException e) {
300 handleException(e);
301 return null;
302 }
303 }
304
305 @Override
306 public PreparedStatement prepareStatement(final String sql, final String[] columnNames) throws SQLException {
307 checkOpen();
308 try {
309 return new DelegatingPreparedStatement(this, pooledConnection.prepareStatement(sql, columnNames));
310 } catch (final SQLException e) {
311 handleException(e);
312 return null;
313 }
314 }
315
316 }