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.sql.CallableStatement; 020import java.sql.Connection; 021import java.sql.DatabaseMetaData; 022import java.sql.PreparedStatement; 023import java.sql.ResultSet; 024import java.sql.SQLException; 025import java.sql.Statement; 026 027import org.springframework.jdbc.datasource.DataSourceUtils; 028 029/** 030 * Abstract adapter class for the {@link NativeJdbcExtractor} interface, 031 * for simplified implementation of basic extractors. 032 * Basically returns the passed-in JDBC objects on all methods. 033 * 034 * <p>{@code getNativeConnection} checks for a ConnectionProxy chain, 035 * for example from a TransactionAwareDataSourceProxy, before delegating to 036 * {@code doGetNativeConnection} for actual unwrapping. You can override 037 * either of the two for a specific connection pool, but the latter is 038 * recommended to participate in ConnectionProxy unwrapping. 039 * 040 * <p>{@code getNativeConnection} also applies a fallback if the first 041 * native extraction process failed, that is, returned the same Connection as 042 * passed in. It assumes that some additional proxying is going in this case: 043 * Hence, it retrieves the underlying native Connection from the DatabaseMetaData 044 * via {@code conHandle.getMetaData().getConnection()} and retries the native 045 * extraction process based on that Connection handle. This works, for example, 046 * for the Connection proxies exposed by Hibernate 3.1's {@code Session.connection()}. 047 * 048 * <p>The {@code getNativeConnectionFromStatement} method is implemented 049 * to simply delegate to {@code getNativeConnection} with the Statement's 050 * Connection. This is what most extractor implementations will stick to, 051 * unless there's a more efficient version for a specific pool. 052 * 053 * @author Juergen Hoeller 054 * @since 1.1 055 * @see #getNativeConnection 056 * @see #getNativeConnectionFromStatement 057 * @see org.springframework.jdbc.datasource.ConnectionProxy 058 */ 059public abstract class NativeJdbcExtractorAdapter implements NativeJdbcExtractor { 060 061 /** 062 * Return {@code false} by default. 063 */ 064 @Override 065 public boolean isNativeConnectionNecessaryForNativeStatements() { 066 return false; 067 } 068 069 /** 070 * Return {@code false} by default. 071 */ 072 @Override 073 public boolean isNativeConnectionNecessaryForNativePreparedStatements() { 074 return false; 075 } 076 077 /** 078 * Return {@code false} by default. 079 */ 080 @Override 081 public boolean isNativeConnectionNecessaryForNativeCallableStatements() { 082 return false; 083 } 084 085 /** 086 * Check for a ConnectionProxy chain, then delegate to doGetNativeConnection. 087 * <p>ConnectionProxy is used by Spring's TransactionAwareDataSourceProxy 088 * and LazyConnectionDataSourceProxy. The target connection behind it is 089 * typically one from a local connection pool, to be unwrapped by the 090 * doGetNativeConnection implementation of a concrete subclass. 091 * @see #doGetNativeConnection 092 * @see org.springframework.jdbc.datasource.ConnectionProxy 093 * @see org.springframework.jdbc.datasource.DataSourceUtils#getTargetConnection 094 * @see org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy 095 * @see org.springframework.jdbc.datasource.LazyConnectionDataSourceProxy 096 */ 097 @Override 098 public Connection getNativeConnection(Connection con) throws SQLException { 099 if (con == null) { 100 return null; 101 } 102 Connection targetCon = DataSourceUtils.getTargetConnection(con); 103 Connection nativeCon = doGetNativeConnection(targetCon); 104 if (nativeCon == targetCon) { 105 // We haven't received a different Connection, so we'll assume that there's 106 // some additional proxying going on. Let's check whether we get something 107 // different back from the DatabaseMetaData.getConnection() call. 108 DatabaseMetaData metaData = targetCon.getMetaData(); 109 // The following check is only really there for mock Connections 110 // which might not carry a DatabaseMetaData instance. 111 if (metaData != null) { 112 Connection metaCon = metaData.getConnection(); 113 if (metaCon != null && metaCon != targetCon) { 114 // We've received a different Connection there: 115 // Let's retry the native extraction process with it. 116 nativeCon = doGetNativeConnection(metaCon); 117 } 118 } 119 } 120 return nativeCon; 121 } 122 123 /** 124 * Not able to unwrap: return passed-in Connection. 125 */ 126 protected Connection doGetNativeConnection(Connection con) throws SQLException { 127 return con; 128 } 129 130 /** 131 * Retrieve the Connection via the Statement's Connection. 132 * @see #getNativeConnection 133 * @see Statement#getConnection 134 */ 135 @Override 136 public Connection getNativeConnectionFromStatement(Statement stmt) throws SQLException { 137 if (stmt == null) { 138 return null; 139 } 140 return getNativeConnection(stmt.getConnection()); 141 } 142 143 /** 144 * Not able to unwrap: return passed-in Statement. 145 */ 146 @Override 147 public Statement getNativeStatement(Statement stmt) throws SQLException { 148 return stmt; 149 } 150 151 /** 152 * Not able to unwrap: return passed-in PreparedStatement. 153 */ 154 @Override 155 public PreparedStatement getNativePreparedStatement(PreparedStatement ps) throws SQLException { 156 return ps; 157 } 158 159 /** 160 * Not able to unwrap: return passed-in CallableStatement. 161 */ 162 @Override 163 public CallableStatement getNativeCallableStatement(CallableStatement cs) throws SQLException { 164 return cs; 165 } 166 167 /** 168 * Not able to unwrap: return passed-in ResultSet. 169 */ 170 @Override 171 public ResultSet getNativeResultSet(ResultSet rs) throws SQLException { 172 return rs; 173 } 174 175}