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.lang.reflect.Method; 020import java.sql.CallableStatement; 021import java.sql.Connection; 022import java.sql.PreparedStatement; 023import java.sql.ResultSet; 024import java.sql.SQLException; 025import java.sql.Statement; 026 027import org.springframework.util.ReflectionUtils; 028 029/** 030 * Implementation of the {@link NativeJdbcExtractor} interface for JBoss, 031 * supporting JBoss Application Server 3.2.4+. As of Spring 3.1.1, it also 032 * supports JBoss 7. 033 * 034 * <p>Returns the underlying native Connection, Statement, etc to 035 * application code instead of JBoss' wrapper implementations. 036 * The returned JDBC classes can then safely be cast, e.g. to 037 * {@code oracle.jdbc.OracleConnection}. 038 * 039 * <p>This NativeJdbcExtractor can be set just to <i>allow</i> working with 040 * a JBoss connection pool: If a given object is not a JBoss wrapper, 041 * it will be returned as-is. 042 * 043 * @author Juergen Hoeller 044 * @since 03.01.2004 045 * @see org.jboss.resource.adapter.jdbc.WrappedConnection#getUnderlyingConnection 046 * @see org.jboss.resource.adapter.jdbc.WrappedStatement#getUnderlyingStatement 047 * @see org.jboss.resource.adapter.jdbc.WrappedResultSet#getUnderlyingResultSet 048 */ 049public class JBossNativeJdbcExtractor extends NativeJdbcExtractorAdapter { 050 051 // JBoss 7 052 private static final String JBOSS_JCA_PREFIX = "org.jboss.jca.adapters.jdbc."; 053 054 // JBoss <= 6 055 private static final String JBOSS_RESOURCE_PREFIX = "org.jboss.resource.adapter.jdbc."; 056 057 058 private Class<?> wrappedConnectionClass; 059 060 private Class<?> wrappedStatementClass; 061 062 private Class<?> wrappedResultSetClass; 063 064 private Method getUnderlyingConnectionMethod; 065 066 private Method getUnderlyingStatementMethod; 067 068 private Method getUnderlyingResultSetMethod; 069 070 071 /** 072 * This constructor retrieves JBoss JDBC wrapper classes, 073 * so we can get the underlying vendor connection using reflection. 074 */ 075 public JBossNativeJdbcExtractor() { 076 String prefix = JBOSS_JCA_PREFIX; 077 try { 078 // trying JBoss 7 jca package first... 079 this.wrappedConnectionClass = getClass().getClassLoader().loadClass(prefix + "WrappedConnection"); 080 } 081 catch (ClassNotFoundException ex) { 082 // JBoss 7 jca package not found -> try traditional resource package. 083 prefix = JBOSS_RESOURCE_PREFIX; 084 try { 085 this.wrappedConnectionClass = getClass().getClassLoader().loadClass(prefix + "WrappedConnection"); 086 } 087 catch (ClassNotFoundException ex2) { 088 throw new IllegalStateException("Could not initialize JBossNativeJdbcExtractor: neither JBoss 7's [" + 089 JBOSS_JCA_PREFIX + ".WrappedConnection] nor traditional JBoss [" + JBOSS_RESOURCE_PREFIX + 090 ".WrappedConnection] found"); 091 } 092 } 093 try { 094 this.wrappedStatementClass = getClass().getClassLoader().loadClass(prefix + "WrappedStatement"); 095 this.wrappedResultSetClass = getClass().getClassLoader().loadClass(prefix + "WrappedResultSet"); 096 this.getUnderlyingConnectionMethod = 097 this.wrappedConnectionClass.getMethod("getUnderlyingConnection", (Class[]) null); 098 this.getUnderlyingStatementMethod = 099 this.wrappedStatementClass.getMethod("getUnderlyingStatement", (Class[]) null); 100 this.getUnderlyingResultSetMethod = 101 this.wrappedResultSetClass.getMethod("getUnderlyingResultSet", (Class[]) null); 102 } 103 catch (Exception ex) { 104 throw new IllegalStateException( 105 "Could not initialize JBossNativeJdbcExtractor because of missing JBoss API methods/classes: " + ex); 106 } 107 } 108 109 110 /** 111 * Retrieve the Connection via JBoss' {@code getUnderlyingConnection} method. 112 */ 113 @Override 114 protected Connection doGetNativeConnection(Connection con) throws SQLException { 115 if (this.wrappedConnectionClass.isAssignableFrom(con.getClass())) { 116 return (Connection) ReflectionUtils.invokeJdbcMethod(this.getUnderlyingConnectionMethod, con); 117 } 118 return con; 119 } 120 121 /** 122 * Retrieve the Connection via JBoss' {@code getUnderlyingStatement} method. 123 */ 124 @Override 125 public Statement getNativeStatement(Statement stmt) throws SQLException { 126 if (this.wrappedStatementClass.isAssignableFrom(stmt.getClass())) { 127 return (Statement) ReflectionUtils.invokeJdbcMethod(this.getUnderlyingStatementMethod, stmt); 128 } 129 return stmt; 130 } 131 132 /** 133 * Retrieve the Connection via JBoss' {@code getUnderlyingStatement} method. 134 */ 135 @Override 136 public PreparedStatement getNativePreparedStatement(PreparedStatement ps) throws SQLException { 137 return (PreparedStatement) getNativeStatement(ps); 138 } 139 140 /** 141 * Retrieve the Connection via JBoss' {@code getUnderlyingStatement} method. 142 */ 143 @Override 144 public CallableStatement getNativeCallableStatement(CallableStatement cs) throws SQLException { 145 return (CallableStatement) getNativeStatement(cs); 146 } 147 148 /** 149 * Retrieve the Connection via JBoss' {@code getUnderlyingResultSet} method. 150 */ 151 @Override 152 public ResultSet getNativeResultSet(ResultSet rs) throws SQLException { 153 if (this.wrappedResultSetClass.isAssignableFrom(rs.getClass())) { 154 return (ResultSet) ReflectionUtils.invokeJdbcMethod(this.getUnderlyingResultSetMethod, rs); 155 } 156 return rs; 157 } 158 159}