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.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 }