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