    001/*
    002 * Licensed to the Apache Software Foundation (ASF) under one or more
    003 * contributor license agreements.  See the NOTICE file distributed with
    004 * this work for additional information regarding copyright ownership.
    005 * The ASF licenses this file to You under the Apache License, Version 2.0
    006 * (the "License"); you may not use this file except in compliance with
    007 * the License.  You may obtain a copy of the License at
    008 *
    009 *      http://www.apache.org/licenses/LICENSE-2.0
    010 *
    011 * Unless required by applicable law or agreed to in writing, software
    012 * distributed under the License is distributed on an "AS IS" BASIS,
    013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    014 * See the License for the specific language governing permissions and
    015 * limitations under the License.
    016 */
    017package org.apache.commons.dbutils;
    018
    019import static java.sql.DriverManager.registerDriver;
    020
    021import java.io.PrintWriter;
    022import java.lang.reflect.Constructor;
    023import java.sql.Connection;
    024import java.sql.Driver;
    025import java.sql.DriverPropertyInfo;
    026import java.sql.ResultSet;
    027import java.sql.SQLException;
    028import java.sql.SQLFeatureNotSupportedException;
    029import java.sql.Statement;
    030import java.util.Properties;
    031import java.util.logging.Logger;
    032
    033/**
    034 * A collection of JDBC helper methods.  This class is thread safe.
    035 */
    036public final class DbUtils {
    037
    038    /**
    039     * Simple {@link Driver} proxy class that proxies a JDBC Driver loaded dynamically.
    040     *
    041     * @since 1.6
    042     */
    043    static final class DriverProxy implements Driver {
    044
    045        /**
    046         * The adapted JDBC Driver loaded dynamically.
    047         */
    048        private final Driver adapted;
    049
    050        /**
    051         * Creates a new JDBC Driver that adapts a JDBC Driver loaded dynamically.
    052         *
    053         * @param adapted the adapted JDBC Driver loaded dynamically.
    054         */
    055        public DriverProxy(final Driver adapted) {
    056            this.adapted = adapted;
    057        }
    058
    059        /**
    060         * {@inheritDoc}
    061         */
    062        @Override
    063        public boolean acceptsURL(final String url) throws SQLException {
    064            return adapted.acceptsURL(url);
    065        }
    066
    067        /**
    068         * {@inheritDoc}
    069         */
    070        @Override
    071        public Connection connect(final String url, final Properties info) throws SQLException {
    072            return adapted.connect(url, info);
    073        }
    074
    075        /**
    076         * {@inheritDoc}
    077         */
    078        @Override
    079        public int getMajorVersion() {
    080            return adapted.getMajorVersion();
    081        }
    082
    083        /**
    084         * {@inheritDoc}
    085         */
    086        @Override
    087        public int getMinorVersion() {
    088            return adapted.getMinorVersion();
    089        }
    090
    091        /**
    092         * Java 1.7 method.
    093         */
    094        @Override
    095        public Logger getParentLogger() throws SQLFeatureNotSupportedException {
    096            return adapted.getParentLogger();
    097        }
    098
    099        /**
    100         * {@inheritDoc}
    101         */
    102        @Override
    103        public DriverPropertyInfo[] getPropertyInfo(final String url, final Properties info) throws SQLException {
    104            return adapted.getPropertyInfo(url, info);
    105        }
    106
    107        /**
    108         * {@inheritDoc}
    109         */
    110        @Override
    111        public boolean jdbcCompliant() {
    112            return adapted.jdbcCompliant();
    113        }
    114
    115    }
    116
    117    /**
    118     * Close a {@code Connection}, avoid closing if null.
    119     *
    120     * @param conn Connection to close.
    121     * @throws SQLException if a database access error occurs
    122     */
    123    public static void close(final Connection conn) throws SQLException {
    124        if (conn != null) {
    125            conn.close();
    126        }
    127    }
    128
    129    /**
    130     * Close a {@code ResultSet}, avoid closing if null.
    131     *
    132     * @param resultSet ResultSet to close.
    133     * @throws SQLException if a database access error occurs
    134     */
    135    public static void close(final ResultSet resultSet) throws SQLException {
    136        if (resultSet != null) {
    137            resultSet.close();
    138        }
    139    }
    140
    141    /**
    142     * Close a {@code Statement}, avoid closing if null.
    143     *
    144     * @param stmt Statement to close.
    145     * @throws SQLException if a database access error occurs
    146     */
    147    public static void close(final Statement stmt) throws SQLException {
    148        if (stmt != null) {
    149            stmt.close();
    150        }
    151    }
    152
    153    /**
    154     * Close a {@code Connection}, avoid closing if null and hide
    155     * any SQLExceptions that occur.
    156     *
    157     * @param conn Connection to close.
    158     */
    159    public static void closeQuietly(final Connection conn) {
    160        try {
    161            close(conn);
    162        } catch (final SQLException e) { // NOPMD
    163            // quiet
    164        }
    165    }
    166
    167    /**
    168     * Close a {@code Connection}, {@code Statement} and
    169     * {@code ResultSet}.  Avoid closing if null and hide any
    170     * SQLExceptions that occur.
    171     *
    172     * @param conn Connection to close.
    173     * @param stmt Statement to close.
    174     * @param rs ResultSet to close.
    175     */
    176    public static void closeQuietly(final Connection conn, final Statement stmt,
    177            final ResultSet rs) {
    178
    179        try {
    180            closeQuietly(rs);
    181        } finally {
    182            try {
    183                closeQuietly(stmt);
    184            } finally {
    185                closeQuietly(conn);
    186            }
    187        }
    188
    189    }
    190
    191    /**
    192     * Close a {@code ResultSet}, avoid closing if null and hide any
    193     * SQLExceptions that occur.
    194     *
    195     * @param resultSet ResultSet to close.
    196     */
    197    public static void closeQuietly(final ResultSet resultSet) {
    198        try {
    199            close(resultSet);
    200        } catch (final SQLException e) { // NOPMD
    201            // quiet
    202        }
    203    }
    204
    205    /**
    206     * Close a {@code Statement}, avoid closing if null and hide
    207     * any SQLExceptions that occur.
    208     *
    209     * @param stmt Statement to close.
    210     */
    211    public static void closeQuietly(final Statement stmt) {
    212        try {
    213            close(stmt);
    214        } catch (final SQLException e) { // NOPMD
    215            // quiet
    216        }
    217    }
    218
    219    /**
    220     * Commits a {@code Connection} then closes it, avoid closing if null.
    221     *
    222     * @param conn Connection to close.
    223     * @throws SQLException if a database access error occurs
    224     */
    225    public static void commitAndClose(final Connection conn) throws SQLException {
    226        if (conn != null) {
    227            try {
    228                conn.commit();
    229            } finally {
    230                conn.close();
    231            }
    232        }
    233    }
    234
    235    /**
    236     * Commits a {@code Connection} then closes it, avoid closing if null
    237     * and hide any SQLExceptions that occur.
    238     *
    239     * @param conn Connection to close.
    240     */
    241    public static void commitAndCloseQuietly(final Connection conn) {
    242        try {
    243            commitAndClose(conn);
    244        } catch (final SQLException e) { // NOPMD
    245            // quiet
    246        }
    247    }
    248
    249    /**
    250     * Loads and registers a database driver class.
    251     * If this succeeds, it returns true, else it returns false.
    252     *
    253     * @param classLoader the class loader used to load the driver class
    254     * @param driverClassName of driver to load
    255     * @return boolean {@code true} if the driver was found, otherwise {@code false}
    256     * @since 1.4
    257     */
    258    public static boolean loadDriver(final ClassLoader classLoader, final String driverClassName) {
    259        try {
    260            final Class<?> loadedClass = classLoader.loadClass(driverClassName);
    261
    262            if (!Driver.class.isAssignableFrom(loadedClass)) {
    263                return false;
    264            }
    265
    266            @SuppressWarnings("unchecked") // guarded by previous check
    267            final
    268            Class<Driver> driverClass = (Class<Driver>) loadedClass;
    269            final Constructor<Driver> driverConstructor = driverClass.getConstructor();
    270
    271            // make Constructor accessible if it is private
    272            @SuppressWarnings("deprecation")
    273            // TODO This is deprecated in Java9 and canAccess() should be used. Adding suppression for building on
    274            //      later JDKs without a warning.
    275            final boolean isConstructorAccessible = driverConstructor.isAccessible();
    276            if (!isConstructorAccessible) {
    277                driverConstructor.setAccessible(true);
    278            }
    279
    280            try {
    281                final Driver driver = driverConstructor.newInstance();
    282                registerDriver(new DriverProxy(driver));
    283            } finally {
    284                driverConstructor.setAccessible(isConstructorAccessible);
    285            }
    286
    287            return true;
    288        } catch (final Exception e) {
    289            return false;
    290        }
    291    }
    292
    293    /**
    294     * Loads and registers a database driver class.
    295     * If this succeeds, it returns true, else it returns false.
    296     *
    297     * @param driverClassName of driver to load
    298     * @return boolean {@code true} if the driver was found, otherwise {@code false}
    299     */
    300    public static boolean loadDriver(final String driverClassName) {
    301        return loadDriver(DbUtils.class.getClassLoader(), driverClassName);
    302    }
    303
    304    /**
    305     * Print the stack trace for a SQLException to STDERR.
    306     *
    307     * @param e SQLException to print stack trace of
    308     */
    309    public static void printStackTrace(final SQLException e) {
    310        printStackTrace(e, new PrintWriter(System.err));
    311    }
    312
    313    /**
    314     * Print the stack trace for a SQLException to a
    315     * specified PrintWriter.
    316     *
    317     * @param e SQLException to print stack trace of
    318     * @param pw PrintWriter to print to
    319     */
    320    public static void printStackTrace(final SQLException e, final PrintWriter pw) {
    321
    322        SQLException next = e;
    323        while (next != null) {
    324            next.printStackTrace(pw);
    325            next = next.getNextException();
    326            if (next != null) {
    327                pw.println("Next SQLException:");
    328            }
    329        }
    330    }
    331
    332    /**
    333     * Print warnings on a Connection to STDERR.
    334     *
    335     * @param conn Connection to print warnings from
    336     */
    337    public static void printWarnings(final Connection conn) {
    338        printWarnings(conn, new PrintWriter(System.err));
    339    }
    340
    341    /**
    342     * Print warnings on a Connection to a specified PrintWriter.
    343     *
    344     * @param conn Connection to print warnings from
    345     * @param pw PrintWriter to print to
    346     */
    347    public static void printWarnings(final Connection conn, final PrintWriter pw) {
    348        if (conn != null) {
    349            try {
    350                printStackTrace(conn.getWarnings(), pw);
    351            } catch (final SQLException e) {
    352                printStackTrace(e, pw);
    353            }
    354        }
    355    }
    356
    357    /**
    358     * Rollback any changes made on the given connection.
    359     * @param conn Connection to rollback.  A null value is legal.
    360     * @throws SQLException if a database access error occurs
    361     */
    362    public static void rollback(final Connection conn) throws SQLException {
    363        if (conn != null) {
    364            conn.rollback();
    365        }
    366    }
    367
    368
    369    /**
    370     * Performs a rollback on the {@code Connection} then closes it,
    371     * avoid closing if null.
    372     *
    373     * @param conn Connection to rollback.  A null value is legal.
    374     * @throws SQLException if a database access error occurs
    375     * @since 1.1
    376     */
    377    public static void rollbackAndClose(final Connection conn) throws SQLException {
    378        if (conn != null) {
    379            try {
    380                conn.rollback();
    381            } finally {
    382                conn.close();
    383            }
    384        }
    385    }
    386
    387    /**
    388     * Performs a rollback on the {@code Connection} then closes it,
    389     * avoid closing if null and hide any SQLExceptions that occur.
    390     *
    391     * @param conn Connection to rollback.  A null value is legal.
    392     * @since 1.1
    393     */
    394    public static void rollbackAndCloseQuietly(final Connection conn) {
    395        try {
    396            rollbackAndClose(conn);
    397        } catch (final SQLException e) { // NOPMD
    398            // quiet
    399        }
    400    }
    401
    402    /**
    403     * Performs a rollback on the <code>Connection</code>, avoid
    404     * closing if null and hide any SQLExceptions that occur.
    405     *
    406     * @param conn Connection to rollback.  A null value is legal.
    407     * @since DbUtils 2.0
    408     */
    409    public static void rollbackQuietly(final Connection conn) {
    410        try {
    411            rollback(conn);
    412        } catch (final SQLException e) { // NOPMD
    413            // quiet
    414        }
    415    }
    416
    417    /**
    418     * Default constructor.
    419     *
    420     * Utility classes should not have a public or default constructor,
    421     * but this one preserves retro-compatibility.
    422     *
    423     * @since 1.4
    424     */
    425    public DbUtils() {
    426        // do nothing
    427    }
    428
    429}