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 (RuntimeException e) {
231             return false;
232         } catch (Exception e) {
233             return false;
234         }
235     }
236 
237     /**
238      * Print the stack trace for a SQLException to STDERR.
239      *
240      * @param e SQLException to print stack trace of
241      */
242     public static void printStackTrace(SQLException e) {
243         printStackTrace(e, new PrintWriter(System.err));
244     }
245 
246     /**
247      * Print the stack trace for a SQLException to a
248      * specified PrintWriter.
249      *
250      * @param e SQLException to print stack trace of
251      * @param pw PrintWriter to print to
252      */
253     public static void printStackTrace(SQLException e, PrintWriter pw) {
254 
255         SQLException next = e;
256         while (next != null) {
257             next.printStackTrace(pw);
258             next = next.getNextException();
259             if (next != null) {
260                 pw.println("Next SQLException:");
261             }
262         }
263     }
264 
265     /**
266      * Print warnings on a Connection to STDERR.
267      *
268      * @param conn Connection to print warnings from
269      */
270     public static void printWarnings(Connection conn) {
271         printWarnings(conn, new PrintWriter(System.err));
272     }
273 
274     /**
275      * Print warnings on a Connection to a specified PrintWriter.
276      *
277      * @param conn Connection to print warnings from
278      * @param pw PrintWriter to print to
279      */
280     public static void printWarnings(Connection conn, PrintWriter pw) {
281         if (conn != null) {
282             try {
283                 printStackTrace(conn.getWarnings(), pw);
284             } catch (SQLException e) {
285                 printStackTrace(e, pw);
286             }
287         }
288     }
289 
290     /**
291      * Rollback any changes made on the given connection.
292      * @param conn Connection to rollback.  A null value is legal.
293      * @throws SQLException if a database access error occurs
294      */
295     public static void rollback(Connection conn) throws SQLException {
296         if (conn != null) {
297             conn.rollback();
298         }
299     }
300 
301     /**
302      * Performs a rollback on the <code>Connection</code> then closes it,
303      * avoid closing if null.
304      *
305      * @param conn Connection to rollback.  A null value is legal.
306      * @throws SQLException if a database access error occurs
307      * @since DbUtils 1.1
308      */
309     public static void rollbackAndClose(Connection conn) throws SQLException {
310         if (conn != null) {
311             try {
312                 conn.rollback();
313             } finally {
314                 conn.close();
315             }
316         }
317     }
318 
319     /**
320      * Performs a rollback on the <code>Connection</code> then closes it,
321      * avoid closing if null and hide any SQLExceptions that occur.
322      *
323      * @param conn Connection to rollback.  A null value is legal.
324      * @since DbUtils 1.1
325      */
326     public static void rollbackAndCloseQuietly(Connection conn) {
327         try {
328             rollbackAndClose(conn);
329         } catch (SQLException e) { // NOPMD
330             // quiet
331         }
332     }
333 
334     /**
335      * Simple {@link Driver} proxy class that proxies a JDBC Driver loaded dynamically.
336      *
337      * @since 1.6
338      */
339     private static final class DriverProxy implements Driver {
340 
341         private boolean parentLoggerSupported = true;
342 
343         /**
344          * The adapted JDBC Driver loaded dynamically.
345          */
346         private final Driver adapted;
347 
348         /**
349          * Creates a new JDBC Driver that adapts a JDBC Driver loaded dynamically.
350          *
351          * @param adapted the adapted JDBC Driver loaded dynamically.
352          */
353         public DriverProxy(Driver adapted) {
354             this.adapted = adapted;
355         }
356 
357         /**
358          * {@inheritDoc}
359          */
360         @Override
361         public boolean acceptsURL(String url) throws SQLException {
362             return adapted.acceptsURL(url);
363         }
364 
365         /**
366          * {@inheritDoc}
367          */
368         @Override
369         public Connection connect(String url, Properties info) throws SQLException {
370             return adapted.connect(url, info);
371         }
372 
373         /**
374          * {@inheritDoc}
375          */
376         @Override
377         public int getMajorVersion() {
378             return adapted.getMajorVersion();
379         }
380 
381         /**
382          * {@inheritDoc}
383          */
384         @Override
385         public int getMinorVersion() {
386             return adapted.getMinorVersion();
387         }
388 
389         /**
390          * {@inheritDoc}
391          */
392         @Override
393         public DriverPropertyInfo[] getPropertyInfo(String url, Properties info) throws SQLException {
394             return adapted.getPropertyInfo(url, info);
395         }
396 
397         /**
398          * {@inheritDoc}
399          */
400         @Override
401         public boolean jdbcCompliant() {
402             return adapted.jdbcCompliant();
403         }
404 
405         /**
406          * Java 1.7 method.
407          */
408         public Logger getParentLogger() throws SQLFeatureNotSupportedException {
409             if (parentLoggerSupported) {
410                 try {
411                     Method method = adapted.getClass().getMethod("getParentLogger", new Class[0]);
412                     return (Logger)method.invoke(adapted, new Object[0]);
413                 } catch (NoSuchMethodException e) {
414                     parentLoggerSupported = false;
415                     throw new SQLFeatureNotSupportedException(e);
416                 } catch (IllegalAccessException e) {
417                     parentLoggerSupported = false;
418                     throw new SQLFeatureNotSupportedException(e);
419                 } catch (InvocationTargetException e) {
420                     parentLoggerSupported = false;
421                     throw new SQLFeatureNotSupportedException(e);
422                 }
423             }
424             throw new SQLFeatureNotSupportedException();
425         }
426 
427     }
428 
429 }