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}