View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.dbutils;
18  
19  import static java.sql.DriverManager.registerDriver;
20  
21  import java.io.PrintWriter;
22  import java.lang.reflect.Constructor;
23  import java.lang.reflect.InvocationTargetException;
24  import java.lang.reflect.Method;
25  import java.sql.Connection;
26  import java.sql.Driver;
27  import java.sql.DriverPropertyInfo;
28  import java.sql.ResultSet;
29  import java.sql.SQLException;
30  import java.sql.SQLFeatureNotSupportedException;
31  import java.sql.Statement;
32  import java.util.logging.Logger;
33  import java.util.Properties;
34  
35  /**
36   * A collection of JDBC helper methods.  This class is thread safe.
37   */
38  public final class DbUtils {
39  
40      /**
41       * Default constructor.
42       *
43       * Utility classes should not have a public or default constructor,
44       * but this one preserves retro-compatibility.
45       *
46       * @since 1.4
47       */
48      public DbUtils() {
49          // do nothing
50      }
51  
52      /**
53       * Close a <code>Connection</code>, avoid closing if null.
54       *
55       * @param conn Connection to close.
56       * @throws SQLException if a database access error occurs
57       */
58      public static void close(Connection conn) throws SQLException {
59          if (conn != null) {
60              conn.close();
61          }
62      }
63  
64      /**
65       * Close a <code>ResultSet</code>, avoid closing if null.
66       *
67       * @param rs ResultSet to close.
68       * @throws SQLException if a database access error occurs
69       */
70      public static void close(ResultSet rs) throws SQLException {
71          if (rs != null) {
72              rs.close();
73          }
74      }
75  
76      /**
77       * Close a <code>Statement</code>, avoid closing if null.
78       *
79       * @param stmt Statement to close.
80       * @throws SQLException if a database access error occurs
81       */
82      public static void close(Statement stmt) throws SQLException {
83          if (stmt != null) {
84              stmt.close();
85          }
86      }
87  
88      /**
89       * Close a <code>Connection</code>, avoid closing if null and hide
90       * any SQLExceptions that occur.
91       *
92       * @param conn Connection to close.
93       */
94      public static void closeQuietly(Connection conn) {
95          try {
96              close(conn);
97          } catch (SQLException e) { // NOPMD
98              // quiet
99          }
100     }
101 
102     /**
103      * Close a <code>Connection</code>, <code>Statement</code> and
104      * <code>ResultSet</code>.  Avoid closing if null and hide any
105      * SQLExceptions that occur.
106      *
107      * @param conn Connection to close.
108      * @param stmt Statement to close.
109      * @param rs ResultSet to close.
110      */
111     public static void closeQuietly(Connection conn, Statement stmt,
112             ResultSet rs) {
113 
114         try {
115             closeQuietly(rs);
116         } finally {
117             try {
118                 closeQuietly(stmt);
119             } finally {
120                 closeQuietly(conn);
121             }
122         }
123 
124     }
125 
126     /**
127      * Close a <code>ResultSet</code>, avoid closing if null and hide any
128      * SQLExceptions that occur.
129      *
130      * @param rs ResultSet to close.
131      */
132     public static void closeQuietly(ResultSet rs) {
133         try {
134             close(rs);
135         } catch (SQLException e) { // NOPMD
136             // quiet
137         }
138     }
139 
140     /**
141      * Close a <code>Statement</code>, avoid closing if null and hide
142      * any SQLExceptions that occur.
143      *
144      * @param stmt Statement to close.
145      */
146     public static void closeQuietly(Statement stmt) {
147         try {
148             close(stmt);
149         } catch (SQLException e) { // NOPMD
150             // quiet
151         }
152     }
153 
154     /**
155      * Commits a <code>Connection</code> then closes it, avoid closing if null.
156      *
157      * @param conn Connection to close.
158      * @throws SQLException if a database access error occurs
159      */
160     public static void commitAndClose(Connection conn) throws SQLException {
161         if (conn != null) {
162             try {
163                 conn.commit();
164             } finally {
165                 conn.close();
166             }
167         }
168     }
169 
170     /**
171      * Commits a <code>Connection</code> then closes it, avoid closing if null
172      * and hide any SQLExceptions that occur.
173      *
174      * @param conn Connection to close.
175      */
176     public static void commitAndCloseQuietly(Connection conn) {
177         try {
178             commitAndClose(conn);
179         } catch (SQLException e) { // NOPMD
180             // quiet
181         }
182     }
183 
184     /**
185      * Loads and registers a database driver class.
186      * If this succeeds, it returns true, else it returns false.
187      *
188      * @param driverClassName of driver to load
189      * @return boolean <code>true</code> if the driver was found, otherwise <code>false</code>
190      */
191     public static boolean loadDriver(String driverClassName) {
192         return loadDriver(DbUtils.class.getClassLoader(), driverClassName);
193     }
194 
195     /**
196      * Loads and registers a database driver class.
197      * If this succeeds, it returns true, else it returns false.
198      *
199      * @param classLoader the class loader used to load the driver class
200      * @param driverClassName of driver to load
201      * @return boolean <code>true</code> if the driver was found, otherwise <code>false</code>
202      * @since 1.4
203      */
204     public static boolean loadDriver(ClassLoader classLoader, String driverClassName) {
205         try {
206             Class<?> loadedClass = classLoader.loadClass(driverClassName);
207 
208             if (!Driver.class.isAssignableFrom(loadedClass)) {
209                 return false;
210             }
211 
212             @SuppressWarnings("unchecked") // guarded by previous check
213             Class<Driver> driverClass = (Class<Driver>) loadedClass;
214             Constructor<Driver> driverConstructor = driverClass.getConstructor();
215 
216             // make Constructor accessible if it is private
217             boolean isConstructorAccessible = driverConstructor.isAccessible();
218             if (!isConstructorAccessible) {
219                 driverConstructor.setAccessible(true);
220             }
221 
222             try {
223                 Driver driver = driverConstructor.newInstance();
224                 registerDriver(new DriverProxy(driver));
225             } finally {
226                 driverConstructor.setAccessible(isConstructorAccessible);
227             }
228 
229             return true;
230         } catch (Exception e) {
231             return false;
232 
233         }
234     }
235 
236     /**
237      * Print the stack trace for a SQLException to STDERR.
238      *
239      * @param e SQLException to print stack trace of
240      */
241     public static void printStackTrace(SQLException e) {
242         printStackTrace(e, new PrintWriter(System.err));
243     }
244 
245     /**
246      * Print the stack trace for a SQLException to a
247      * specified PrintWriter.
248      *
249      * @param e SQLException to print stack trace of
250      * @param pw PrintWriter to print to
251      */
252     public static void printStackTrace(SQLException e, PrintWriter pw) {
253 
254         SQLException next = e;
255         while (next != null) {
256             next.printStackTrace(pw);
257             next = next.getNextException();
258             if (next != null) {
259                 pw.println("Next SQLException:");
260             }
261         }
262     }
263 
264     /**
265      * Print warnings on a Connection to STDERR.
266      *
267      * @param conn Connection to print warnings from
268      */
269     public static void printWarnings(Connection conn) {
270         printWarnings(conn, new PrintWriter(System.err));
271     }
272 
273     /**
274      * Print warnings on a Connection to a specified PrintWriter.
275      *
276      * @param conn Connection to print warnings from
277      * @param pw PrintWriter to print to
278      */
279     public static void printWarnings(Connection conn, PrintWriter pw) {
280         if (conn != null) {
281             try {
282                 printStackTrace(conn.getWarnings(), pw);
283             } catch (SQLException e) {
284                 printStackTrace(e, pw);
285             }
286         }
287     }
288 
289     /**
290      * Rollback any changes made on the given connection.
291      * @param conn Connection to rollback.  A null value is legal.
292      * @throws SQLException if a database access error occurs
293      */
294     public static void rollback(Connection conn) throws SQLException {
295         if (conn != null) {
296             conn.rollback();
297         }
298     }
299 
300     /**
301      * Performs a rollback on the <code>Connection</code> then closes it,
302      * avoid closing if null.
303      *
304      * @param conn Connection to rollback.  A null value is legal.
305      * @throws SQLException if a database access error occurs
306      * @since DbUtils 1.1
307      */
308     public static void rollbackAndClose(Connection conn) throws SQLException {
309         if (conn != null) {
310             try {
311                 conn.rollback();
312             } finally {
313                 conn.close();
314             }
315         }
316     }
317 
318     /**
319      * Performs a rollback on the <code>Connection</code> then closes it,
320      * avoid closing if null and hide any SQLExceptions that occur.
321      *
322      * @param conn Connection to rollback.  A null value is legal.
323      * @since DbUtils 1.1
324      */
325     public static void rollbackAndCloseQuietly(Connection conn) {
326         try {
327             rollbackAndClose(conn);
328         } catch (SQLException e) { // NOPMD
329             // quiet
330         }
331     }
332 
333     /**
334      * Simple {@link Driver} proxy class that proxies a JDBC Driver loaded dynamically.
335      *
336      * @since 1.6
337      */
338     private static final class DriverProxy implements Driver {
339 
340         private boolean parentLoggerSupported = true;
341 
342         /**
343          * The adapted JDBC Driver loaded dynamically.
344          */
345         private final Driver adapted;
346 
347         /**
348          * Creates a new JDBC Driver that adapts a JDBC Driver loaded dynamically.
349          *
350          * @param adapted the adapted JDBC Driver loaded dynamically.
351          */
352         public DriverProxy(Driver adapted) {
353             this.adapted = adapted;
354         }
355 
356         /**
357          * {@inheritDoc}
358          */
359         @Override
360         public boolean acceptsURL(String url) throws SQLException {
361             return adapted.acceptsURL(url);
362         }
363 
364         /**
365          * {@inheritDoc}
366          */
367         @Override
368         public Connection connect(String url, Properties info) throws SQLException {
369             return adapted.connect(url, info);
370         }
371 
372         /**
373          * {@inheritDoc}
374          */
375         @Override
376         public int getMajorVersion() {
377             return adapted.getMajorVersion();
378         }
379 
380         /**
381          * {@inheritDoc}
382          */
383         @Override
384         public int getMinorVersion() {
385             return adapted.getMinorVersion();
386         }
387 
388         /**
389          * {@inheritDoc}
390          */
391         @Override
392         public DriverPropertyInfo[] getPropertyInfo(String url, Properties info) throws SQLException {
393             return adapted.getPropertyInfo(url, info);
394         }
395 
396         /**
397          * {@inheritDoc}
398          */
399         @Override
400         public boolean jdbcCompliant() {
401             return adapted.jdbcCompliant();
402         }
403 
404         /**
405          * Java 1.7 method.
406          */
407         public Logger getParentLogger() throws SQLFeatureNotSupportedException {
408             if (parentLoggerSupported) {
409                 try {
410                     Method method = adapted.getClass().getMethod("getParentLogger", new Class[0]);
411                     return (Logger)method.invoke(adapted, new Object[0]);
412                 } catch (NoSuchMethodException e) {
413                     parentLoggerSupported = false;
414                     throw new SQLFeatureNotSupportedException(e);
415                 } catch (IllegalAccessException e) {
416                     parentLoggerSupported = false;
417                     throw new SQLFeatureNotSupportedException(e);
418                 } catch (InvocationTargetException e) {
419                     parentLoggerSupported = false;
420                     throw new SQLFeatureNotSupportedException(e);
421                 }
422             }
423             throw new SQLFeatureNotSupportedException();
424         }
425 
426     }
427 
428 }