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.dbcp2; 018 019import java.io.InputStream; 020import java.io.Reader; 021import java.math.BigDecimal; 022import java.net.URL; 023import java.sql.Array; 024import java.sql.Blob; 025import java.sql.Clob; 026import java.sql.Connection; 027import java.sql.DatabaseMetaData; 028import java.sql.Date; 029import java.sql.Ref; 030import java.sql.ResultSet; 031import java.sql.RowId; 032import java.sql.SQLException; 033import java.sql.SQLFeatureNotSupportedException; 034import java.sql.SQLXML; 035import java.sql.Statement; 036import java.sql.Time; 037import java.sql.Timestamp; 038import java.util.concurrent.Executor; 039import java.util.logging.Logger; 040 041import javax.sql.CommonDataSource; 042 043/** 044 * Defines bridge methods to JDBC 4.1 (Java 7) methods to allow call sites to operate safely (without 045 * {@link AbstractMethodError}) when using a JDBC driver written for JDBC 4.0 (Java 6). 046 * 047 * @since 2.6.0 048 */ 049public class Jdbc41Bridge { 050 051 /** 052 * Delegates to {@link Connection#abort(Executor)} without throwing a {@link AbstractMethodError}. 053 * <p> 054 * If the JDBC driver does not implement {@link Connection#abort(Executor)}, then call {@link Connection#close()}. 055 * </p> 056 * 057 * @param connection 058 * the receiver 059 * @param executor 060 * See {@link Connection#abort(Executor)}. 061 * @throws SQLException 062 * See {@link Connection#abort(Executor)}. 063 * @see Connection#abort(Executor) 064 */ 065 public static void abort(final Connection connection, final Executor executor) throws SQLException { 066 try { 067 connection.abort(executor); 068 } catch (final AbstractMethodError e) { 069 connection.close(); 070 } 071 } 072 073 /** 074 * Delegates to {@link DatabaseMetaData#generatedKeyAlwaysReturned()} without throwing a 075 * {@link AbstractMethodError}. 076 * <p> 077 * If the JDBC driver does not implement {@link DatabaseMetaData#generatedKeyAlwaysReturned()}, then return false. 078 * </p> 079 * 080 * @param databaseMetaData 081 * See {@link DatabaseMetaData#generatedKeyAlwaysReturned()} 082 * @return See {@link DatabaseMetaData#generatedKeyAlwaysReturned()} 083 * @throws SQLException 084 * See {@link DatabaseMetaData#generatedKeyAlwaysReturned()} 085 * @see DatabaseMetaData#generatedKeyAlwaysReturned() 086 */ 087 public static boolean generatedKeyAlwaysReturned(final DatabaseMetaData databaseMetaData) throws SQLException { 088 try { 089 return databaseMetaData.generatedKeyAlwaysReturned(); 090 } catch (final AbstractMethodError e) { 091 // do nothing 092 return false; 093 } 094 } 095 096 /** 097 * Delegates to {@link Connection#getNetworkTimeout()} without throwing a {@link AbstractMethodError}. 098 * <p> 099 * If the JDBC driver does not implement {@link Connection#getNetworkTimeout()}, then return 0. 100 * </p> 101 * 102 * @param connection 103 * the receiver 104 * @return See {@link Connection#getNetworkTimeout()} 105 * @throws SQLException 106 * See {@link Connection#getNetworkTimeout()} 107 * @see Connection#getNetworkTimeout() 108 */ 109 public static int getNetworkTimeout(final Connection connection) throws SQLException { 110 try { 111 return connection.getNetworkTimeout(); 112 } catch (final AbstractMethodError e) { 113 return 0; 114 } 115 } 116 117 /** 118 * Delegates to {@link ResultSet#getObject(int, Class)} without throwing a {@link AbstractMethodError}. 119 * <p> 120 * If the JDBC driver does not implement {@link ResultSet#getObject(int, Class)}, then return 0. 121 * </p> 122 * 123 * @param <T> 124 * See {@link ResultSet#getObject(int, Class)} 125 * @param resultSet 126 * See {@link ResultSet#getObject(int, Class)} 127 * @param columnIndex 128 * See {@link ResultSet#getObject(int, Class)} 129 * @param type 130 * See {@link ResultSet#getObject(int, Class)} 131 * @return See {@link ResultSet#getObject(int, Class)} 132 * @throws SQLException 133 * See {@link ResultSet#getObject(int, Class)} 134 * @see ResultSet#getObject(int, Class) 135 */ 136 @SuppressWarnings("unchecked") 137 public static <T> T getObject(final ResultSet resultSet, final int columnIndex, final Class<T> type) 138 throws SQLException { 139 try { 140 return resultSet.getObject(columnIndex, type); 141 } catch (final AbstractMethodError e) { 142 if (type == String.class) { 143 return (T) resultSet.getString(columnIndex); 144 } 145 // Numbers 146 if (type == Integer.class) { 147 return (T) Integer.valueOf(resultSet.getInt(columnIndex)); 148 } 149 if (type == Long.class) { 150 return (T) Long.valueOf(resultSet.getLong(columnIndex)); 151 } 152 if (type == Double.class) { 153 return (T) Double.valueOf(resultSet.getDouble(columnIndex)); 154 } 155 if (type == Float.class) { 156 return (T) Float.valueOf(resultSet.getFloat(columnIndex)); 157 } 158 if (type == Short.class) { 159 return (T) Short.valueOf(resultSet.getShort(columnIndex)); 160 } 161 if (type == BigDecimal.class) { 162 return (T) resultSet.getBigDecimal(columnIndex); 163 } 164 if (type == Byte.class) { 165 return (T) Byte.valueOf(resultSet.getByte(columnIndex)); 166 } 167 // Dates 168 if (type == Date.class) { 169 return (T) resultSet.getDate(columnIndex); 170 } 171 if (type == Time.class) { 172 return (T) resultSet.getTime(columnIndex); 173 } 174 if (type == Timestamp.class) { 175 return (T) resultSet.getTimestamp(columnIndex); 176 } 177 // Streams 178 if (type == InputStream.class) { 179 return (T) resultSet.getBinaryStream(columnIndex); 180 } 181 if (type == Reader.class) { 182 return (T) resultSet.getCharacterStream(columnIndex); 183 } 184 // Other 185 if (type == Object.class) { 186 return (T) resultSet.getObject(columnIndex); 187 } 188 if (type == Boolean.class) { 189 return (T) Boolean.valueOf(resultSet.getBoolean(columnIndex)); 190 } 191 if (type == Array.class) { 192 return (T) resultSet.getArray(columnIndex); 193 } 194 if (type == Blob.class) { 195 return (T) resultSet.getBlob(columnIndex); 196 } 197 if (type == Clob.class) { 198 return (T) resultSet.getClob(columnIndex); 199 } 200 if (type == Ref.class) { 201 return (T) resultSet.getRef(columnIndex); 202 } 203 if (type == RowId.class) { 204 return (T) resultSet.getRowId(columnIndex); 205 } 206 if (type == SQLXML.class) { 207 return (T) resultSet.getSQLXML(columnIndex); 208 } 209 if (type == URL.class) { 210 return (T) resultSet.getURL(columnIndex); 211 } 212 throw new SQLFeatureNotSupportedException( 213 String.format("resultSet=%s, columnIndex=%,d, type=%s", resultSet, columnIndex, type)); 214 } 215 } 216 217 /** 218 * Delegates to {@link ResultSet#getObject(String, Class)} without throwing a {@link AbstractMethodError}. 219 * 220 * @param <T> 221 * See {@link ResultSet#getObject(String, Class)} 222 * @param resultSet 223 * See {@link ResultSet#getObject(String, Class)} 224 * @param columnLabel 225 * See {@link ResultSet#getObject(String, Class)} 226 * @param type 227 * See {@link ResultSet#getObject(String, Class)} 228 * @return See {@link ResultSet#getObject(String, Class)} 229 * @throws SQLException 230 * See {@link ResultSet#getObject(String, Class)} 231 * @see ResultSet#getObject(int, Class) 232 */ 233 @SuppressWarnings("unchecked") 234 public static <T> T getObject(final ResultSet resultSet, final String columnLabel, final Class<T> type) 235 throws SQLException { 236 try { 237 return resultSet.getObject(columnLabel, type); 238 } catch (final AbstractMethodError e) { 239 // Numbers 240 if (type == Integer.class) { 241 return (T) Integer.valueOf(resultSet.getInt(columnLabel)); 242 } 243 if (type == Long.class) { 244 return (T) Long.valueOf(resultSet.getLong(columnLabel)); 245 } 246 if (type == Double.class) { 247 return (T) Double.valueOf(resultSet.getDouble(columnLabel)); 248 } 249 if (type == Float.class) { 250 return (T) Float.valueOf(resultSet.getFloat(columnLabel)); 251 } 252 if (type == Short.class) { 253 return (T) Short.valueOf(resultSet.getShort(columnLabel)); 254 } 255 if (type == BigDecimal.class) { 256 return (T) resultSet.getBigDecimal(columnLabel); 257 } 258 if (type == Byte.class) { 259 return (T) Byte.valueOf(resultSet.getByte(columnLabel)); 260 } 261 // Dates 262 if (type == Date.class) { 263 return (T) resultSet.getDate(columnLabel); 264 } 265 if (type == Time.class) { 266 return (T) resultSet.getTime(columnLabel); 267 } 268 if (type == Timestamp.class) { 269 return (T) resultSet.getTimestamp(columnLabel); 270 } 271 // Streams 272 if (type == InputStream.class) { 273 return (T) resultSet.getBinaryStream(columnLabel); 274 } 275 if (type == Reader.class) { 276 return (T) resultSet.getCharacterStream(columnLabel); 277 } 278 // Other 279 if (type == Object.class) { 280 return (T) resultSet.getObject(columnLabel); 281 } 282 if (type == Boolean.class) { 283 return (T) Boolean.valueOf(resultSet.getBoolean(columnLabel)); 284 } 285 if (type == Array.class) { 286 return (T) resultSet.getArray(columnLabel); 287 } 288 if (type == Blob.class) { 289 return (T) resultSet.getBlob(columnLabel); 290 } 291 if (type == Clob.class) { 292 return (T) resultSet.getClob(columnLabel); 293 } 294 if (type == Ref.class) { 295 return (T) resultSet.getRef(columnLabel); 296 } 297 if (type == RowId.class) { 298 return (T) resultSet.getRowId(columnLabel); 299 } 300 if (type == SQLXML.class) { 301 return (T) resultSet.getSQLXML(columnLabel); 302 } 303 if (type == URL.class) { 304 return (T) resultSet.getURL(columnLabel); 305 } 306 throw new SQLFeatureNotSupportedException( 307 String.format("resultSet=%s, columnLabel=%s, type=%s", resultSet, columnLabel, type)); 308 } 309 } 310 311 /** 312 * Delegates to {@link DatabaseMetaData#getPseudoColumns(String, String, String, String)} without throwing a 313 * {@link AbstractMethodError}. 314 * <p> 315 * If the JDBC driver does not implement {@link DatabaseMetaData#getPseudoColumns(String, String, String, String)}, 316 * then return null. 317 * </p> 318 * 319 * @param databaseMetaData 320 * the receiver 321 * @param catalog 322 * See {@link DatabaseMetaData#getPseudoColumns(String, String, String, String)} 323 * @param schemaPattern 324 * See {@link DatabaseMetaData#getPseudoColumns(String, String, String, String)} 325 * @param tableNamePattern 326 * See {@link DatabaseMetaData#getPseudoColumns(String, String, String, String)} 327 * @param columnNamePattern 328 * See {@link DatabaseMetaData#getPseudoColumns(String, String, String, String)} 329 * @return See {@link DatabaseMetaData#getPseudoColumns(String, String, String, String)} 330 * @throws SQLException 331 * See {@link DatabaseMetaData#getPseudoColumns(String, String, String, String)} 332 * @see DatabaseMetaData#getPseudoColumns(String, String, String, String) 333 */ 334 public static ResultSet getPseudoColumns(final DatabaseMetaData databaseMetaData, final String catalog, 335 final String schemaPattern, final String tableNamePattern, final String columnNamePattern) 336 throws SQLException { 337 try { 338 return databaseMetaData.getPseudoColumns(catalog, schemaPattern, tableNamePattern, columnNamePattern); 339 } catch (final AbstractMethodError e) { 340 // do nothing 341 return null; 342 } 343 } 344 345 /** 346 * Delegates to {@link Connection#getSchema()} without throwing a {@link AbstractMethodError}. 347 * <p> 348 * If the JDBC driver does not implement {@link Connection#getSchema()}, then return null. 349 * </p> 350 * 351 * @param connection 352 * the receiver 353 * @return null for a JDBC 4 driver or a value per {@link Connection#getSchema()}. 354 * @throws SQLException 355 * See {@link Connection#getSchema()}. 356 * @see Connection#getSchema() 357 */ 358 public static String getSchema(final Connection connection) throws SQLException { 359 try { 360 return connection.getSchema(); 361 } catch (final AbstractMethodError e) { 362 // do nothing 363 return null; 364 } 365 } 366 367 /** 368 * Delegates to {@link Connection#setNetworkTimeout(Executor, int)} without throwing a {@link AbstractMethodError}. 369 * <p> 370 * If the JDBC driver does not implement {@link Connection#setNetworkTimeout(Executor, int)}, then do nothing. 371 * </p> 372 * 373 * @param connection 374 * the receiver 375 * @param executor 376 * See {@link Connection#setNetworkTimeout(Executor, int)} 377 * @param milliseconds 378 * {@link Connection#setNetworkTimeout(Executor, int)} 379 * @throws SQLException 380 * {@link Connection#setNetworkTimeout(Executor, int)} 381 * @see Connection#setNetworkTimeout(Executor, int) 382 */ 383 public static void setNetworkTimeout(final Connection connection, final Executor executor, final int milliseconds) 384 throws SQLException { 385 try { 386 connection.setNetworkTimeout(executor, milliseconds); 387 } catch (final AbstractMethodError e) { 388 // do nothing 389 } 390 } 391 392 /** 393 * Delegates to {@link Connection#setSchema(String)} without throwing a {@link AbstractMethodError}. 394 * <p> 395 * If the JDBC driver does not implement {@link Connection#setSchema(String)}, then do nothing. 396 * </p> 397 * 398 * @param connection 399 * the receiver 400 * @param schema 401 * See {@link Connection#setSchema(String)}. 402 * @throws SQLException 403 * See {@link Connection#setSchema(String)}. 404 * @see Connection#setSchema(String) 405 */ 406 public static void setSchema(final Connection connection, final String schema) throws SQLException { 407 try { 408 connection.setSchema(schema); 409 } catch (final AbstractMethodError e) { 410 // do nothing 411 } 412 } 413 414 /** 415 * Delegates to {@link Statement#closeOnCompletion()} without throwing a {@link AbstractMethodError}. 416 * <p> 417 * If the JDBC driver does not implement {@link Statement#closeOnCompletion()}, then just check that the connection 418 * is closed to then throw a SQLException. 419 * </p> 420 * 421 * @param statement 422 * See {@link Statement#closeOnCompletion()} 423 * @throws SQLException 424 * See {@link Statement#closeOnCompletion()} 425 * @see Statement#closeOnCompletion() 426 */ 427 public static void closeOnCompletion(final Statement statement) throws SQLException { 428 try { 429 statement.closeOnCompletion(); 430 } catch (final AbstractMethodError e) { 431 if (statement.isClosed()) { 432 throw new SQLException("Statement closed"); 433 } 434 } 435 } 436 437 /** 438 * Delegates to {@link Statement#isCloseOnCompletion()} without throwing a {@link AbstractMethodError}. 439 * <p> 440 * If the JDBC driver does not implement {@link Statement#isCloseOnCompletion()}, then just check that the 441 * connection is closed to then throw a SQLException. 442 * </p> 443 * 444 * @param statement 445 * See {@link Statement#isCloseOnCompletion()} 446 * @return See {@link Statement#isCloseOnCompletion()} 447 * @throws SQLException 448 * See {@link Statement#isCloseOnCompletion()} 449 * @see Statement#closeOnCompletion() 450 */ 451 public static boolean isCloseOnCompletion(final Statement statement) throws SQLException { 452 try { 453 return statement.isCloseOnCompletion(); 454 } catch (final AbstractMethodError e) { 455 if (statement.isClosed()) { 456 throw new SQLException("Statement closed"); 457 } 458 return false; 459 } 460 } 461 462 /** 463 * Delegates to {@link CommonDataSource#getParentLogger()} without throwing a {@link AbstractMethodError}. 464 * <p> 465 * If the JDBC driver does not implement {@link CommonDataSource#getParentLogger()}, then return null. 466 * </p> 467 * 468 * @param commonDataSource 469 * See {@link CommonDataSource#getParentLogger()} 470 * @return See {@link CommonDataSource#getParentLogger()} 471 * @throws SQLFeatureNotSupportedException 472 * See {@link CommonDataSource#getParentLogger()} 473 */ 474 public static Logger getParentLogger(final CommonDataSource commonDataSource) throws SQLFeatureNotSupportedException { 475 try { 476 return commonDataSource.getParentLogger(); 477 } catch (final AbstractMethodError e) { 478 throw new SQLFeatureNotSupportedException("javax.sql.CommonDataSource#getParentLogger()"); 479 } 480 } 481 482}