segunda-feira, 17 de julho de 2006

JBoss WrappedConnection

No JBoss, quando obtemos uma conexão de banco de dados de um Datasource, obtemos um objeto da classe org.jboss.resource.adapter.jdbc.WrappedConnection, que é uma classe que implementa a interface java.sql.Connection.

No entanto, ao utilizar algumas operações específicas da implementação do JDBC da Oracle, me deparei com a seguinte exceção:

java.lang.ClassCastException: org.jboss.resource.adapter.jdbc.WrappedConnection

Pelo que pude entender isto ocorre porque estas operações específicas esperam um objeto conexão do tipo oracle.jdbc.driver.OracleConnection. No entanto, a conexão devolvida pelo Datasource é deste tipo, uma vez que estou usando um banco de dados Oracle (pois é leitor, não iria tentar usar o JDBC da Oracle com outro banco). O que o JBoss faz é encapsular este objeto dentro do objeto WrappedConnection. Desta forma, é possível obter o objeto OracleConnection e utilizar as funcionalidades desejadas do JDBC da Oracle. Para tanto, escrevi o seguinte código:

public class ConnectionUtilities {
   
    /**
     *
     */
    private static final String WRAPPED_CONNECTION_NAME =
        "org.jboss.resource.adapter.jdbc.WrappedConnection";

    /**
     *
     */
    private static final String GET_UNDERLYING_CONNECTION_METHOD =
        "getUnderlyingConnection";

    /**
     * Se a aplicação estiver rodando dentro do JBoss retorna a conexão encapsulada dentro
     * da conexão obtida pelo JBoss. Caso contrário, retorna a própria conexão dada
     *
     * @param conn A conexão com o banco de dados
     * 
     * @return
     */
    public static Connection getUnderlyingConnection(Connection conn) {
        // Variaveis auxiliares
        Connection underlyingConn = conn;
        ClassLoader cl = null;
        Class wrappedConnectionClass = null;
        Method getUnderlyingConnectionMethod = null;
       
        try {
 
            cl = Thread.currentThread().getContextClassLoader();
            wrappedConnectionClass =  cl.loadClass( WRAPPED_CONNECTION_NAME );
            getUnderlyingConnectionMethod = wrappedConnectionClass.getMethod(
                    GET_UNDERLYING_CONNECTION_METHOD, (Class[]) null );
           
            if( wrappedConnectionClass.isAssignableFrom( conn.getClass() ) ) {
                underlyingConn =
                    (Connection) getUnderlyingConnectionMethod.invoke( conn,
                            (Object[]) null );
            }
        } catch (Exception e) {           
        }
       
        return underlyingConn;
    }

}

Note-se que se este código for utilizado fora do ambiente JBoss ele retorna a própria conexão dada como parâmetro. Desta forma consigo utilizar o mesmo código no ambiente de testes que configurei no Eclipse, e no ambiente de produção com o JBoss.