/* * Copyright 2008-2014 by Emeric Vernat * * This file is part of Java Melody. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package net.bull.javamelody; import java.sql.Connection; import java.sql.Driver; import java.sql.DriverManager; import java.sql.DriverPropertyInfo; import java.sql.SQLException; import java.sql.SQLFeatureNotSupportedException; import java.util.Collections; import java.util.Properties; import java.util.logging.Logger; /** * Driver jdbc "proxy" pour le monitoring. * C'est la classe de ce driver qui doit être déclarée si un driver jdbc et non une dataSource est utilisé. * Dans la déclaration une propriété jdbc 'driver' doit contenir le nom de la classe du vrai driver. * D'autres propriétés jdbc comme url, username ou password peuvent être déclarées. * @author Emeric Vernat */ public class JdbcDriver implements Driver { // cette classe est publique pour être déclarée dans une configuration jdbc static final JdbcDriver SINGLETON = new JdbcDriver(); // initialisation statique du driver static { try { DriverManager.registerDriver(SINGLETON); LOG.debug("JDBC driver registered"); // on désinstalle et on réinstalle les autres drivers pour que le notre soit en premier // (notamment, si le jar du driver contient un fichier java.sql.Driver dans META-INF/services // pour initialiser automatiquement le driver contenu dans le jar) for (final Driver driver : Collections.list(DriverManager.getDrivers())) { if (driver != SINGLETON) { DriverManager.deregisterDriver(driver); DriverManager.registerDriver(driver); } } } catch (final SQLException e) { // ne peut arriver throw new IllegalStateException(e); } } /** {@inheritDoc} */ @Override public Connection connect(String url, Properties info) throws SQLException { final String proxiedDriver = info.getProperty("driver"); if (proxiedDriver == null) { // si pas de propriété driver alors ce n'est pas pour nous // (on passe ici lors du DriverManager.getConnection ci-dessous) return null; } try { // on utilise Thread.currentThread().getContextClassLoader() car le driver peut ne pas être // dans le même classLoader que les classes de javamelody Class.forName(proxiedDriver, true, Thread.currentThread().getContextClassLoader()); // et non Class.forName(proxiedDriver); } catch (final ClassNotFoundException e) { // Rq: le constructeur de SQLException avec message et cause n'existe qu'en jdk 1.6 throw new SQLException(e.getMessage(), e); } final Properties tmp = (Properties) info.clone(); tmp.remove("driver"); Parameters.initJdbcDriverParameters(url, tmp); return JdbcWrapper.SINGLETON.createConnectionProxy(DriverManager.getConnection(url, tmp)); } /** {@inheritDoc} */ @Override public boolean acceptsURL(String url) throws SQLException { // test sur dbcp nécessaire pour le cas où le monitoring est utilisé avec le web.xml global // et le répertoire lib global de tomcat et également pour les anomalies 1&2 (sonar, grails) // (rq: Thread.currentThread().getStackTrace() a été mesuré à environ 3 micro-secondes) for (final StackTraceElement element : Thread.currentThread().getStackTrace()) { if (element.getClassName().endsWith("dbcp.BasicDataSource")) { return false; } } return true; } /** {@inheritDoc} */ @Override public int getMajorVersion() { return -1; } /** {@inheritDoc} */ @Override public int getMinorVersion() { return -1; } /** {@inheritDoc} */ @Override public DriverPropertyInfo[] getPropertyInfo(String url, Properties info) throws SQLException { return new DriverPropertyInfo[0]; } /** {@inheritDoc} */ @Override public boolean jdbcCompliant() { return true; } /** {@inheritDoc} */ @Override public String toString() { return getClass().getSimpleName() + "[lastConnectUrl=" + Parameters.getLastConnectUrl() + ", lastConnectInfo=" + Parameters.getLastConnectInfo() + ']'; } /** * Définition de la méthode getParentLogger ajoutée dans l'interface Driver en jdk 1.7. * @return Logger * @throws SQLFeatureNotSupportedException e */ @Override public Logger getParentLogger() throws SQLFeatureNotSupportedException { return Logger.getLogger(Logger.GLOBAL_LOGGER_NAME); } }