1. /*
  2. * Copyright 2002-2004 the original author or authors.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. package org.springframework.jdbc.support.nativejdbc;
  17. import java.sql.Connection;
  18. import java.sql.SQLException;
  19. import org.apache.commons.logging.Log;
  20. import org.apache.commons.logging.LogFactory;
  21. /**
  22. * Simple implementation of the NativeJdbcExtractor interface.
  23. * Assumes a pool that wraps Connection handles but not DatabaseMetaData:
  24. * In this case, the underlying native Connection can be retrieved by simply
  25. * calling <code>conHandle.getMetaData().getConnection()</code>.
  26. * All other JDBC objects will be returned as passed in.
  27. *
  28. * <p>This extractor should work with any pool that does not wrap DatabaseMetaData,
  29. * and will also work with any plain JDBC driver. Note that a pool can still wrap
  30. * Statements, PreparedStatements, etc: The only requirement of this extractor is
  31. * that java.sql.DatabaseMetaData does not get wrapped, returning the native
  32. * Connection of the JDBC driver on <code>metaData.getConnection()</code>.
  33. *
  34. * <p>Customize this extractor by setting the "nativeConnectionNecessaryForXxx"
  35. * flags accordingly: If Statements, PreparedStatements, and/or CallableStatements
  36. * are wrapped by your pool, set the corresponding "nativeConnectionNecessaryForXxx"
  37. * flags to true. If none of the statement types is wrapped - or you solely need
  38. * Connection unwrapping in the first place -, the defaults are fine.
  39. *
  40. * <p>SimpleNativeJdbcExtractor is a common choice for use with OracleLobHandler,
  41. * which just needs Connection unwrapping via the
  42. * <code>getNativeConnectionFromStatement</code> method. This usage will work
  43. * with almost any connection pool. Known to work are, for example:
  44. * <ul>
  45. * <li>Resin (2.1 and 3.0)
  46. * <li>C3P0
  47. * <li>Jakarta Commons DBCP
  48. * </ul>
  49. *
  50. * <p>For full usage with JdbcTemplate:
  51. * <ul>
  52. * <li>Use a default SimpleNativeJdbcExtractor for Resin (no JDBC Statement
  53. * objects are wrapped, therefore no special unwrapping is necessary)
  54. * <li>Use a SimpleNativeJdbcExtractor with all "nativeConnectionNecessaryForXxx"
  55. * flags set to true for C3P0 (all JDBC Statement objects are wrapped, but none
  56. * of the wrappers allow for unwrapping)
  57. * <li>Use a CommonsDbcpNativeJdbcExtractor for Jakarta Commons DBCP (all JDBC
  58. * Statement objects are wrapped, but all of them can be extracted by casting
  59. * to DBCP implementation classes)
  60. * </ul>
  61. *
  62. * @author Juergen Hoeller
  63. * @since 05.12.2003
  64. * @see java.sql.Statement#getConnection
  65. * @see org.springframework.jdbc.core.JdbcTemplate#setNativeJdbcExtractor
  66. * @see org.springframework.jdbc.support.lob.OracleLobHandler#setNativeJdbcExtractor
  67. * @see #getNativeConnectionFromStatement
  68. * @see #getNativeConnection
  69. */
  70. public class SimpleNativeJdbcExtractor extends NativeJdbcExtractorAdapter {
  71. protected final Log logger = LogFactory.getLog(getClass());
  72. private boolean nativeConnectionNecessaryForNativeStatements = false;
  73. private boolean nativeConnectionNecessaryForNativePreparedStatements = false;
  74. private boolean nativeConnectionNecessaryForNativeCallableStatements = false;
  75. /**
  76. * Set whether it is necessary to work on the native Connection to
  77. * receive native Statements. Default is false. If true, the Connection
  78. * will be unwrapped first to create a Statement.
  79. * <p>This makes sense if you need to work with native Statements from
  80. * a pool that does not allow to extract the native JDBC objects from its
  81. * wrappers but returns the native Connection on DatabaseMetaData.getConnection.
  82. * <p>The standard SimpleNativeJdbcExtractor is unable to unwrap statements,
  83. * so set this to true if your connection pool wraps Statements.
  84. * @see java.sql.Connection#createStatement
  85. * @see java.sql.DatabaseMetaData#getConnection
  86. */
  87. public void setNativeConnectionNecessaryForNativeStatements(boolean nativeConnectionNecessaryForNativeStatements) {
  88. this.nativeConnectionNecessaryForNativeStatements = nativeConnectionNecessaryForNativeStatements;
  89. }
  90. public boolean isNativeConnectionNecessaryForNativeStatements() {
  91. return nativeConnectionNecessaryForNativeStatements;
  92. }
  93. /**
  94. * Set whether it is necessary to work on the native Connection to
  95. * receive native PreparedStatements. Default is false. If true,
  96. * the Connection will be unwrapped first to create a PreparedStatement.
  97. * <p>This makes sense if you need to work with native PreparedStatements from
  98. * a pool that does not allow to extract the native JDBC objects from its
  99. * wrappers but returns the native Connection on Statement.getConnection.
  100. * <p>The standard SimpleNativeJdbcExtractor is unable to unwrap statements,
  101. * so set this to true if your connection pool wraps PreparedStatements.
  102. * @see java.sql.Connection#prepareStatement
  103. * @see java.sql.DatabaseMetaData#getConnection
  104. */
  105. public void setNativeConnectionNecessaryForNativePreparedStatements(boolean nativeConnectionNecessary) {
  106. this.nativeConnectionNecessaryForNativePreparedStatements = nativeConnectionNecessary;
  107. }
  108. public boolean isNativeConnectionNecessaryForNativePreparedStatements() {
  109. return nativeConnectionNecessaryForNativePreparedStatements;
  110. }
  111. /**
  112. * Set whether it is necessary to work on the native Connection to
  113. * receive native CallableStatements. Default is false. If true,
  114. * the Connection will be unwrapped first to create a CallableStatement.
  115. * <p>This makes sense if you need to work with native CallableStatements from
  116. * a pool that does not allow to extract the native JDBC objects from its
  117. * wrappers but returns the native Connection on Statement.getConnection.
  118. * <p>The standard SimpleNativeJdbcExtractor is unable to unwrap statements,
  119. * so set this to true if your connection pool wraps CallableStatements.
  120. * @see java.sql.Connection#prepareCall
  121. * @see java.sql.DatabaseMetaData#getConnection
  122. */
  123. public void setNativeConnectionNecessaryForNativeCallableStatements(boolean nativeConnectionNecessary) {
  124. this.nativeConnectionNecessaryForNativeCallableStatements = nativeConnectionNecessary;
  125. }
  126. public boolean isNativeConnectionNecessaryForNativeCallableStatements() {
  127. return nativeConnectionNecessaryForNativeCallableStatements;
  128. }
  129. /**
  130. * Retrieve the Connection via the DatabaseMetaData object, which will
  131. * result in the native JDBC Connection with many connection pools.
  132. * @see java.sql.DatabaseMetaData#getConnection
  133. */
  134. public Connection getNativeConnection(Connection con) throws SQLException {
  135. Connection nativeCon = con.getMetaData().getConnection();
  136. if (logger.isDebugEnabled()) {
  137. logger.debug("Returning native Connection [" + nativeCon + "] for given Connection handle [" + con + "]");
  138. }
  139. return nativeCon;
  140. }
  141. }