Browse Source

added configurable Connection/Statement/ResultSet target types to Jdbc4NativeJdbcExtractor (SPR-7613); added OracleJdbc4NativeJdbcExtractor with pre-configured Oracle JDBC API types

pull/1234/head
Juergen Hoeller 15 years ago
parent
commit
ccded10d86
  1. 38
      org.springframework.jdbc/src/main/java/org/springframework/jdbc/support/lob/OracleLobHandler.java
  2. 71
      org.springframework.jdbc/src/main/java/org/springframework/jdbc/support/nativejdbc/Jdbc4NativeJdbcExtractor.java
  3. 60
      org.springframework.jdbc/src/main/java/org/springframework/jdbc/support/nativejdbc/OracleJdbc4NativeJdbcExtractor.java
  4. 1
      org.springframework.jdbc/template.mf

38
org.springframework.jdbc/src/main/java/org/springframework/jdbc/support/lob/OracleLobHandler.java

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2008 the original author or authors. * Copyright 2002-2010 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -122,6 +122,7 @@ public class OracleLobHandler extends AbstractLobHandler {
* See SimpleNativeJdbcExtractor's javadoc for details. * See SimpleNativeJdbcExtractor's javadoc for details.
* @see org.springframework.jdbc.support.nativejdbc.NativeJdbcExtractor#getNativeConnectionFromStatement * @see org.springframework.jdbc.support.nativejdbc.NativeJdbcExtractor#getNativeConnectionFromStatement
* @see org.springframework.jdbc.support.nativejdbc.SimpleNativeJdbcExtractor * @see org.springframework.jdbc.support.nativejdbc.SimpleNativeJdbcExtractor
* @see org.springframework.jdbc.support.nativejdbc.OracleJdbc4NativeJdbcExtractor
* @see oracle.jdbc.OracleConnection * @see oracle.jdbc.OracleConnection
*/ */
public void setNativeJdbcExtractor(NativeJdbcExtractor nativeJdbcExtractor) { public void setNativeJdbcExtractor(NativeJdbcExtractor nativeJdbcExtractor) {
@ -144,20 +145,16 @@ public class OracleLobHandler extends AbstractLobHandler {
* Set whether to agressively release any resources used by the LOB. If set to <code>true</code> * Set whether to agressively release any resources used by the LOB. If set to <code>true</code>
* then you can only read the LOB values once. Any subsequent reads will fail since the resources * then you can only read the LOB values once. Any subsequent reads will fail since the resources
* have been closed. * have been closed.
*
* <p>Setting this property to <code>true</code> can be useful when your queries generates large * <p>Setting this property to <code>true</code> can be useful when your queries generates large
* temporary LOBs that occupy space in the TEMPORARY tablespace or when you want to free up any * temporary LOBs that occupy space in the TEMPORARY tablespace or when you want to free up any
* memory allocated by the driver for the LOB reading. * memory allocated by the driver for the LOB reading.
*
* <p>Default is <code>false</code>. * <p>Default is <code>false</code>.
*
* @see oracle.sql.BLOB#freeTemporary * @see oracle.sql.BLOB#freeTemporary
* @see oracle.sql.CLOB#freeTemporary * @see oracle.sql.CLOB#freeTemporary
* @see oracle.sql.BLOB#open * @see oracle.sql.BLOB#open
* @see oracle.sql.CLOB#open * @see oracle.sql.CLOB#open
* @see oracle.sql.BLOB#close * @see oracle.sql.BLOB#close
* @see oracle.sql.CLOB#close * @see oracle.sql.CLOB#close
* @since 3.0
*/ */
public void setReleaseResourcesAfterRead(boolean releaseResources) { public void setReleaseResourcesAfterRead(boolean releaseResources) {
this.releaseResourcesAfterRead = releaseResources; this.releaseResourcesAfterRead = releaseResources;
@ -258,27 +255,25 @@ public class OracleLobHandler extends AbstractLobHandler {
/** /**
* Initialize any LOB resources before a read is done. * Initialize any LOB resources before a read is done.
* * <p>This implementation calls <code>BLOB.open(BLOB.MODE_READONLY)</code> or
* <p>This implementation calls * <code>CLOB.open(CLOB.MODE_READONLY)</code> on any non-temporary LOBs if
* <code>BLOB.open(BLOB.MODE_READONLY)</code> or <code>CLOB.open(CLOB.MODE_READONLY)</code> * <code>releaseResourcesAfterRead</code> property is set to <code>true</code>.
* on any non-temporary LOBs
* if <code>releaseResourcesAfterRead</code> property is set to <code>true</code>.
* <p>This method can be overridden by sublcasses if different behavior is desired. * <p>This method can be overridden by sublcasses if different behavior is desired.
* @param con the connection to be usde for initilization * @param con the connection to be usde for initilization
* @param lob the LOB to initialize * @param lob the LOB to initialize
*/ */
protected void initializeResourcesBeforeRead(Connection con, Object lob) { protected void initializeResourcesBeforeRead(Connection con, Object lob) {
if (releaseResourcesAfterRead) { if (this.releaseResourcesAfterRead) {
initOracleDriverClasses(con); initOracleDriverClasses(con);
try { try {
/* /*
if (!((BLOB)lob.isTemporary() { if (!((BLOB) lob.isTemporary() {
*/ */
Method isTemporary = lob.getClass().getMethod("isTemporary"); Method isTemporary = lob.getClass().getMethod("isTemporary");
Boolean temporary = (Boolean) isTemporary.invoke(lob); Boolean temporary = (Boolean) isTemporary.invoke(lob);
if (!temporary) { if (!temporary) {
/* /*
((BLOB)lob).open(BLOB.MODE_READONLY); ((BLOB) lob).open(BLOB.MODE_READONLY);
*/ */
Method open = lob.getClass().getMethod("open", int.class); Method open = lob.getClass().getMethod("open", int.class);
open.invoke(lob, modeReadOnlyConstants.get(lob.getClass())); open.invoke(lob, modeReadOnlyConstants.get(lob.getClass()));
@ -295,44 +290,42 @@ public class OracleLobHandler extends AbstractLobHandler {
/** /**
* Release any LOB resources after read is complete. * Release any LOB resources after read is complete.
*
* <p>If <code>releaseResourcesAfterRead</code> property is set to <code>true</code> * <p>If <code>releaseResourcesAfterRead</code> property is set to <code>true</code>
* then this implementation calls * then this implementation calls
* <code>BLOB.close()</code> or <code>CLOB.close()</code> * <code>BLOB.close()</code> or <code>CLOB.close()</code>
* on any non-temporary LOBs that are open or * on any non-temporary LOBs that are open or
* <code>BLOB.freeTemporary()</code> or <code>CLOB.freeTemporary()</code> * <code>BLOB.freeTemporary()</code> or <code>CLOB.freeTemporary()</code>
* on any temporary LOBs. * on any temporary LOBs.
*
* <p>This method can be overridden by sublcasses if different behavior is desired. * <p>This method can be overridden by sublcasses if different behavior is desired.
* @param con the connection to be usde for initilization * @param con the connection to be usde for initilization
* @param lob the LOB to initialize * @param lob the LOB to initialize
*/ */
protected void releaseResourcesAfterRead(Connection con, Object lob) { protected void releaseResourcesAfterRead(Connection con, Object lob) {
if (releaseResourcesAfterRead) { if (this.releaseResourcesAfterRead) {
initOracleDriverClasses(con); initOracleDriverClasses(con);
Boolean temporary = Boolean.FALSE; Boolean temporary = Boolean.FALSE;
try { try {
/* /*
if (((BLOB)lob.isTemporary() { if (((BLOB) lob.isTemporary() {
*/ */
Method isTemporary = lob.getClass().getMethod("isTemporary"); Method isTemporary = lob.getClass().getMethod("isTemporary");
temporary = (Boolean) isTemporary.invoke(lob); temporary = (Boolean) isTemporary.invoke(lob);
if (temporary) { if (temporary) {
/* /*
((BLOB)lob).freeTemporary(); ((BLOB) lob).freeTemporary();
*/ */
Method freeTemporary = lob.getClass().getMethod("freeTemporary"); Method freeTemporary = lob.getClass().getMethod("freeTemporary");
freeTemporary.invoke(lob); freeTemporary.invoke(lob);
} }
else { else {
/* /*
if (((BLOB)lob.isOpen() { if (((BLOB) lob.isOpen() {
*/ */
Method isOpen = lob.getClass().getMethod("isOpen"); Method isOpen = lob.getClass().getMethod("isOpen");
Boolean open = (Boolean) isOpen.invoke(lob); Boolean open = (Boolean) isOpen.invoke(lob);
if (open) { if (open) {
/* /*
((BLOB)lob).close(); ((BLOB) lob).close();
*/ */
Method close = lob.getClass().getMethod("close"); Method close = lob.getClass().getMethod("close");
close.invoke(lob); close.invoke(lob);
@ -358,6 +351,7 @@ public class OracleLobHandler extends AbstractLobHandler {
} }
} }
/** /**
* LobCreator implementation for Oracle databases. * LobCreator implementation for Oracle databases.
* Creates Oracle-style temporary BLOBs and CLOBs that it frees on close. * Creates Oracle-style temporary BLOBs and CLOBs that it frees on close.
@ -529,8 +523,8 @@ public class OracleLobHandler extends AbstractLobHandler {
protected Connection getOracleConnection(PreparedStatement ps) protected Connection getOracleConnection(PreparedStatement ps)
throws SQLException, ClassNotFoundException { throws SQLException, ClassNotFoundException {
return (nativeJdbcExtractor != null) ? return (nativeJdbcExtractor != null ?
nativeJdbcExtractor.getNativeConnectionFromStatement(ps) : ps.getConnection(); nativeJdbcExtractor.getNativeConnectionFromStatement(ps) : ps.getConnection());
} }
/** /**

71
org.springframework.jdbc/src/main/java/org/springframework/jdbc/support/nativejdbc/Jdbc4NativeJdbcExtractor.java

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2007 the original author or authors. * Copyright 2002-2010 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -26,10 +26,16 @@ import java.sql.Statement;
/** /**
* {@link NativeJdbcExtractor} implementation that delegates to JDBC 4.0's * {@link NativeJdbcExtractor} implementation that delegates to JDBC 4.0's
* <code>unwrap</code> method, as defined by {@link java.sql.Wrapper}. * <code>unwrap</code> method, as defined by {@link java.sql.Wrapper}.
* You will typically need to specify a vendor {@link #setConnectionType Connection type}
* / {@link #setStatementType Statement type} / {@link #setResultSetType ResultSet type}
* to extract, since JDBC 4.0 only actually unwraps to a given target type.
* *
* <p>Note: Only use this when actually running against a JDBC 4.0 driver, * <p>Note: Only use this when actually running against a JDBC 4.0 driver, with a
* with a connection pool that supports the JDBC 4.0 API (i.e. at least accepts * connection pool that supports the JDBC 4.0 API (i.e. at least accepts JDBC 4.0
* JDBC 4.0 API calls and passes them through to the underlying driver)! * API calls and passes them through to the underlying driver)! Other than that,
* there is no need for connection pool specific setup. As of JDBC 4.0,
* NativeJdbcExtractors will typically be implemented for specific drivers
* instead of for specific pools (e.g. {@link OracleJdbc4NativeJdbcExtractor}).
* *
* @author Juergen Hoeller * @author Juergen Hoeller
* @since 2.5 * @since 2.5
@ -40,29 +46,76 @@ import java.sql.Statement;
*/ */
public class Jdbc4NativeJdbcExtractor extends NativeJdbcExtractorAdapter { public class Jdbc4NativeJdbcExtractor extends NativeJdbcExtractorAdapter {
private Class<? extends Connection> connectionType = Connection.class;
private Class<? extends Statement> statementType = Statement.class;
private Class<? extends PreparedStatement> preparedStatementType = PreparedStatement.class;
private Class<? extends CallableStatement> callableStatementType = CallableStatement.class;
private Class<? extends ResultSet> resultSetType = ResultSet.class;
/**
* Set the vendor's Connection type, e.g. <code>oracle.jdbc.OracleConnection</code>.
*/
public void setConnectionType(Class<? extends Connection> connectionType) {
this.connectionType = connectionType;
}
/**
* Set the vendor's Statement type, e.g. <code>oracle.jdbc.OracleStatement</code>.
*/
public void setStatementType(Class<? extends Statement> statementType) {
this.statementType = statementType;
}
/**
* Set the vendor's PreparedStatement type, e.g. <code>oracle.jdbc.OraclePreparedStatement</code>.
*/
public void setPreparedStatementType(Class<? extends PreparedStatement> preparedStatementType) {
this.preparedStatementType = preparedStatementType;
}
/**
* Set the vendor's CallableStatement type, e.g. <code>oracle.jdbc.OracleCallableStatement</code>.
*/
public void setCallableStatementType(Class<? extends CallableStatement> callableStatementType) {
this.callableStatementType = callableStatementType;
}
/**
* Set the vendor's ResultSet type, e.g. <code>oracle.jdbc.OracleResultSet</code>.
*/
public void setResultSetType(Class<? extends ResultSet> resultSetType) {
this.resultSetType = resultSetType;
}
@Override @Override
protected Connection doGetNativeConnection(Connection con) throws SQLException { protected Connection doGetNativeConnection(Connection con) throws SQLException {
return (Connection) con.unwrap(Connection.class); return con.unwrap(this.connectionType);
} }
@Override @Override
public Statement getNativeStatement(Statement stmt) throws SQLException { public Statement getNativeStatement(Statement stmt) throws SQLException {
return (Statement) stmt.unwrap(Statement.class); return stmt.unwrap(this.statementType);
} }
@Override @Override
public PreparedStatement getNativePreparedStatement(PreparedStatement ps) throws SQLException { public PreparedStatement getNativePreparedStatement(PreparedStatement ps) throws SQLException {
return (PreparedStatement) ps.unwrap(PreparedStatement.class); return ps.unwrap(this.preparedStatementType);
} }
@Override @Override
public CallableStatement getNativeCallableStatement(CallableStatement cs) throws SQLException { public CallableStatement getNativeCallableStatement(CallableStatement cs) throws SQLException {
return (CallableStatement) cs.unwrap(CallableStatement.class); return cs.unwrap(this.callableStatementType);
} }
@Override @Override
public ResultSet getNativeResultSet(ResultSet rs) throws SQLException { public ResultSet getNativeResultSet(ResultSet rs) throws SQLException {
return (ResultSet) rs.unwrap(ResultSet.class); return rs.unwrap(this.resultSetType);
} }
} }

60
org.springframework.jdbc/src/main/java/org/springframework/jdbc/support/nativejdbc/OracleJdbc4NativeJdbcExtractor.java

@ -0,0 +1,60 @@
/*
* Copyright 2002-2010 the original author or authors.
*
* Licensed 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.springframework.jdbc.support.nativejdbc;
import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Statement;
/**
* A {@link Jdbc4NativeJdbcExtractor} which comes pre-configured for Oracle's JDBC driver,
* specifying the following vendor-specific API types for unwrapping:
* <ul>
* <li><code>oracle.jdbc.OracleConnection</code>
* <li><code>oracle.jdbc.OracleStatement</code>
* <li><code>oracle.jdbc.OraclePreparedStatement</code>
* <li><code>oracle.jdbc.OracleCallableStatement</code>
* <li><code>oracle.jdbc.OracleResultSet</code>
* </ul>
*
* <p>Note: This will work with any JDBC 4.0 compliant connection pool, without a need for
* connection pool specific setup. In other words, as of JDBC 4.0, NativeJdbcExtractors
* will typically be implemented for specific drivers instead of for specific pools.
*
* @author Juergen Hoeller
* @since 3.0.5
*/
public class OracleJdbc4NativeJdbcExtractor extends Jdbc4NativeJdbcExtractor {
@SuppressWarnings("unchecked")
public OracleJdbc4NativeJdbcExtractor() {
try {
setConnectionType((Class<Connection>) getClass().getClassLoader().loadClass("oracle.jdbc.OracleConnection"));
setStatementType((Class<Statement>) getClass().getClassLoader().loadClass("oracle.jdbc.OracleStatement"));
setPreparedStatementType((Class<PreparedStatement>) getClass().getClassLoader().loadClass("oracle.jdbc.OraclePreparedStatement"));
setCallableStatementType((Class<CallableStatement>) getClass().getClassLoader().loadClass("oracle.jdbc.OracleCallableStatement"));
setResultSetType((Class<ResultSet>) getClass().getClassLoader().loadClass("oracle.jdbc.OracleResultSet"));
}
catch (Exception ex) {
throw new IllegalStateException(
"Could not initialize OracleJdbc4NativeJdbcExtractor because Oracle API classes are not available: " + ex);
}
}
}

1
org.springframework.jdbc/template.mf

@ -5,6 +5,7 @@ Bundle-ManifestVersion: 2
Import-Package: Import-Package:
com.ibm.websphere.rsadapter;version="0";resolution:=optional, com.ibm.websphere.rsadapter;version="0";resolution:=optional,
com.ibm.ws.rsadapter.jdbc;version="0";resolution:=optional, com.ibm.ws.rsadapter.jdbc;version="0";resolution:=optional,
oracle.jdbc;version="0";resolution:=optional,
oracle.sql;version="0";resolution:=optional, oracle.sql;version="0";resolution:=optional,
org.h2;version="[1.8.0, 2.0.0)";resolution:=optional, org.h2;version="[1.8.0, 2.0.0)";resolution:=optional,
org.hsqldb;version="[1.0.0, 2.0.0)";resolution:=optional, org.hsqldb;version="[1.0.0, 2.0.0)";resolution:=optional,

Loading…
Cancel
Save