Extraction d'une connexion native JDBC

1) avec Spring

Ceux qui utilisent Spring connaissent probablement le package org.springframework.jdbc.support.nativejdbc qui contient des extracteurs de connexion.
Voici par exemple comment récupérer une connexion native sous-jacente avec un extracteur Spring :

import javax.sql.DataSource;
import java.sql.Connection;
import org.springframework.jdbc.datasource.DataSourceUtils;
import org.springframework.jdbc.support.nativejdbc.SimpleNativeJdbcExtractor;

DataSource dataSource = ... // récupération par JNDI par exemple et/ou injecté par Spring
Connection conn = DataSourceUtils.getConnection(dataSource);
SimpleNativeJdbcExtractor extractor = new SimpleNativeJdbcExtractor();
OracleConnection oraConn = (OracleConnection) extractor.getNativeConnection(conn);


Généralement les applications conçues avec Spring gère généralement les ressources base de données à haut niveau (niveau DataSource). La classe utilitaire DataSourceUtils de Spring permet notamment de récupérer la connexion sous-jacente à la DataSource. Ensuite, le SimpleNativeJdbcExtractor permet d'extraire la connexion native en réalisant un unwrap de la connexion du pool. D'autres extracteurs existent dans ce package utilitaire de Spring, mais malheureusement, cela ne fonctionne pas toujours.

2) sans Spring

En effet, si vous avez un pool de connexion fait maison il sera alors beaucoup plus difficile d'utiliser les classes utilitaires Spring. Un autre cas de figure est lorsque l'application doit pouvoir être déployée sur différents conteneurs JEE, dont certains non identifiés par les outils Spring.
Dans certains cas, la méthode getMetadata() de l'objet Connection peut-être utilisé directement pour récupérer la connexions native. Dans d'autres cas, il faut utiliser la méthode getUnderlyingConnection() (pas toujours présente) pour récupérer la connexion native (comme c'est le cas pour le wrapper JBoss).
Voici la classe utilitaire permettant de récupérer une connexion native Oracle quelque soit le conteneur (pas testé partout) :

package com.openfarm.util;

import java.lang.reflect.Method;
import java.sql.Connection;
import java.sql.SQLException;

import oracle.jdbc.OracleConnection;

import org.apache.log4j.Logger;

/**
 * Classe statique réalisant quasiment la même chose que la classe spring suivante
 * org.springframework.jdbc.support.nativejdbc.SimpleNativeJdbcExtractor
 * c'est à dire extraire la connection native sous-jacente d'un pool de connexion.
 * La récupération à travers les metadata fonctionne avec la plupart des pools de
 * connexion (JBoss 3.x, DBCP 1.x, Resin, etc.)
 * La récupération de la connexion native est parfois nécessaire notamment pour
 * l'utilisation de l'API Network Data Model d'Oracle.
 * 
 * @author guillaume viel at openfarm dot fr
 *
 */
public class OracleNativeJdbcExtractor {
   
    private static final Logger logger = Logger.getLogger(OracleNativeJdbcExtractor.class);
   
    /**
     * Retourne la connexion native sous-jacente au pool de connexion
     * @param poolConn La connexion du pool
     * @return Connection La connexion native
     * @throws SQLException
     */
    public static Connection getNativeConnection(Connection poolConn) throws SQLException {
        Connection nativeConn = poolConn;
        if(poolConn != null) {
            nativeConn = poolConn.getMetaData().getConnection();
            logger.info(poolConn + " encapsulates ["+nativeConn+"]");
        }
        return nativeConn;
    }
   
    /**
     * Retourne la connexion native Oracle sous-jacente au pool de connexion
     * @param poolConn La connexion du pool
     * @return OracleConnection La connexion Oracle sous-jacente au pool
     * @throws SQLException
     */
    public static OracleConnection getNativeOracleConnection(Connection poolConn) throws SQLException {
        OracleConnection oraConn = null;
        if(poolConn != null) {
            logger.debug( poolConn.getClass().getName() ); // permet d'identifier le nom du wrapper
           
            try {
                oraConn = (OracleConnection)poolConn.getMetaData().getConnection();
                logger.info(poolConn + " wraps [" + oraConn + "]");
            } catch(ClassCastException e) {
                // fonctionne par exemple avec le wrapper JBoss qui supporte la methode getUnderlyingConnection
                try {
                    Method method = poolConn.getClass().getDeclaredMethod("getUnderlyingConnection", (Class[])null);
                    if(method != null) {
                        oraConn = (OracleConnection)method.invoke(poolConn, (Object[])null);
                        logger.info(poolConn + " encapsulates ["+oraConn+"]");
                    }
                } catch (Exception e1) {
                    e1.printStackTrace();
                }
            }
        }
        return oraConn;
    }
   
}