001/*
002 * Copyright 2002-2012 the original author or authors.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *      https://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017package org.springframework.jdbc.support.nativejdbc;
018
019import java.lang.reflect.Method;
020import java.sql.Connection;
021import java.sql.SQLException;
022
023import com.mchange.v2.c3p0.C3P0ProxyConnection;
024
025import org.springframework.util.ReflectionUtils;
026
027/**
028 * Implementation of the {@link NativeJdbcExtractor} interface for the
029 * C3P0 connection pool.
030 *
031 * <p>Returns underlying native Connections to application code instead of C3P0's
032 * wrapper implementations; unwraps the Connection for native Statements.
033 * The returned JDBC classes can then safely be cast, e.g. to
034 * {@code oracle.jdbc.OracleConnection}.
035 *
036 * <p>This NativeJdbcExtractor can be set just to <i>allow</i> working with
037 * a C3P0 DataSource: If a given object is not a C3P0 wrapper, it will be
038 * returned as-is.
039 *
040 * <p>Note that this class requires C3P0 0.8.5 or later; for earlier C3P0 versions,
041 * use SimpleNativeJdbcExtractor (which won't work for C3P0 0.8.5 or later).
042 *
043 * @author Juergen Hoeller
044 * @since 1.1.5
045 * @see com.mchange.v2.c3p0.C3P0ProxyConnection#rawConnectionOperation
046 * @see SimpleNativeJdbcExtractor
047 */
048public class C3P0NativeJdbcExtractor extends NativeJdbcExtractorAdapter {
049
050        private final Method getRawConnectionMethod;
051
052
053        /**
054         * This method is not meant to be used directly; it rather serves
055         * as callback method for C3P0's "rawConnectionOperation" API.
056         * @param con a native Connection handle
057         * @return the native Connection handle, as-is
058         */
059        public static Connection getRawConnection(Connection con) {
060                return con;
061        }
062
063
064        public C3P0NativeJdbcExtractor() {
065                try {
066                        this.getRawConnectionMethod = getClass().getMethod("getRawConnection", new Class<?>[] {Connection.class});
067                }
068                catch (NoSuchMethodException ex) {
069                        throw new IllegalStateException("Internal error in C3P0NativeJdbcExtractor: " + ex.getMessage());
070                }
071        }
072
073
074        @Override
075        public boolean isNativeConnectionNecessaryForNativeStatements() {
076                return true;
077        }
078
079        @Override
080        public boolean isNativeConnectionNecessaryForNativePreparedStatements() {
081                return true;
082        }
083
084        @Override
085        public boolean isNativeConnectionNecessaryForNativeCallableStatements() {
086                return true;
087        }
088
089        /**
090         * Retrieve the Connection via C3P0's {@code rawConnectionOperation} API,
091         * using the {@code getRawConnection} as callback to get access to the
092         * raw Connection (which is otherwise not directly supported by C3P0).
093         * @see #getRawConnection
094         */
095        @Override
096        protected Connection doGetNativeConnection(Connection con) throws SQLException {
097                if (con instanceof C3P0ProxyConnection) {
098                        C3P0ProxyConnection cpCon = (C3P0ProxyConnection) con;
099                        try {
100                                return (Connection) cpCon.rawConnectionOperation(
101                                                this.getRawConnectionMethod, null, new Object[] {C3P0ProxyConnection.RAW_CONNECTION});
102                        }
103                        catch (SQLException ex) {
104                                throw ex;
105                        }
106                        catch (Exception ex) {
107                                ReflectionUtils.handleReflectionException(ex);
108                        }
109                }
110                return con;
111        }
112
113}