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 }