/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.tomcat.dbcp.dbcp2.cpdsadapter; import java.sql.CallableStatement; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.SQLException; import org.apache.tomcat.dbcp.dbcp2.DelegatingCallableStatement; import org.apache.tomcat.dbcp.dbcp2.DelegatingConnection; import org.apache.tomcat.dbcp.dbcp2.DelegatingPreparedStatement; /** * This class is the Connection that will be returned from * PooledConnectionImpl.getConnection(). Most methods are wrappers around the JDBC 1.x * Connection. A few exceptions include preparedStatement and close. In accordance with the JDBC * specification this Connection cannot be used after closed() is called. Any further usage will result in an * SQLException. *

* ConnectionImpl extends DelegatingConnection to enable access to the underlying connection. *

* * @since 2.0 */ class ConnectionImpl extends DelegatingConnection { private final boolean accessToUnderlyingConnectionAllowed; /** The object that instantiated this object */ private final PooledConnectionImpl pooledConnection; /** * Creates a ConnectionImpl. * * @param pooledConnection * The PooledConnection that is calling the ctor. * @param connection * The JDBC 1.x Connection to wrap. * @param accessToUnderlyingConnectionAllowed * if true, then access is allowed to the underlying connection */ ConnectionImpl(final PooledConnectionImpl pooledConnection, final Connection connection, final boolean accessToUnderlyingConnectionAllowed) { super(connection); this.pooledConnection = pooledConnection; this.accessToUnderlyingConnectionAllowed = accessToUnderlyingConnectionAllowed; } /** * Marks the Connection as closed, and notifies the pool that the pooled connection is available. *

* In accordance with the JDBC specification this Connection cannot be used after closed() is called. Any further * usage will result in an SQLException. *

* * @throws SQLException * The database connection couldn't be closed. */ @Override public void close() throws SQLException { if (!isClosedInternal()) { try { passivate(); } finally { setClosedInternal(true); pooledConnection.notifyListeners(); } } } /** * If pooling of CallableStatements is turned on in the {@link DriverAdapterCPDS}, a pooled object may * be returned, otherwise delegate to the wrapped JDBC 1.x {@link java.sql.Connection}. * * @param sql * an SQL statement that may contain one or more '?' parameter placeholders. Typically this statement is * specified using JDBC call escape syntax. * @return a default CallableStatement object containing the pre-compiled SQL statement. * @exception SQLException * Thrown if a database access error occurs or this method is called on a closed connection. * @since 2.4.0 */ @Override public CallableStatement prepareCall(final String sql) throws SQLException { checkOpen(); try { return new DelegatingCallableStatement(this, pooledConnection.prepareCall(sql)); } catch (final SQLException e) { handleException(e); // Does not return return null; } } /** * If pooling of CallableStatements is turned on in the {@link DriverAdapterCPDS}, a pooled object may * be returned, otherwise delegate to the wrapped JDBC 1.x {@link java.sql.Connection}. * * @param sql * a String object that is the SQL statement to be sent to the database; may contain on or * more '?' parameters. * @param resultSetType * a result set type; one of ResultSet.TYPE_FORWARD_ONLY, * ResultSet.TYPE_SCROLL_INSENSITIVE, or ResultSet.TYPE_SCROLL_SENSITIVE. * @param resultSetConcurrency * a concurrency type; one of ResultSet.CONCUR_READ_ONLY or * ResultSet.CONCUR_UPDATABLE. * @return a CallableStatement object containing the pre-compiled SQL statement that will produce * ResultSet objects with the given type and concurrency. * @throws SQLException * Thrown if a database access error occurs, this method is called on a closed connection or the given * parameters are not ResultSet constants indicating type and concurrency. * @since 2.4.0 */ @Override public CallableStatement prepareCall(final String sql, final int resultSetType, final int resultSetConcurrency) throws SQLException { checkOpen(); try { return new DelegatingCallableStatement(this, pooledConnection.prepareCall(sql, resultSetType, resultSetConcurrency)); } catch (final SQLException e) { handleException(e); // Does not return return null; } } /** * If pooling of CallableStatements is turned on in the {@link DriverAdapterCPDS}, a pooled object may * be returned, otherwise delegate to the wrapped JDBC 1.x {@link java.sql.Connection}. * * @param sql * a String object that is the SQL statement to be sent to the database; may contain on or * more '?' parameters. * @param resultSetType * one of the following ResultSet constants: ResultSet.TYPE_FORWARD_ONLY, * ResultSet.TYPE_SCROLL_INSENSITIVE, or ResultSet.TYPE_SCROLL_SENSITIVE. * @param resultSetConcurrency * one of the following ResultSet constants: ResultSet.CONCUR_READ_ONLY or * ResultSet.CONCUR_UPDATABLE. * @param resultSetHoldability * one of the following ResultSet constants: ResultSet.HOLD_CURSORS_OVER_COMMIT * or ResultSet.CLOSE_CURSORS_AT_COMMIT. * @return a new CallableStatement object, containing the pre-compiled SQL statement, that will * generate ResultSet objects with the given type, concurrency, and holdability. * @throws SQLException * Thrown if a database access error occurs, this method is called on a closed connection or the given * parameters are not ResultSet constants indicating type, concurrency, and holdability. * @since 2.4.0 */ @Override public CallableStatement prepareCall(final String sql, final int resultSetType, final int resultSetConcurrency, final int resultSetHoldability) throws SQLException { checkOpen(); try { return new DelegatingCallableStatement(this, pooledConnection.prepareCall(sql, resultSetType, resultSetConcurrency, resultSetHoldability)); } catch (final SQLException e) { handleException(e); // Does not return return null; } } /** * If pooling of PreparedStatements is turned on in the {@link DriverAdapterCPDS}, a pooled object may * be returned, otherwise delegate to the wrapped JDBC 1.x {@link java.sql.Connection}. * * @param sql * SQL statement to be prepared * @return the prepared statement * @throws SQLException * if this connection is closed or an error occurs in the wrapped connection. */ @Override public PreparedStatement prepareStatement(final String sql) throws SQLException { checkOpen(); try { return new DelegatingPreparedStatement(this, pooledConnection.prepareStatement(sql)); } catch (final SQLException e) { handleException(e); // Does not return return null; } } /** * If pooling of PreparedStatements is turned on in the {@link DriverAdapterCPDS}, a pooled object may * be returned, otherwise delegate to the wrapped JDBC 1.x {@link java.sql.Connection}. * * @throws SQLException * if this connection is closed or an error occurs in the wrapped connection. */ @Override public PreparedStatement prepareStatement(final String sql, final int resultSetType, final int resultSetConcurrency) throws SQLException { checkOpen(); try { return new DelegatingPreparedStatement(this, pooledConnection.prepareStatement(sql, resultSetType, resultSetConcurrency)); } catch (final SQLException e) { handleException(e); return null; } } @Override public PreparedStatement prepareStatement(final String sql, final int resultSetType, final int resultSetConcurrency, final int resultSetHoldability) throws SQLException { checkOpen(); try { return new DelegatingPreparedStatement(this, pooledConnection.prepareStatement(sql, resultSetType, resultSetConcurrency, resultSetHoldability)); } catch (final SQLException e) { handleException(e); return null; } } @Override public PreparedStatement prepareStatement(final String sql, final int autoGeneratedKeys) throws SQLException { checkOpen(); try { return new DelegatingPreparedStatement(this, pooledConnection.prepareStatement(sql, autoGeneratedKeys)); } catch (final SQLException e) { handleException(e); return null; } } @Override public PreparedStatement prepareStatement(final String sql, final int columnIndexes[]) throws SQLException { checkOpen(); try { return new DelegatingPreparedStatement(this, pooledConnection.prepareStatement(sql, columnIndexes)); } catch (final SQLException e) { handleException(e); return null; } } @Override public PreparedStatement prepareStatement(final String sql, final String columnNames[]) throws SQLException { checkOpen(); try { return new DelegatingPreparedStatement(this, pooledConnection.prepareStatement(sql, columnNames)); } catch (final SQLException e) { handleException(e); return null; } } // // Methods for accessing the delegate connection // /** * If false, getDelegate() and getInnermostDelegate() will return null. * * @return true if access is allowed to the underlying connection * @see ConnectionImpl */ public boolean isAccessToUnderlyingConnectionAllowed() { return accessToUnderlyingConnectionAllowed; } /** * Get the delegated connection, if allowed. * * @return the internal connection, or null if access is not allowed. * @see #isAccessToUnderlyingConnectionAllowed() */ @Override public Connection getDelegate() { if (isAccessToUnderlyingConnectionAllowed()) { return getDelegateInternal(); } return null; } /** * Get the innermost connection, if allowed. * * @return the innermost internal connection, or null if access is not allowed. * @see #isAccessToUnderlyingConnectionAllowed() */ @Override public Connection getInnermostDelegate() { if (isAccessToUnderlyingConnectionAllowed()) { return super.getInnermostDelegateInternal(); } return null; } }