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.dbcp2;
18
19 import java.io.InputStream;
20 import java.io.Reader;
21 import java.math.BigDecimal;
22 import java.net.URL;
23 import java.sql.Array;
24 import java.sql.Blob;
25 import java.sql.Clob;
26 import java.sql.Connection;
27 import java.sql.DatabaseMetaData;
28 import java.sql.Date;
29 import java.sql.Ref;
30 import java.sql.ResultSet;
31 import java.sql.RowId;
32 import java.sql.SQLException;
33 import java.sql.SQLFeatureNotSupportedException;
34 import java.sql.SQLXML;
35 import java.sql.Statement;
36 import java.sql.Time;
37 import java.sql.Timestamp;
38 import java.util.concurrent.Executor;
39 import java.util.logging.Logger;
40
41 import javax.sql.CommonDataSource;
42
43 /**
44 * Defines bridge methods to JDBC 4.1 (Java 7 or above) methods to allow call sites to operate safely (without
45 * {@link AbstractMethodError}) when using a JDBC driver written for JDBC 4.0 (Java 6 or above).
46 * <p>
47 * There should be no need to this kind of code for JDBC 4.2 in Java 8 due to JDBC's use of default methods.
48 * </p>
49 * <p>
50 * This should probably be moved or at least copied in some form to Apache Commons DbUtils.
51 * </p>
52 *
53 * @since 2.6.0
54 */
55 public class Jdbc41Bridge {
56
57 /**
58 * Delegates to {@link Connection#abort(Executor)} without throwing an {@link AbstractMethodError}.
59 * <p>
60 * If the JDBC driver does not implement {@link Connection#abort(Executor)}, then call {@link Connection#close()}.
61 * </p>
62 *
63 * @param connection
64 * the receiver
65 * @param executor
66 * See {@link Connection#abort(Executor)}.
67 * @throws SQLException
68 * See {@link Connection#abort(Executor)}.
69 * @see Connection#abort(Executor)
70 */
71 public static void abort(final Connection connection, final Executor executor) throws SQLException {
72 try {
73 connection.abort(executor);
74 } catch (final AbstractMethodError e) {
75 connection.close();
76 }
77 }
78
79 /**
80 * Delegates to {@link Statement#closeOnCompletion()} without throwing an {@link AbstractMethodError}.
81 * <p>
82 * If the JDBC driver does not implement {@link Statement#closeOnCompletion()}, then just check that the connection
83 * is closed to then throw an SQLException.
84 * </p>
85 *
86 * @param statement
87 * See {@link Statement#closeOnCompletion()}
88 * @throws SQLException
89 * See {@link Statement#closeOnCompletion()}
90 * @see Statement#closeOnCompletion()
91 */
92 public static void closeOnCompletion(final Statement statement) throws SQLException {
93 try {
94 statement.closeOnCompletion();
95 } catch (final AbstractMethodError e) {
96 if (statement.isClosed()) {
97 throw new SQLException("Statement closed");
98 }
99 }
100 }
101
102 /**
103 * Delegates to {@link DatabaseMetaData#generatedKeyAlwaysReturned()} without throwing a
104 * {@link AbstractMethodError}.
105 * <p>
106 * If the JDBC driver does not implement {@link DatabaseMetaData#generatedKeyAlwaysReturned()}, then return false.
107 * </p>
108 *
109 * @param databaseMetaData
110 * See {@link DatabaseMetaData#generatedKeyAlwaysReturned()}
111 * @return See {@link DatabaseMetaData#generatedKeyAlwaysReturned()}
112 * @throws SQLException
113 * See {@link DatabaseMetaData#generatedKeyAlwaysReturned()}
114 * @see DatabaseMetaData#generatedKeyAlwaysReturned()
115 */
116 public static boolean generatedKeyAlwaysReturned(final DatabaseMetaData databaseMetaData) throws SQLException {
117 try {
118 return databaseMetaData.generatedKeyAlwaysReturned();
119 } catch (final AbstractMethodError e) {
120 // do nothing
121 return false;
122 }
123 }
124
125 /**
126 * Delegates to {@link Connection#getNetworkTimeout()} without throwing an {@link AbstractMethodError}.
127 * <p>
128 * If the JDBC driver does not implement {@link Connection#getNetworkTimeout()}, then return 0.
129 * </p>
130 *
131 * @param connection
132 * the receiver
133 * @return See {@link Connection#getNetworkTimeout()}
134 * @throws SQLException
135 * See {@link Connection#getNetworkTimeout()}
136 * @see Connection#getNetworkTimeout()
137 */
138 public static int getNetworkTimeout(final Connection connection) throws SQLException {
139 try {
140 return connection.getNetworkTimeout();
141 } catch (final AbstractMethodError e) {
142 return 0;
143 }
144 }
145
146 /**
147 * Delegates to {@link ResultSet#getObject(int, Class)} without throwing an {@link AbstractMethodError}.
148 * <p>
149 * If the JDBC driver does not implement {@link ResultSet#getObject(int, Class)}, then return 0.
150 * </p>
151 *
152 * @param <T>
153 * See {@link ResultSet#getObject(int, Class)}
154 * @param resultSet
155 * See {@link ResultSet#getObject(int, Class)}
156 * @param columnIndex
157 * See {@link ResultSet#getObject(int, Class)}
158 * @param type
159 * See {@link ResultSet#getObject(int, Class)}
160 * @return See {@link ResultSet#getObject(int, Class)}
161 * @throws SQLException
162 * See {@link ResultSet#getObject(int, Class)}
163 * @see ResultSet#getObject(int, Class)
164 */
165 @SuppressWarnings("unchecked")
166 public static <T> T getObject(final ResultSet resultSet, final int columnIndex, final Class<T> type)
167 throws SQLException {
168 try {
169 return resultSet.getObject(columnIndex, type);
170 } catch (final AbstractMethodError e) {
171 if (type == String.class) {
172 return (T) resultSet.getString(columnIndex);
173 }
174 // Numbers
175 if (type == Integer.class) {
176 return (T) Integer.valueOf(resultSet.getInt(columnIndex));
177 }
178 if (type == Long.class) {
179 return (T) Long.valueOf(resultSet.getLong(columnIndex));
180 }
181 if (type == Double.class) {
182 return (T) Double.valueOf(resultSet.getDouble(columnIndex));
183 }
184 if (type == Float.class) {
185 return (T) Float.valueOf(resultSet.getFloat(columnIndex));
186 }
187 if (type == Short.class) {
188 return (T) Short.valueOf(resultSet.getShort(columnIndex));
189 }
190 if (type == BigDecimal.class) {
191 return (T) resultSet.getBigDecimal(columnIndex);
192 }
193 if (type == Byte.class) {
194 return (T) Byte.valueOf(resultSet.getByte(columnIndex));
195 }
196 // Dates
197 if (type == Date.class) {
198 return (T) resultSet.getDate(columnIndex);
199 }
200 if (type == Time.class) {
201 return (T) resultSet.getTime(columnIndex);
202 }
203 if (type == Timestamp.class) {
204 return (T) resultSet.getTimestamp(columnIndex);
205 }
206 // Streams
207 if (type == InputStream.class) {
208 return (T) resultSet.getBinaryStream(columnIndex);
209 }
210 if (type == Reader.class) {
211 return (T) resultSet.getCharacterStream(columnIndex);
212 }
213 // Other
214 if (type == Object.class) {
215 return (T) resultSet.getObject(columnIndex);
216 }
217 if (type == Boolean.class) {
218 return (T) Boolean.valueOf(resultSet.getBoolean(columnIndex));
219 }
220 if (type == Array.class) {
221 return (T) resultSet.getArray(columnIndex);
222 }
223 if (type == Blob.class) {
224 return (T) resultSet.getBlob(columnIndex);
225 }
226 if (type == Clob.class) {
227 return (T) resultSet.getClob(columnIndex);
228 }
229 if (type == Ref.class) {
230 return (T) resultSet.getRef(columnIndex);
231 }
232 if (type == RowId.class) {
233 return (T) resultSet.getRowId(columnIndex);
234 }
235 if (type == SQLXML.class) {
236 return (T) resultSet.getSQLXML(columnIndex);
237 }
238 if (type == URL.class) {
239 return (T) resultSet.getURL(columnIndex);
240 }
241 throw new SQLFeatureNotSupportedException(
242 String.format("resultSet=%s, columnIndex=%,d, type=%s", resultSet, columnIndex, type));
243 }
244 }
245
246 /**
247 * Delegates to {@link ResultSet#getObject(String, Class)} without throwing an {@link AbstractMethodError}.
248 *
249 * @param <T>
250 * See {@link ResultSet#getObject(String, Class)}
251 * @param resultSet
252 * See {@link ResultSet#getObject(String, Class)}
253 * @param columnLabel
254 * See {@link ResultSet#getObject(String, Class)}
255 * @param type
256 * See {@link ResultSet#getObject(String, Class)}
257 * @return See {@link ResultSet#getObject(String, Class)}
258 * @throws SQLException
259 * See {@link ResultSet#getObject(String, Class)}
260 * @see ResultSet#getObject(int, Class)
261 */
262 @SuppressWarnings("unchecked")
263 public static <T> T getObject(final ResultSet resultSet, final String columnLabel, final Class<T> type)
264 throws SQLException {
265 try {
266 return resultSet.getObject(columnLabel, type);
267 } catch (final AbstractMethodError e) {
268 // Numbers
269 if (type == Integer.class) {
270 return (T) Integer.valueOf(resultSet.getInt(columnLabel));
271 }
272 if (type == Long.class) {
273 return (T) Long.valueOf(resultSet.getLong(columnLabel));
274 }
275 if (type == Double.class) {
276 return (T) Double.valueOf(resultSet.getDouble(columnLabel));
277 }
278 if (type == Float.class) {
279 return (T) Float.valueOf(resultSet.getFloat(columnLabel));
280 }
281 if (type == Short.class) {
282 return (T) Short.valueOf(resultSet.getShort(columnLabel));
283 }
284 if (type == BigDecimal.class) {
285 return (T) resultSet.getBigDecimal(columnLabel);
286 }
287 if (type == Byte.class) {
288 return (T) Byte.valueOf(resultSet.getByte(columnLabel));
289 }
290 // Dates
291 if (type == Date.class) {
292 return (T) resultSet.getDate(columnLabel);
293 }
294 if (type == Time.class) {
295 return (T) resultSet.getTime(columnLabel);
296 }
297 if (type == Timestamp.class) {
298 return (T) resultSet.getTimestamp(columnLabel);
299 }
300 // Streams
301 if (type == InputStream.class) {
302 return (T) resultSet.getBinaryStream(columnLabel);
303 }
304 if (type == Reader.class) {
305 return (T) resultSet.getCharacterStream(columnLabel);
306 }
307 // Other
308 if (type == Object.class) {
309 return (T) resultSet.getObject(columnLabel);
310 }
311 if (type == Boolean.class) {
312 return (T) Boolean.valueOf(resultSet.getBoolean(columnLabel));
313 }
314 if (type == Array.class) {
315 return (T) resultSet.getArray(columnLabel);
316 }
317 if (type == Blob.class) {
318 return (T) resultSet.getBlob(columnLabel);
319 }
320 if (type == Clob.class) {
321 return (T) resultSet.getClob(columnLabel);
322 }
323 if (type == Ref.class) {
324 return (T) resultSet.getRef(columnLabel);
325 }
326 if (type == RowId.class) {
327 return (T) resultSet.getRowId(columnLabel);
328 }
329 if (type == SQLXML.class) {
330 return (T) resultSet.getSQLXML(columnLabel);
331 }
332 if (type == URL.class) {
333 return (T) resultSet.getURL(columnLabel);
334 }
335 throw new SQLFeatureNotSupportedException(
336 String.format("resultSet=%s, columnLabel=%s, type=%s", resultSet, columnLabel, type));
337 }
338 }
339
340 /**
341 * Delegates to {@link CommonDataSource#getParentLogger()} without throwing an {@link AbstractMethodError}.
342 * <p>
343 * If the JDBC driver does not implement {@link CommonDataSource#getParentLogger()}, then return null.
344 * </p>
345 *
346 * @param commonDataSource
347 * See {@link CommonDataSource#getParentLogger()}
348 * @return See {@link CommonDataSource#getParentLogger()}
349 * @throws SQLFeatureNotSupportedException
350 * See {@link CommonDataSource#getParentLogger()}
351 */
352 public static Logger getParentLogger(final CommonDataSource commonDataSource) throws SQLFeatureNotSupportedException {
353 try {
354 return commonDataSource.getParentLogger();
355 } catch (final AbstractMethodError e) {
356 throw new SQLFeatureNotSupportedException("javax.sql.CommonDataSource#getParentLogger()");
357 }
358 }
359
360 /**
361 * Delegates to {@link DatabaseMetaData#getPseudoColumns(String, String, String, String)} without throwing a
362 * {@link AbstractMethodError}.
363 * <p>
364 * If the JDBC driver does not implement {@link DatabaseMetaData#getPseudoColumns(String, String, String, String)},
365 * then return null.
366 * </p>
367 *
368 * @param databaseMetaData
369 * the receiver
370 * @param catalog
371 * See {@link DatabaseMetaData#getPseudoColumns(String, String, String, String)}
372 * @param schemaPattern
373 * See {@link DatabaseMetaData#getPseudoColumns(String, String, String, String)}
374 * @param tableNamePattern
375 * See {@link DatabaseMetaData#getPseudoColumns(String, String, String, String)}
376 * @param columnNamePattern
377 * See {@link DatabaseMetaData#getPseudoColumns(String, String, String, String)}
378 * @return See {@link DatabaseMetaData#getPseudoColumns(String, String, String, String)}
379 * @throws SQLException
380 * See {@link DatabaseMetaData#getPseudoColumns(String, String, String, String)}
381 * @see DatabaseMetaData#getPseudoColumns(String, String, String, String)
382 */
383 public static ResultSet getPseudoColumns(final DatabaseMetaData databaseMetaData, final String catalog,
384 final String schemaPattern, final String tableNamePattern, final String columnNamePattern)
385 throws SQLException {
386 try {
387 return databaseMetaData.getPseudoColumns(catalog, schemaPattern, tableNamePattern, columnNamePattern);
388 } catch (final AbstractMethodError e) {
389 // do nothing
390 return null;
391 }
392 }
393
394 /**
395 * Delegates to {@link Connection#getSchema()} without throwing an {@link AbstractMethodError}.
396 * <p>
397 * If the JDBC driver does not implement {@link Connection#getSchema()}, then return null.
398 * </p>
399 *
400 * @param connection
401 * the receiver
402 * @return null for a JDBC 4 driver or a value per {@link Connection#getSchema()}.
403 * @throws SQLException
404 * See {@link Connection#getSchema()}.
405 * @see Connection#getSchema()
406 */
407 public static String getSchema(final Connection connection) throws SQLException {
408 try {
409 return connection.getSchema();
410 } catch (final AbstractMethodError e) {
411 // do nothing
412 return null;
413 }
414 }
415
416 /**
417 * Delegates to {@link Statement#isCloseOnCompletion()} without throwing an {@link AbstractMethodError}.
418 * <p>
419 * If the JDBC driver does not implement {@link Statement#isCloseOnCompletion()}, then just check that the
420 * connection is closed to then throw an SQLException.
421 * </p>
422 *
423 * @param statement
424 * See {@link Statement#isCloseOnCompletion()}
425 * @return See {@link Statement#isCloseOnCompletion()}
426 * @throws SQLException
427 * See {@link Statement#isCloseOnCompletion()}
428 * @see Statement#closeOnCompletion()
429 */
430 public static boolean isCloseOnCompletion(final Statement statement) throws SQLException {
431 try {
432 return statement.isCloseOnCompletion();
433 } catch (final AbstractMethodError e) {
434 if (statement.isClosed()) {
435 throw new SQLException("Statement closed");
436 }
437 return false;
438 }
439 }
440
441 /**
442 * Delegates to {@link Connection#setNetworkTimeout(Executor, int)} without throwing an {@link AbstractMethodError}.
443 * <p>
444 * If the JDBC driver does not implement {@link Connection#setNetworkTimeout(Executor, int)}, then do nothing.
445 * </p>
446 *
447 * @param connection
448 * the receiver
449 * @param executor
450 * See {@link Connection#setNetworkTimeout(Executor, int)}
451 * @param milliseconds
452 * {@link Connection#setNetworkTimeout(Executor, int)}
453 * @throws SQLException
454 * {@link Connection#setNetworkTimeout(Executor, int)}
455 * @see Connection#setNetworkTimeout(Executor, int)
456 */
457 public static void setNetworkTimeout(final Connection connection, final Executor executor, final int milliseconds)
458 throws SQLException {
459 try {
460 connection.setNetworkTimeout(executor, milliseconds);
461 } catch (final AbstractMethodError ignored) {
462 // do nothing
463 }
464 }
465
466 /**
467 * Delegates to {@link Connection#setSchema(String)} without throwing an {@link AbstractMethodError}.
468 * <p>
469 * If the JDBC driver does not implement {@link Connection#setSchema(String)}, then do nothing.
470 * </p>
471 *
472 * @param connection
473 * the receiver
474 * @param schema
475 * See {@link Connection#setSchema(String)}.
476 * @throws SQLException
477 * See {@link Connection#setSchema(String)}.
478 * @see Connection#setSchema(String)
479 */
480 public static void setSchema(final Connection connection, final String schema) throws SQLException {
481 try {
482 connection.setSchema(schema);
483 } catch (final AbstractMethodError ignored) {
484 // do nothing
485 }
486 }
487
488 }