mkalen 2005/03/14 18:50:45
Modified: src/java/org/apache/ojb/broker/platforms
PlatformOracle9iImpl.java
PlatformWLOracle9iImpl.java
Log:
Merge with OJB_1_0_RELEASE branch: Add support for Oracle 10g JDBC-driver.
Add generic unwrapping of Connection and PreparedStatement (current
implementation handles large CLOB/BLOB for Oracle 10g, DBPC and P6Spy). Add
(untested) support for BEA WebLogic and deprecate WLOracle9i platform.
Revision Changes Path
1.17 +261 -90
db-ojb/src/java/org/apache/ojb/broker/platforms/PlatformOracle9iImpl.java
Index: PlatformOracle9iImpl.java
===================================================================
RCS file:
/home/cvs/db-ojb/src/java/org/apache/ojb/broker/platforms/PlatformOracle9iImpl.java,v
retrieving revision 1.16
retrieving revision 1.17
diff -u -r1.16 -r1.17
--- PlatformOracle9iImpl.java 14 Mar 2005 22:48:32 -0000 1.16
+++ PlatformOracle9iImpl.java 15 Mar 2005 02:50:45 -0000 1.17
@@ -16,9 +16,7 @@
*/
import org.apache.ojb.broker.metadata.JdbcConnectionDescriptor;
-import org.apache.ojb.broker.metadata.JdbcType;
import org.apache.ojb.broker.util.ClassHelper;
-import org.apache.ojb.broker.util.JdbcTypesHelper;
import org.apache.ojb.broker.util.logging.Logger;
import org.apache.ojb.broker.util.logging.LoggerFactory;
@@ -27,6 +25,7 @@
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
+import java.sql.Statement;
import java.sql.Types;
import java.util.Collections;
import java.util.Map;
@@ -36,6 +35,12 @@
* This class is a concrete implementation of <code>Platform</code>. Provides
* an implementation that uses Oracle specific optimizations and
LOB-handling.
*
+ * NOTE: When using BEA WebLogic and BLOB/CLOB datatypes, the physical
connection will be
+ * used causing WebLogic to mark it as "infected" and discard it when
+ * the logicical connection is closed. You can change this behavior by
setting the
+ * RemoveInfectedConnectionsEnabled attribute on a connection pool.
+ * see <a
href="http://e-docs.bea.com/wls/docs81/jdbc/thirdparty.html#1043646">WebLogic
docs</a>.
+ *
* Optimization: Oracle Batching (not standard JDBC batching)
* see <a
href="http://technet.oracle.com/products/oracle9i/daily/jun07.html">OTN</a>.
*
@@ -82,17 +87,81 @@
protected static final int STATEMENTS_PER_BATCH = 20;
protected static Map m_batchStatementsInProgress =
Collections.synchronizedMap(new WeakHashMap(STATEMENTS_PER_BATCH));
+ protected static final Class[] PARAM_TYPE_EMPTY = {};
protected static final Class[] PARAM_TYPE_INTEGER = {Integer.TYPE};
protected static final Class[] PARAM_TYPE_BOOLEAN = {Boolean.TYPE};
protected static final Class[] PARAM_TYPE_STRING = {String.class};
+ protected static final Object[] PARAM_EMPTY = new Object[]{};
protected static final Object[] PARAM_STATEMENT_CACHE_SIZE = new
Object[]{new Integer(STATEMENT_CACHE_SIZE)};
protected static final Object[] PARAM_ROW_PREFETCH_SIZE = new
Object[]{new Integer(ROW_PREFETCH_SIZE)};
protected static final Object[] PARAM_STATEMENT_BATCH_SIZE = new
Object[]{new Integer(STATEMENTS_PER_BATCH)};
protected static final Object[] PARAM_BOOLEAN_TRUE = new
Object[]{Boolean.TRUE};
- protected static final JdbcType BASE_CLOB =
JdbcTypesHelper.getJdbcTypeByName("clob");
- protected static final JdbcType BASE_BLOB =
JdbcTypesHelper.getJdbcTypeByName("blob");
+ protected static Class ORA_CONN_CLASS;
+ protected static Class ORA_PS_CLASS;
+ protected static Class ORA_CLOB_CLASS;
+ protected static Class ORA_BLOB_CLASS;
+ protected static Class[] PARAM_TYPE_INT_ORACLOB;
+ protected static Class[] PARAM_TYPE_INT_ORABLOB;
+ protected static Method METHOD_SET_STATEMENT_CACHE_SIZE;
+ protected static Method METHOD_SET_IMPLICIT_CACHING_ENABLED;
+ protected static Method METHOD_SET_ROW_PREFETCH;
+ protected static Method METHOD_SET_BLOB = null;
+ protected static Method METHOD_SET_CLOB = null;
+ protected static boolean ORA_STATEMENT_CACHING_AVAILABLE;
+ protected static boolean ORA_ROW_PREFETCH_AVAILABLE;
+ protected static boolean ORA_CLOB_HANDLING_AVAILABLE;
+ protected static boolean ORA_BLOB_HANDLING_AVAILABLE;
+
+ /** Method names used by [EMAIL PROTECTED] #unwrapConnection}. */
+ protected static final String UNWRAP_CONN_METHOD_NAMES[] =
+ {
+ "unwrapCompletely" /* Oracle 10g */,
+ "getInnermostDelegate" /* Commons DBCP */,
+ "getVendorConnection" /* BEA WebLogic */,
+ "getJDBC" /* P6Spy */
+ };
+ /**
+ * Method parameter signature used by [EMAIL PROTECTED]
#unwrapConnection} for corresponding
+ * [EMAIL PROTECTED] #UNWRAP_CONN_METHOD_NAMES}-index.
+ * If signature is not [EMAIL PROTECTED] #PARAM_TYPE_EMPTY}, the actual
connection object
+ * will be passed at runtime. (NB: Requires special handling of param
type in constructor.)
+ */
+ protected static final Class[][] UNWRAP_CONN_PARAM_TYPES =
+ {
+ null /* Index 0 reserved for Oracle 10g - initialized in
constructor */,
+ PARAM_TYPE_EMPTY /* Commons DBCP */,
+ PARAM_TYPE_EMPTY /* BEA WebLogic */,
+ PARAM_TYPE_EMPTY /* P6Spy */
+ };
+ /** Method names used by [EMAIL PROTECTED] #unwrapStatement}. */
+ protected static final String UNWRAP_PS_METHOD_NAMES[] =
+ {
+ "getInnermostDelegate" /* Commons DBCP */,
+ "getJDBC" /* P6Spy */
+ };
+ /**
+ * Method parameter signature used by [EMAIL PROTECTED]
#unwrapStatement} for corresponding
+ * [EMAIL PROTECTED] #UNWRAP_PS_METHOD_NAMES}-index.
+ * If signature is not [EMAIL PROTECTED] #PARAM_TYPE_EMPTY}, the actual
Statement object
+ * will be passed at runtime. (NB: Requires special handling of param
type in constructor.)
+ */
+ protected static final Class[][] UNWRAP_PS_PARAM_TYPES =
+ {
+ PARAM_TYPE_EMPTY /* Commons DBCP */,
+ PARAM_TYPE_EMPTY /* P6Spy */
+ };
+
+
+ /**
+ * Default constructor.
+ * Runs static init needed for Oracle-extensions and large BLOB/CLOB
support to function.
+ */
+ public PlatformOracle9iImpl()
+ {
+ initOracleReflectedVars();
+ }
/**
* Enables Oracle statement caching and row prefetching if supported by
the JDBC-driver.
@@ -104,25 +173,29 @@
* @see <a
href="http://otn.oracle.com/sample_code/tech/java/sqlj_jdbc/files/advanced/RowPrefetchSample/Readme.html">
* Oracle TechNet Row Pre-fetch Sample<a>
*/
- public void initializeJdbcConnection(JdbcConnectionDescriptor jcd,
Connection conn) throws PlatformException
+ public void initializeJdbcConnection(final JdbcConnectionDescriptor jcd,
+ final Connection conn)
+ throws PlatformException
{
// Do all the generic initialization in PlatformDefaultImpl first
super.initializeJdbcConnection(jcd, conn);
- // Check for OracleConnection-specific statement caching methods
- final Method methodSetStatementCacheSize;
- final Method methodSetImplicitCachingEnabled;
- methodSetStatementCacheSize = ClassHelper.getMethod(conn,
"setStatementCacheSize", PARAM_TYPE_INTEGER);
- methodSetImplicitCachingEnabled = ClassHelper.getMethod(conn,
"setImplicitCachingEnabled", PARAM_TYPE_BOOLEAN);
+ // Check if this is a wrapped connection and if so unwrap it
+ final Connection oraConn = unwrapConnection(conn);
+ if (oraConn == null)
+ {
+ return;
+ }
- final boolean statementCachingSupported =
methodSetStatementCacheSize != null && methodSetImplicitCachingEnabled != null;
- if (statementCachingSupported)
+ // At this point we know that we have an OracleConnection instance
and can thus
+ // try to invoke methods via reflection (if available)
+ if (ORA_STATEMENT_CACHING_AVAILABLE)
{
try
{
// Set number of cached statements and enable implicit
caching
- methodSetStatementCacheSize.invoke(conn,
PARAM_STATEMENT_CACHE_SIZE);
- methodSetImplicitCachingEnabled.invoke(conn,
PARAM_BOOLEAN_TRUE);
+ METHOD_SET_STATEMENT_CACHE_SIZE.invoke(oraConn,
PARAM_STATEMENT_CACHE_SIZE);
+ METHOD_SET_IMPLICIT_CACHING_ENABLED.invoke(oraConn,
PARAM_BOOLEAN_TRUE);
}
catch (Exception e)
{
@@ -130,17 +203,12 @@
}
}
- // Check for OracleConnection-specific row pre-fetching support
- final Method methodSetRowPrefetch;
- methodSetRowPrefetch = ClassHelper.getMethod(conn,
"setDefaultRowPrefetch", PARAM_TYPE_INTEGER);
-
- final boolean rowPrefetchingSupported = methodSetRowPrefetch != null;
- if (rowPrefetchingSupported)
+ if (ORA_ROW_PREFETCH_AVAILABLE)
{
try
{
// Set number of prefetched rows
- methodSetRowPrefetch.invoke(conn, PARAM_ROW_PREFETCH_SIZE);
+ METHOD_SET_ROW_PREFETCH.invoke(oraConn,
PARAM_ROW_PREFETCH_SIZE);
}
catch (Exception e)
{
@@ -150,6 +218,18 @@
}
/**
+ * Performs platform-specific operations on each statement.
+ * @param stmt the statement just created
+ */
+ public void afterStatementCreate(Statement stmt)
+ {
+ // mkalen: do NOT call super#afterStatementCreate since escape
processing for SQL92
+ // syntax is enabled by default for Oracle9i and higher,
and explicit calls
+ // to setEscapeProcessing for PreparedStatements will make
Oracle 10g JDBC-
+ // driver throw exceptions (and is functionally useless).
+ }
+
+ /**
* Try Oracle update batching and call setExecuteBatch or revert to
* JDBC update batching. See 12-2 Update Batching in the Oracle9i
* JDBC Developer's Guide and Reference.
@@ -250,45 +330,23 @@
/** @see Platform#setObjectForStatement */
public void setObjectForStatement(PreparedStatement ps, int index,
Object value, int sqlType) throws SQLException
{
- boolean nativeOraBlobsSupported = false;
- boolean nativeOraClobsSupported = false;
- Method methodSetBlob = null;
- Method methodSetClob = null;
-
// Check for Oracle JDBC-driver LOB-support
- if (sqlType == Types.CLOB)
- {
- try
- {
- Class clobClass = ClassHelper.getClass("oracle.sql.CLOB",
false);
- methodSetClob = ClassHelper.getMethod(ps, "setCLOB", new
Class[]{Integer.TYPE, clobClass});
- nativeOraClobsSupported = methodSetClob != null;
- if (!nativeOraClobsSupported && logger.isDebugEnabled())
- {
- logger.debug("Oracle CLOB JDBC extensions not available
for connection " + ps.getConnection().getClass());
- }
- }
- catch (Exception e)
- {
- logger.warn("Exception while checking for Oracle CLOB JDBC
extensions", e);
- }
+ final Statement oraStmt;
+ final Connection oraConn;
+ final boolean oraLargeLobSupportAvailable;
+ if (sqlType == Types.CLOB || sqlType == Types.BLOB)
+ {
+ oraStmt = unwrapStatement(ps);
+ oraConn = unwrapConnection(ps.getConnection());
+ oraLargeLobSupportAvailable =
+ oraStmt != null && oraConn != null &&
+ (sqlType == Types.CLOB ? ORA_CLOB_HANDLING_AVAILABLE :
ORA_BLOB_HANDLING_AVAILABLE);
}
- else if (sqlType == Types.BLOB)
+ else
{
- try
- {
- Class blobClass = ClassHelper.getClass("oracle.sql.BLOB",
false);
- methodSetBlob = ClassHelper.getMethod(ps, "setBLOB", new
Class[]{Integer.TYPE, blobClass});
- nativeOraBlobsSupported = methodSetBlob != null;
- if (!nativeOraBlobsSupported && logger.isDebugEnabled())
- {
- logger.debug("Oracle CLOB JDBC extensions not available
for connection " + ps.getConnection().getClass());
- }
- }
- catch (Exception e)
- {
- logger.warn("Exception while checking for Oracle BLOB JDBC
extensions", e);
- }
+ oraStmt = null;
+ oraConn = null;
+ oraLargeLobSupportAvailable = false;
}
// Type-specific Oracle conversions
@@ -313,48 +371,30 @@
{
ps.setLong(index, ((Long) value).longValue());
}
- else if (sqlType == Types.CLOB && value instanceof String)
+ else if (sqlType == Types.CLOB && oraLargeLobSupportAvailable &&
value instanceof String)
{
- // First try native Oracle CLOB handling
- if (nativeOraClobsSupported)
+ // TODO: If using Oracle update batching with the thin driver,
throw exception on 4k limit
+ try
{
- // TODO: If using Oracle update batching with the thin
driver, throw exception on 4k limit
- try
- {
- Object clob =
Oracle9iLobHandler.createCLOBFromString(ps.getConnection(), (String) value);
- methodSetClob.invoke(ps, new Object[]{new
Integer(index), clob});
- }
- catch (Exception e)
- {
- throw new SQLException(e.getLocalizedMessage());
- }
+ Object clob =
Oracle9iLobHandler.createCLOBFromString(oraConn, (String) value);
+ METHOD_SET_CLOB.invoke(oraStmt, new Object[]{new
Integer(index), clob});
}
- else
- // Fall back to default Oracle platform capabilities
+ catch (Exception e)
{
- super.setObjectForStatement(ps, index, value, sqlType);
+ throw new SQLException(e.getLocalizedMessage());
}
}
- else if (sqlType == Types.BLOB && value instanceof byte[])
+ else if (sqlType == Types.BLOB && oraLargeLobSupportAvailable &&
value instanceof byte[])
{
- // First try native Oracle BLOB handling
- if (nativeOraBlobsSupported)
+ // TODO: If using Oracle update batching with the thin driver,
throw exception on 2k limit
+ try
{
- // TODO: If using Oracle update batching with the thin
driver, throw exception on 2k limit
- try
- {
- Object blob =
Oracle9iLobHandler.createBLOBFromByteArray(ps.getConnection(), (byte[]) value);
- methodSetBlob.invoke(ps, new Object[]{new
Integer(index), blob});
- }
- catch (Exception e)
- {
- throw new SQLException(e.getLocalizedMessage());
- }
+ Object blob =
Oracle9iLobHandler.createBLOBFromByteArray(oraConn, (byte[]) value);
+ METHOD_SET_BLOB.invoke(oraStmt, new Object[]{new
Integer(index), blob});
}
- else
- // Fall back to default Oracle platform capabilities
+ catch (Exception e)
{
- super.setObjectForStatement(ps, index, value, sqlType);
+ throw new SQLException(e.getLocalizedMessage());
}
}
else
@@ -374,4 +414,135 @@
return SQL92_NOPAREN_JOIN_SYNTAX;
}
+ /**
+ * Return an OracleConnection after trying to unwrap from known
Connection wrappers.
+ * @param conn the connection to unwrap (if needed)
+ * @return OracleConnection or null if not able to unwrap
+ */
+ protected Connection unwrapConnection(Connection conn)
+ {
+ final Object unwrapped;
+ unwrapped = genericUnwrap(ORA_CONN_CLASS, conn,
UNWRAP_CONN_METHOD_NAMES, UNWRAP_CONN_PARAM_TYPES);
+ if (unwrapped == null && logger.isDebugEnabled())
+ {
+ // mkalen: only log this as debug since it will be logged for
every connection
+ // (ie only useful during development).
+ logger.debug("PlatformOracle9iImpl could not unwrap " +
conn.getClass().getName() +
+ ", Oracle-extensions disabled.");
+ }
+ return (Connection) unwrapped;
+ }
+
+ /**
+ * Return an OraclePreparedStatement after trying to unwrap from known
Statement wrappers.
+ * @param ps the PreparedStatement to unwrap (if needed)
+ * @return OraclePreparedStatement or null if not able to unwrap
+ */
+ protected Statement unwrapStatement(Statement ps)
+ {
+ final Object unwrapped;
+ unwrapped = genericUnwrap(ORA_PS_CLASS, ps, UNWRAP_PS_METHOD_NAMES,
UNWRAP_PS_PARAM_TYPES);
+ if (unwrapped == null && logger.isDebugEnabled())
+ {
+ // mkalen: only log this as debug since it will be logged for
every connection
+ // (ie only useful during development).
+ logger.debug("PlatformOracle9iImpl could not unwrap " +
ps.getClass().getName() +
+ ", large CLOB/BLOB support disabled.");
+ }
+ return (Statement) unwrapped;
+ }
+
+ protected Object genericUnwrap(Class classToMatch, Object toUnwrap,
+ String[] methodNameCandidates,
+ Class[][] methodTypeCandidates)
+ {
+ if (classToMatch == null)
+ {
+ return null;
+ }
+
+ Object unwrapped;
+ final Class psClass = toUnwrap.getClass();
+ if (classToMatch.isAssignableFrom(psClass))
+ {
+ return toUnwrap;
+ }
+ try
+ {
+ String methodName;
+ Class[] paramTypes;
+ Object[] args;
+ for (int i = 0; i < methodNameCandidates.length; i++)
+ {
+ methodName = methodNameCandidates[i];
+ paramTypes = methodTypeCandidates[i];
+ final Method method = ClassHelper.getMethod(toUnwrap,
methodName, paramTypes);
+ if (method != null)
+ {
+ args = paramTypes == PARAM_TYPE_EMPTY ? PARAM_EMPTY :
new Object[]{ toUnwrap };
+ unwrapped = method.invoke(toUnwrap, args);
+ if (unwrapped != null)
+ {
+ if
(classToMatch.isAssignableFrom(unwrapped.getClass()))
+ {
+ return unwrapped;
+ }
+ // When using eg both DBCP and P6Spy we have to
recursively unwrap
+ return genericUnwrap(classToMatch, unwrapped,
+ methodNameCandidates, methodTypeCandidates);
+ }
+ }
+ }
+ }
+ catch (Exception e)
+ {
+ // ignore
+ if (logger.isDebugEnabled())
+ {
+ logger.debug("genericUnwrap failed", e);
+ }
+ }
+ return null;
+ }
+
+ protected static void initOracleReflectedVars() {
+ try
+ {
+ /*
+ Check for Oracle-specific classes, OracleConnection-specific
+ statement caching/row pre-fetch methods and Oracle BLOB/CLOB
access methods.
+ We can do this in constructor in spite of possible mixing of
instance being
+ able vs unable passed at runtime (since withouth these classes
and methods
+ it's impossible to enable ORA-extensions at all even if
instances are capable).
+ */
+ ORA_CONN_CLASS =
ClassHelper.getClass("oracle.jdbc.OracleConnection", false);
+ ORA_PS_CLASS =
ClassHelper.getClass("oracle.jdbc.OraclePreparedStatement", false);
+ ORA_CLOB_CLASS = ClassHelper.getClass("oracle.sql.CLOB", false);
+ ORA_BLOB_CLASS = ClassHelper.getClass("oracle.sql.BLOB", false);
+ PARAM_TYPE_INT_ORACLOB = new Class[]{ Integer.TYPE,
ORA_CLOB_CLASS };
+ PARAM_TYPE_INT_ORABLOB = new Class[]{ Integer.TYPE,
ORA_BLOB_CLASS };
+
+ // Index 0 reserved for Oracle 10g
+ UNWRAP_CONN_PARAM_TYPES[0] = new Class[]{ ORA_CONN_CLASS };
+
+ METHOD_SET_STATEMENT_CACHE_SIZE =
+ ClassHelper.getMethod(ORA_CONN_CLASS,
"setStatementCacheSize", PARAM_TYPE_INTEGER);
+ METHOD_SET_IMPLICIT_CACHING_ENABLED =
+ ClassHelper.getMethod(ORA_CONN_CLASS,
"setImplicitCachingEnabled", PARAM_TYPE_BOOLEAN);
+ METHOD_SET_ROW_PREFETCH = ClassHelper.getMethod(ORA_CONN_CLASS,
"setDefaultRowPrefetch", PARAM_TYPE_INTEGER);
+ METHOD_SET_CLOB = ClassHelper.getMethod(ORA_PS_CLASS, "setCLOB",
PARAM_TYPE_INT_ORACLOB);
+ METHOD_SET_BLOB = ClassHelper.getMethod(ORA_PS_CLASS, "setBLOB",
PARAM_TYPE_INT_ORABLOB);
+
+ ORA_STATEMENT_CACHING_AVAILABLE =
+ METHOD_SET_STATEMENT_CACHE_SIZE != null &&
METHOD_SET_IMPLICIT_CACHING_ENABLED != null;
+ ORA_ROW_PREFETCH_AVAILABLE = METHOD_SET_ROW_PREFETCH != null;
+ ORA_CLOB_HANDLING_AVAILABLE = METHOD_SET_CLOB != null;
+ ORA_BLOB_HANDLING_AVAILABLE = METHOD_SET_BLOB != null;
+ }
+ catch (ClassNotFoundException e)
+ {
+ // ignore (we tried...)
+ }
+ }
+
}
1.3 +3 -1
db-ojb/src/java/org/apache/ojb/broker/platforms/PlatformWLOracle9iImpl.java
Index: PlatformWLOracle9iImpl.java
===================================================================
RCS file:
/home/cvs/db-ojb/src/java/org/apache/ojb/broker/platforms/PlatformWLOracle9iImpl.java,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -r1.2 -r1.3
--- PlatformWLOracle9iImpl.java 22 May 2004 09:55:33 -0000 1.2
+++ PlatformWLOracle9iImpl.java 15 Mar 2005 02:50:45 -0000 1.3
@@ -58,6 +58,8 @@
* @see PlatformDefaultImpl
* @see PlatformOracleImpl
* @see PlatformOracle9iImpl
+ *
+ * @deprecated since OJB 1.0.2 the default [EMAIL PROTECTED]
PlatformOracle9iImpl} should be usable in WebLogic
*/
public class PlatformWLOracle9iImpl extends PlatformOracleImpl
{
---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]