From 3c07ac12249f65f04ab540a36c5c0807c0fa8d2d Mon Sep 17 00:00:00 2001 From: wenshao Date: Wed, 29 Jun 2011 04:22:34 +0000 Subject: [PATCH] =?UTF-8?q?=E4=BB=BF=E7=85=A7ibatis=E7=9A=84=E9=A3=8E?= =?UTF-8?q?=E6=A0=BC=E5=AE=9E=E7=8E=B0Log=EF=BC=8C=E4=BB=A5=E5=8F=8A?= =?UTF-8?q?=E6=B7=BB=E5=8A=A0ConnectionChecker?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit git-svn-id: http://code.alibabatech.com/svn/druid/trunk@292 b9813039-fb51-4c41-a8b9-e21c2acb5095 --- .../java/com/alibaba/druid/logging/Log.java | 17 + .../com/alibaba/druid/logging/LogFactory.java | 65 ++++ .../com/alibaba/druid/logging/Resources.java | 308 ++++++++++++++++++ .../druid/pool/ValidConnectionChecker.java | 8 + .../vendor/MSSQLValidConnectionChecker.java | 67 ++++ .../vendor/MySQLValidConnectionChecker.java | 76 +++++ .../vendor/OracleValidConnectionChecker.java | 67 ++++ 7 files changed, 608 insertions(+) create mode 100644 src/main/java/com/alibaba/druid/logging/Log.java create mode 100644 src/main/java/com/alibaba/druid/logging/LogFactory.java create mode 100644 src/main/java/com/alibaba/druid/logging/Resources.java create mode 100644 src/main/java/com/alibaba/druid/pool/ValidConnectionChecker.java create mode 100644 src/main/java/com/alibaba/druid/pool/vendor/MSSQLValidConnectionChecker.java create mode 100644 src/main/java/com/alibaba/druid/pool/vendor/MySQLValidConnectionChecker.java create mode 100644 src/main/java/com/alibaba/druid/pool/vendor/OracleValidConnectionChecker.java diff --git a/src/main/java/com/alibaba/druid/logging/Log.java b/src/main/java/com/alibaba/druid/logging/Log.java new file mode 100644 index 0000000000..cd015b83a0 --- /dev/null +++ b/src/main/java/com/alibaba/druid/logging/Log.java @@ -0,0 +1,17 @@ +package com.alibaba.druid.logging; + +public interface Log { + + boolean isDebugEnabled(); + + void error(String s, Throwable e); + + void error(String s); + + public void debug(String s); + + public void warn(String s); + + void warn(String s, Throwable e); + +} diff --git a/src/main/java/com/alibaba/druid/logging/LogFactory.java b/src/main/java/com/alibaba/druid/logging/LogFactory.java new file mode 100644 index 0000000000..692da638e7 --- /dev/null +++ b/src/main/java/com/alibaba/druid/logging/LogFactory.java @@ -0,0 +1,65 @@ +package com.alibaba.druid.logging; + +import java.lang.reflect.Constructor; + +public class LogFactory { + + private static Constructor logConstructor; + + static { + tryImplementation("org.apache.commons.logging.LogFactory", + "com.ibatis.common.logging.jakarta.JakartaCommonsLoggingImpl"); + tryImplementation("org.apache.log4j.Logger", "com.ibatis.common.logging.log4j.Log4jImpl"); + tryImplementation("java.util.logging.Logger", "com.ibatis.common.logging.jdk14.Jdk14LoggingImpl"); + tryImplementation("java.lang.Object", "com.ibatis.common.logging.nologging.NoLoggingImpl"); + } + + private static void tryImplementation(String testClassName, String implClassName) { + if (logConstructor == null) { + try { + Resources.classForName(testClassName); + Class implClass = Resources.classForName(implClassName); + logConstructor = implClass.getConstructor(new Class[] { Class.class }); + } catch (Throwable t) { + } + } + } + + public static Log getLog(Class aClass) { + try { + return (Log) logConstructor.newInstance(new Object[] { aClass }); + } catch (Throwable t) { + throw new RuntimeException("Error creating logger for class " + aClass + ". Cause: " + t, t); + } + } + + /** + * This method will switch the logging implementation to Log4J if Log4J is available on the classpath. This is + * useful in situations where you want to use Log4J to log iBATIS activity but commons logging is on the classpath. + * Note that this method is only effective for log classes obtained after calling this method. If you intend to use + * this method you should call it before calling any other iBATIS method. + */ + public static synchronized void selectLog4JLogging() { + try { + Resources.classForName("org.apache.log4j.Logger"); + Class implClass = Resources.classForName("com.ibatis.common.logging.log4j.Log4jImpl"); + logConstructor = implClass.getConstructor(new Class[] { Class.class }); + } catch (Throwable t) { + } + } + + /** + * This method will switch the logging implementation to Java native logging if you are running in JRE 1.4 or above. + * This is useful in situations where you want to use Java native logging to log iBATIS activity but commons logging + * or Log4J is on the classpath. Note that this method is only effective for log classes obtained after calling this + * method. If you intend to use this method you should call it before calling any other iBATIS method. + */ + public static synchronized void selectJavaLogging() { + try { + Resources.classForName("java.util.logging.Logger"); + Class implClass = Resources.classForName("com.ibatis.common.logging.jdk14.Jdk14LoggingImpl"); + logConstructor = implClass.getConstructor(new Class[] { Class.class }); + } catch (Throwable t) { + } + } +} diff --git a/src/main/java/com/alibaba/druid/logging/Resources.java b/src/main/java/com/alibaba/druid/logging/Resources.java new file mode 100644 index 0000000000..b0293eb347 --- /dev/null +++ b/src/main/java/com/alibaba/druid/logging/Resources.java @@ -0,0 +1,308 @@ +package com.alibaba.druid.logging; + + +import java.io.*; +import java.net.URL; +import java.net.URLConnection; +import java.nio.charset.Charset; +import java.util.Properties; + +/** + * A class to simplify access to resources through the classloader. + */ +public class Resources extends Object { + + private static ClassLoader defaultClassLoader; + + /** + * Charset to use when calling getResourceAsReader. + * null means use the system default. + */ + private static Charset charset; + + private Resources() { + } + + /** + * Returns the default classloader (may be null). + * + * @return The default classloader + */ + public static ClassLoader getDefaultClassLoader() { + return defaultClassLoader; + } + + /** + * Sets the default classloader + * + * @param defaultClassLoader - the new default ClassLoader + */ + public static void setDefaultClassLoader(ClassLoader defaultClassLoader) { + Resources.defaultClassLoader = defaultClassLoader; + } + + /** + * Returns the URL of the resource on the classpath + * + * @param resource The resource to find + * @return The resource + * @throws IOException If the resource cannot be found or read + */ + public static URL getResourceURL(String resource) throws IOException { + return getResourceURL(getClassLoader(), resource); + } + + /** + * Returns the URL of the resource on the classpath + * + * @param loader The classloader used to load the resource + * @param resource The resource to find + * @return The resource + * @throws IOException If the resource cannot be found or read + */ + public static URL getResourceURL(ClassLoader loader, String resource) throws IOException { + URL url = null; + if (loader != null) url = loader.getResource(resource); + if (url == null) url = ClassLoader.getSystemResource(resource); + if (url == null) throw new IOException("Could not find resource " + resource); + return url; + } + + /** + * Returns a resource on the classpath as a Stream object + * + * @param resource The resource to find + * @return The resource + * @throws IOException If the resource cannot be found or read + */ + public static InputStream getResourceAsStream(String resource) throws IOException { + return getResourceAsStream(getClassLoader(), resource); + } + + /** + * Returns a resource on the classpath as a Stream object + * + * @param loader The classloader used to load the resource + * @param resource The resource to find + * @return The resource + * @throws IOException If the resource cannot be found or read + */ + public static InputStream getResourceAsStream(ClassLoader loader, String resource) throws IOException { + InputStream in = null; + if (loader != null) in = loader.getResourceAsStream(resource); + if (in == null) in = ClassLoader.getSystemResourceAsStream(resource); + if (in == null) throw new IOException("Could not find resource " + resource); + return in; + } + + /** + * Returns a resource on the classpath as a Properties object + * + * @param resource The resource to find + * @return The resource + * @throws IOException If the resource cannot be found or read + */ + public static Properties getResourceAsProperties(String resource) + throws IOException { + Properties props = new Properties(); + InputStream in = null; + String propfile = resource; + in = getResourceAsStream(propfile); + props.load(in); + in.close(); + return props; + } + + /** + * Returns a resource on the classpath as a Properties object + * + * @param loader The classloader used to load the resource + * @param resource The resource to find + * @return The resource + * @throws IOException If the resource cannot be found or read + */ + public static Properties getResourceAsProperties(ClassLoader loader, String resource) + throws IOException { + Properties props = new Properties(); + InputStream in = null; + String propfile = resource; + in = getResourceAsStream(loader, propfile); + props.load(in); + in.close(); + return props; + } + + /** + * Returns a resource on the classpath as a Reader object + * + * @param resource The resource to find + * @return The resource + * @throws IOException If the resource cannot be found or read + */ + public static Reader getResourceAsReader(String resource) throws IOException { + Reader reader; + if (charset == null) { + reader = new InputStreamReader(getResourceAsStream(resource)); + } else { + reader = new InputStreamReader(getResourceAsStream(resource), charset); + } + + return reader; + } + + /** + * Returns a resource on the classpath as a Reader object + * + * @param loader The classloader used to load the resource + * @param resource The resource to find + * @return The resource + * @throws IOException If the resource cannot be found or read + */ + public static Reader getResourceAsReader(ClassLoader loader, String resource) throws IOException { + Reader reader; + if (charset == null) { + reader = new InputStreamReader(getResourceAsStream(loader, resource)); + } else { + reader = new InputStreamReader(getResourceAsStream(loader, resource), charset); + } + + return reader; + } + + /** + * Returns a resource on the classpath as a File object + * + * @param resource The resource to find + * @return The resource + * @throws IOException If the resource cannot be found or read + */ + public static File getResourceAsFile(String resource) throws IOException { + return new File(getResourceURL(resource).getFile()); + } + + /** + * Returns a resource on the classpath as a File object + * + * @param loader - the classloader used to load the resource + * @param resource - the resource to find + * @return The resource + * @throws IOException If the resource cannot be found or read + */ + public static File getResourceAsFile(ClassLoader loader, String resource) throws IOException { + return new File(getResourceURL(loader, resource).getFile()); + } + + /** + * Gets a URL as an input stream + * + * @param urlString - the URL to get + * @return An input stream with the data from the URL + * @throws IOException If the resource cannot be found or read + */ + public static InputStream getUrlAsStream(String urlString) throws IOException { + URL url = new URL(urlString); + URLConnection conn = url.openConnection(); + return conn.getInputStream(); + } + + /** + * Gets a URL as a Reader + * + * @param urlString - the URL to get + * @return A Reader with the data from the URL + * @throws IOException If the resource cannot be found or read + */ + public static Reader getUrlAsReader(String urlString) throws IOException { + return new InputStreamReader(getUrlAsStream(urlString)); + } + + /** + * Gets a URL as a Properties object + * + * @param urlString - the URL to get + * @return A Properties object with the data from the URL + * @throws IOException If the resource cannot be found or read + */ + public static Properties getUrlAsProperties(String urlString) throws IOException { + Properties props = new Properties(); + InputStream in = null; + String propfile = urlString; + in = getUrlAsStream(propfile); + props.load(in); + in.close(); + return props; + } + + /** + * Loads a class + * + * @param className - the class to load + * @return The loaded class + * @throws ClassNotFoundException If the class cannot be found (duh!) + */ + public static Class classForName(String className) throws ClassNotFoundException { + Class clazz = null; + try { + clazz = getClassLoader().loadClass(className); + } catch (Exception e) { + // Ignore. Failsafe below. + } + if (clazz == null) { + clazz = Class.forName(className); + } + return clazz; + } + + /** + * Creates an instance of a class + * + * @param className - the class to create + * @return An instance of the class + * @throws ClassNotFoundException If the class cannot be found (duh!) + * @throws InstantiationException If the class cannot be instantiaed + * @throws IllegalAccessException If the class is not public, or other access problems arise + */ + public static Object instantiate(String className) + throws ClassNotFoundException, InstantiationException, IllegalAccessException { + return instantiate(classForName(className)); + } + + /** + * Creates an instance of a class + * + * @param clazz - the class to create + * @return An instance of the class + * @throws InstantiationException If the class cannot be instantiaed + * @throws IllegalAccessException If the class is not public, or other access problems arise + */ + public static Object instantiate(Class clazz) + throws InstantiationException, IllegalAccessException { + return clazz.newInstance(); + } + + private static ClassLoader getClassLoader() { + if (defaultClassLoader != null) { + return defaultClassLoader; + } else { + return Thread.currentThread().getContextClassLoader(); + } + } + + public static Charset getCharset() { + return charset; + } + + /** + * Use this method to set the Charset to be used when + * calling the getResourceAsReader methods. This will + * allow iBATIS to function properly when the system default + * encoding doesn't deal well with unicode (IBATIS-340, IBATIS-349) + * + * @param charset + */ + public static void setCharset(Charset charset) { + Resources.charset = charset; + } + +} + diff --git a/src/main/java/com/alibaba/druid/pool/ValidConnectionChecker.java b/src/main/java/com/alibaba/druid/pool/ValidConnectionChecker.java new file mode 100644 index 0000000000..6e8997ffcc --- /dev/null +++ b/src/main/java/com/alibaba/druid/pool/ValidConnectionChecker.java @@ -0,0 +1,8 @@ +package com.alibaba.druid.pool; + +import java.sql.Connection; +import java.sql.SQLException; + +public interface ValidConnectionChecker { + SQLException isValidConnection(Connection c); +} diff --git a/src/main/java/com/alibaba/druid/pool/vendor/MSSQLValidConnectionChecker.java b/src/main/java/com/alibaba/druid/pool/vendor/MSSQLValidConnectionChecker.java new file mode 100644 index 0000000000..a8ece1ed5b --- /dev/null +++ b/src/main/java/com/alibaba/druid/pool/vendor/MSSQLValidConnectionChecker.java @@ -0,0 +1,67 @@ +/* + * JBoss, Home of Professional Open Source. + * Copyright 2006, Red Hat Middleware LLC, and individual contributors + * as indicated by the @author tags. See the copyright.txt file in the + * distribution for a full listing of individual contributors. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package com.alibaba.druid.pool.vendor; + +import java.io.Serializable; +import java.sql.Connection; +import java.sql.SQLException; +import java.sql.Statement; + +import com.alibaba.druid.logging.Log; +import com.alibaba.druid.logging.LogFactory; +import com.alibaba.druid.pool.ValidConnectionChecker; +import com.alibaba.druid.util.JdbcUtils; + +/** + * A MSSQLValidConnectionChecker. + * + * @author Weston Price + * @version $Revision: 57189 $ + */ +public class MSSQLValidConnectionChecker implements ValidConnectionChecker, Serializable { + + private static final String QUERY = "SELECT x"; + private static final Log LOG = LogFactory.getLog(MSSQLValidConnectionChecker.class); + + /** The serialVersionUID */ + private static final long serialVersionUID = 3995516551833725723L; + + public SQLException isValidConnection(final Connection c) { + SQLException sqe = null; + Statement stmt = null; + + try { + stmt = c.createStatement(); + stmt.execute(QUERY); + } + + catch (SQLException e) { + LOG.warn("warning: connection validation failed for current managed connection."); + sqe = e; + } finally { + JdbcUtils.close(stmt); + } + + return sqe; + } + +} diff --git a/src/main/java/com/alibaba/druid/pool/vendor/MySQLValidConnectionChecker.java b/src/main/java/com/alibaba/druid/pool/vendor/MySQLValidConnectionChecker.java new file mode 100644 index 0000000000..fc18147916 --- /dev/null +++ b/src/main/java/com/alibaba/druid/pool/vendor/MySQLValidConnectionChecker.java @@ -0,0 +1,76 @@ +package com.alibaba.druid.pool.vendor; + +import java.io.Serializable; +import java.lang.reflect.Method; +import java.sql.Connection; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; + +import com.alibaba.druid.logging.Log; +import com.alibaba.druid.logging.LogFactory; +import com.alibaba.druid.pool.ValidConnectionChecker; +import com.alibaba.druid.util.JdbcUtils; + +public class MySQLValidConnectionChecker implements ValidConnectionChecker, Serializable { + + private static final long serialVersionUID = 1L; + private static final Log LOG = LogFactory.getLog(MySQLValidConnectionChecker.class); + + private Method ping; + private boolean driverHasPingMethod = false; + + // The timeout (apparently the timeout is ignored?) + private static Object[] params = new Object[] {}; + + @SuppressWarnings({ "unchecked", "rawtypes" }) + public MySQLValidConnectionChecker(){ + try { + Class mysqlConnection = Thread.currentThread().getContextClassLoader().loadClass("com.mysql.jdbc.Connection"); + ping = mysqlConnection.getMethod("ping", new Class[] {}); + if (ping != null) { + driverHasPingMethod = true; + } + } catch (Exception e) { + LOG.warn("Cannot resolve com.mysq.jdbc.Connection.ping method. Will use 'SELECT 1' instead.", e); + } + } + + public SQLException isValidConnection(Connection c) { + // if there is a ping method then use it, otherwise just use a 'SELECT 1' statement + if (driverHasPingMethod) { + try { + ping.invoke(c, params); + } catch (Exception e) { + if (e instanceof SQLException) { + return (SQLException) e; + } else { + LOG.warn("Unexpected error in ping", e); + return new SQLException("ping failed: " + e.toString()); + } + } + + } else { + + Statement stmt = null; + ResultSet rs = null; + try { + stmt = c.createStatement(); + rs = stmt.executeQuery("SELECT 1"); + } catch (Exception e) { + if (e instanceof SQLException) { + return (SQLException) e; + } else { + LOG.warn("Unexpected error in ping (SELECT 1)", e); + return new SQLException("ping (SELECT 1) failed: " + e.toString()); + } + } finally { + JdbcUtils.close(rs); + JdbcUtils.close(stmt); + } + + } + return null; + } + +} diff --git a/src/main/java/com/alibaba/druid/pool/vendor/OracleValidConnectionChecker.java b/src/main/java/com/alibaba/druid/pool/vendor/OracleValidConnectionChecker.java new file mode 100644 index 0000000000..c6ac9454d4 --- /dev/null +++ b/src/main/java/com/alibaba/druid/pool/vendor/OracleValidConnectionChecker.java @@ -0,0 +1,67 @@ +/* + * JBoss, Home of Professional Open Source. + * Copyright 2006, Red Hat Middleware LLC, and individual contributors + * as indicated by the @author tags. See the copyright.txt file in the + * distribution for a full listing of individual contributors. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package com.alibaba.druid.pool.vendor; + +import java.io.Serializable; +import java.lang.reflect.Method; +import java.sql.Connection; +import java.sql.SQLException; + +import com.alibaba.druid.logging.Log; +import com.alibaba.druid.logging.LogFactory; +import com.alibaba.druid.pool.ValidConnectionChecker; + +public class OracleValidConnectionChecker implements ValidConnectionChecker, Serializable { + + private static final long serialVersionUID = -2227528634302168877L; + + private static final Log LOG = LogFactory.getLog(OracleValidConnectionChecker.class); + + private Method ping; + + // The timeout (apparently the timeout is ignored?) + private static Object[] params = new Object[] { new Integer(5000) }; + + @SuppressWarnings({ "unchecked", "rawtypes" }) + public OracleValidConnectionChecker(){ + try { + Class oracleConnection = Thread.currentThread().getContextClassLoader().loadClass("oracle.jdbc.driver.OracleConnection"); + ping = oracleConnection.getMethod("pingDatabase", new Class[] { Integer.TYPE }); + } catch (Exception e) { + throw new RuntimeException("Unable to resolve pingDatabase method:", e); + } + } + + public SQLException isValidConnection(Connection c) { + try { + Integer status = (Integer) ping.invoke(c, params); + + // Error + if (status.intValue() < 0) return new SQLException("pingDatabase failed status=" + status); + } catch (Exception e) { + LOG.warn("Unexpected error in pingDatabase", e); + } + + // OK + return null; + } +}