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}