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.sql.Connection;
24  import java.sql.Driver;
25  import java.sql.DriverPropertyInfo;
26  import java.sql.ResultSet;
27  import java.sql.SQLException;
28  import java.sql.SQLFeatureNotSupportedException;
29  import java.sql.Statement;
30  import java.util.Properties;
31  import java.util.logging.Logger;
32  
33  /**
34   * A collection of JDBC helper methods.  This class is thread safe.
35   */
36  public final class DbUtils {
37  
38      /**
39       * Simple {@link Driver} proxy class that proxies a JDBC Driver loaded dynamically.
40       *
41       * @since 1.6
42       */
43      static final class DriverProxy implements Driver {
44  
45          /**
46           * The adapted JDBC Driver loaded dynamically.
47           */
48          private final Driver adapted;
49  
50          /**
51           * Creates a new JDBC Driver that adapts a JDBC Driver loaded dynamically.
52           *
53           * @param adapted the adapted JDBC Driver loaded dynamically.
54           */
55          public DriverProxy(final Driver adapted) {
56              this.adapted = adapted;
57          }
58  
59          /**
60           * {@inheritDoc}
61           */
62          @Override
63          public boolean acceptsURL(final String url) throws SQLException {
64              return adapted.acceptsURL(url);
65          }
66  
67          /**
68           * {@inheritDoc}
69           */
70          @Override
71          public Connection connect(final String url, final Properties info) throws SQLException {
72              return adapted.connect(url, info);
73          }
74  
75          /**
76           * {@inheritDoc}
77           */
78          @Override
79          public int getMajorVersion() {
80              return adapted.getMajorVersion();
81          }
82  
83          /**
84           * {@inheritDoc}
85           */
86          @Override
87          public int getMinorVersion() {
88              return adapted.getMinorVersion();
89          }
90  
91          /**
92           * Java 1.7 method.
93           */
94          @Override
95          public Logger getParentLogger() throws SQLFeatureNotSupportedException {
96              return adapted.getParentLogger();
97          }
98  
99          /**
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 }