001: /*
002: * Copyright 2002-2006 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: * http://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:
017: package org.springframework.jdbc.support.nativejdbc;
018:
019: import java.sql.CallableStatement;
020: import java.sql.Connection;
021: import java.sql.DatabaseMetaData;
022: import java.sql.PreparedStatement;
023: import java.sql.ResultSet;
024: import java.sql.SQLException;
025: import java.sql.Statement;
026:
027: import org.springframework.jdbc.datasource.DataSourceUtils;
028:
029: /**
030: * Abstract adapter class for the 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</code> checks for a ConnectionProxy chain,
035: * for example from a TransactionAwareDataSourceProxy, before delegating to
036: * <code>doGetNativeConnection</code> 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</code> 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()</code> 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()</code>.
047: *
048: * <p>The <code>getNativeConnectionFromStatement</code> method is implemented
049: * to simply delegate to <code>getNativeConnection</code> 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: */
059: public abstract class NativeJdbcExtractorAdapter implements
060: NativeJdbcExtractor {
061:
062: /**
063: * Return <code>false</code> by default.
064: */
065: public boolean isNativeConnectionNecessaryForNativeStatements() {
066: return false;
067: }
068:
069: /**
070: * Return <code>false</code> by default.
071: */
072: public boolean isNativeConnectionNecessaryForNativePreparedStatements() {
073: return false;
074: }
075:
076: /**
077: * Return <code>false</code> by default.
078: */
079: public boolean isNativeConnectionNecessaryForNativeCallableStatements() {
080: return false;
081: }
082:
083: /**
084: * Check for a ConnectionProxy chain, then delegate to doGetNativeConnection.
085: * <p>ConnectionProxy is used by Spring's TransactionAwareDataSourceProxy
086: * and LazyConnectionDataSourceProxy. The target connection behind it is
087: * typically one from a local connection pool, to be unwrapped by the
088: * doGetNativeConnection implementation of a concrete subclass.
089: * @see #doGetNativeConnection
090: * @see org.springframework.jdbc.datasource.ConnectionProxy
091: * @see org.springframework.jdbc.datasource.DataSourceUtils#getTargetConnection
092: * @see org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy
093: * @see org.springframework.jdbc.datasource.LazyConnectionDataSourceProxy
094: */
095: public Connection getNativeConnection(Connection con)
096: throws SQLException {
097: if (con == null) {
098: return null;
099: }
100: Connection targetCon = DataSourceUtils.getTargetConnection(con);
101: Connection nativeCon = doGetNativeConnection(targetCon);
102: if (nativeCon == targetCon) {
103: // We haven't received a different Connection, so we'll assume that there's
104: // some additional proxying going on. Let's check whether we get something
105: // different back from the DatabaseMetaData.getConnection() call.
106: DatabaseMetaData metaData = targetCon.getMetaData();
107: // The following check is only really there for mock Connections
108: // which might not carry a DatabaseMetaData instance.
109: if (metaData != null) {
110: Connection metaCon = metaData.getConnection();
111: if (metaCon != targetCon) {
112: // We've received a different Connection there:
113: // Let's retry the native extraction process with it.
114: nativeCon = doGetNativeConnection(metaCon);
115: }
116: }
117: }
118: return nativeCon;
119: }
120:
121: /**
122: * Not able to unwrap: return passed-in Connection.
123: */
124: protected Connection doGetNativeConnection(Connection con)
125: throws SQLException {
126: return con;
127: }
128:
129: /**
130: * Retrieve the Connection via the Statement's Connection.
131: * @see #getNativeConnection
132: * @see Statement#getConnection
133: */
134: public Connection getNativeConnectionFromStatement(Statement stmt)
135: throws SQLException {
136: if (stmt == null) {
137: return null;
138: }
139: return getNativeConnection(stmt.getConnection());
140: }
141:
142: /**
143: * Not able to unwrap: return passed-in Statement.
144: */
145: public Statement getNativeStatement(Statement stmt)
146: throws SQLException {
147: return stmt;
148: }
149:
150: /**
151: * Not able to unwrap: return passed-in PreparedStatement.
152: */
153: public PreparedStatement getNativePreparedStatement(
154: PreparedStatement ps) throws SQLException {
155: return ps;
156: }
157:
158: /**
159: * Not able to unwrap: return passed-in CallableStatement.
160: */
161: public CallableStatement getNativeCallableStatement(
162: CallableStatement cs) throws SQLException {
163: return cs;
164: }
165:
166: /**
167: * Not able to unwrap: return passed-in ResultSet.
168: */
169: public ResultSet getNativeResultSet(ResultSet rs)
170: throws SQLException {
171: return rs;
172: }
173:
174: }
|