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 */ 017 018package org.apache.commons.dbcp2; 019 020import java.sql.Array; 021import java.sql.Blob; 022import java.sql.CallableStatement; 023import java.sql.ClientInfoStatus; 024import java.sql.Clob; 025import java.sql.Connection; 026import java.sql.DatabaseMetaData; 027import java.sql.NClob; 028import java.sql.PreparedStatement; 029import java.sql.ResultSet; 030import java.sql.SQLClientInfoException; 031import java.sql.SQLException; 032import java.sql.SQLWarning; 033import java.sql.SQLXML; 034import java.sql.Savepoint; 035import java.sql.Statement; 036import java.sql.Struct; 037import java.util.ArrayList; 038import java.util.Collections; 039import java.util.List; 040import java.util.Map; 041import java.util.Properties; 042import java.util.concurrent.Executor; 043 044/** 045 * A base delegating implementation of {@link Connection}. 046 * <p> 047 * All of the methods from the {@link Connection} interface simply check to see that the {@link Connection} is active, 048 * and call the corresponding method on the "delegate" provided in my constructor. 049 * </p> 050 * <p> 051 * Extends AbandonedTrace to implement Connection tracking and logging of code which created the Connection. Tracking 052 * the Connection ensures that the AbandonedObjectPool can close this connection and recycle it if its pool of 053 * connections is nearing exhaustion and this connection's last usage is older than the removeAbandonedTimeout. 054 * </p> 055 * 056 * @param <C> 057 * the Connection type 058 * 059 * @since 2.0 060 */ 061public class DelegatingConnection<C extends Connection> extends AbandonedTrace implements Connection { 062 063 private static final Map<String, ClientInfoStatus> EMPTY_FAILED_PROPERTIES = Collections 064 .<String, ClientInfoStatus>emptyMap(); 065 066 /** My delegate {@link Connection}. */ 067 private volatile C connection; 068 069 private volatile boolean closed; 070 071 private boolean cacheState = true; 072 private Boolean cachedAutoCommit; 073 private Boolean cachedReadOnly; 074 private String cachedCatalog; 075 private String cachedSchema; 076 private Integer defaultQueryTimeoutSeconds; 077 078 /** 079 * Creates a wrapper for the Connection which traces this Connection in the AbandonedObjectPool. 080 * 081 * @param connection the {@link Connection} to delegate all calls to. 082 */ 083 public DelegatingConnection(final C connection) { 084 this.connection = connection; 085 } 086 087 @Override 088 public void abort(final Executor executor) throws SQLException { 089 try { 090 Jdbc41Bridge.abort(connection, executor); 091 } catch (final SQLException e) { 092 handleException(e); 093 } 094 } 095 096 protected void activate() { 097 closed = false; 098 setLastUsed(); 099 if (connection instanceof DelegatingConnection) { 100 ((DelegatingConnection<?>) connection).activate(); 101 } 102 } 103 104 protected void checkOpen() throws SQLException { 105 if (closed) { 106 if (null != connection) { 107 String label = ""; 108 try { 109 label = connection.toString(); 110 } catch (final Exception ex) { 111 // ignore, leave label empty 112 } 113 throw new SQLException("Connection " + label + " is closed."); 114 } 115 throw new SQLException("Connection is null."); 116 } 117 } 118 119 /** 120 * Can be used to clear cached state when it is known that the underlying connection may have been accessed 121 * directly. 122 */ 123 public void clearCachedState() { 124 cachedAutoCommit = null; 125 cachedReadOnly = null; 126 cachedSchema = null; 127 cachedCatalog = null; 128 if (connection instanceof DelegatingConnection) { 129 ((DelegatingConnection<?>) connection).clearCachedState(); 130 } 131 } 132 133 @Override 134 public void clearWarnings() throws SQLException { 135 checkOpen(); 136 try { 137 connection.clearWarnings(); 138 } catch (final SQLException e) { 139 handleException(e); 140 } 141 } 142 143 /** 144 * Closes the underlying connection, and close any Statements that were not explicitly closed. Sub-classes that 145 * override this method must: 146 * <ol> 147 * <li>Call passivate()</li> 148 * <li>Call close (or the equivalent appropriate action) on the wrapped connection</li> 149 * <li>Set _closed to <code>false</code></li> 150 * </ol> 151 */ 152 @Override 153 public void close() throws SQLException { 154 if (!closed) { 155 closeInternal(); 156 } 157 } 158 159 protected final void closeInternal() throws SQLException { 160 try { 161 passivate(); 162 } finally { 163 if (connection != null) { 164 boolean connectionIsClosed; 165 try { 166 connectionIsClosed = connection.isClosed(); 167 } catch (final SQLException e) { 168 // not sure what the state is, so assume the connection is open. 169 connectionIsClosed = false; 170 } 171 try { 172 // DBCP-512: Avoid exceptions when closing a connection in mutli-threaded use case. 173 // Avoid closing again, which should be a no-op, but some drivers like H2 throw an exception when 174 // closing from multiple threads. 175 if (!connectionIsClosed) { 176 connection.close(); 177 } 178 } finally { 179 closed = true; 180 } 181 } else { 182 closed = true; 183 } 184 } 185 } 186 187 @Override 188 public void commit() throws SQLException { 189 checkOpen(); 190 try { 191 connection.commit(); 192 } catch (final SQLException e) { 193 handleException(e); 194 } 195 } 196 197 @Override 198 public Array createArrayOf(final String typeName, final Object[] elements) throws SQLException { 199 checkOpen(); 200 try { 201 return connection.createArrayOf(typeName, elements); 202 } catch (final SQLException e) { 203 handleException(e); 204 return null; 205 } 206 } 207 208 @Override 209 public Blob createBlob() throws SQLException { 210 checkOpen(); 211 try { 212 return connection.createBlob(); 213 } catch (final SQLException e) { 214 handleException(e); 215 return null; 216 } 217 } 218 219 @Override 220 public Clob createClob() throws SQLException { 221 checkOpen(); 222 try { 223 return connection.createClob(); 224 } catch (final SQLException e) { 225 handleException(e); 226 return null; 227 } 228 } 229 230 @Override 231 public NClob createNClob() throws SQLException { 232 checkOpen(); 233 try { 234 return connection.createNClob(); 235 } catch (final SQLException e) { 236 handleException(e); 237 return null; 238 } 239 } 240 241 @Override 242 public SQLXML createSQLXML() throws SQLException { 243 checkOpen(); 244 try { 245 return connection.createSQLXML(); 246 } catch (final SQLException e) { 247 handleException(e); 248 return null; 249 } 250 } 251 252 @SuppressWarnings("resource") // Caller is responsible for closing the resource. 253 @Override 254 public Statement createStatement() throws SQLException { 255 checkOpen(); 256 try { 257 return init(new DelegatingStatement(this, connection.createStatement())); 258 } catch (final SQLException e) { 259 handleException(e); 260 return null; 261 } 262 } 263 264 @SuppressWarnings("resource") // Caller is responsible for closing the resource. 265 @Override 266 public Statement createStatement(final int resultSetType, final int resultSetConcurrency) throws SQLException { 267 checkOpen(); 268 try { 269 return init(new DelegatingStatement(this, connection.createStatement(resultSetType, resultSetConcurrency))); 270 } catch (final SQLException e) { 271 handleException(e); 272 return null; 273 } 274 } 275 276 @SuppressWarnings("resource") // Caller is responsible for closing the resource. 277 @Override 278 public Statement createStatement(final int resultSetType, final int resultSetConcurrency, 279 final int resultSetHoldability) throws SQLException { 280 checkOpen(); 281 try { 282 return init(new DelegatingStatement(this, 283 connection.createStatement(resultSetType, resultSetConcurrency, resultSetHoldability))); 284 } catch (final SQLException e) { 285 handleException(e); 286 return null; 287 } 288 } 289 290 @Override 291 public Struct createStruct(final String typeName, final Object[] attributes) throws SQLException { 292 checkOpen(); 293 try { 294 return connection.createStruct(typeName, attributes); 295 } catch (final SQLException e) { 296 handleException(e); 297 return null; 298 } 299 } 300 301 @Override 302 public boolean getAutoCommit() throws SQLException { 303 checkOpen(); 304 if (cacheState && cachedAutoCommit != null) { 305 return cachedAutoCommit; 306 } 307 try { 308 cachedAutoCommit = connection.getAutoCommit(); 309 return cachedAutoCommit; 310 } catch (final SQLException e) { 311 handleException(e); 312 return false; 313 } 314 } 315 316 /** 317 * Returns the state caching flag. 318 * 319 * @return the state caching flag 320 */ 321 public boolean getCacheState() { 322 return cacheState; 323 } 324 325 @Override 326 public String getCatalog() throws SQLException { 327 checkOpen(); 328 if (cacheState && cachedCatalog != null) { 329 return cachedCatalog; 330 } 331 try { 332 cachedCatalog = connection.getCatalog(); 333 return cachedCatalog; 334 } catch (final SQLException e) { 335 handleException(e); 336 return null; 337 } 338 } 339 340 @Override 341 public Properties getClientInfo() throws SQLException { 342 checkOpen(); 343 try { 344 return connection.getClientInfo(); 345 } catch (final SQLException e) { 346 handleException(e); 347 return null; 348 } 349 } 350 351 @Override 352 public String getClientInfo(final String name) throws SQLException { 353 checkOpen(); 354 try { 355 return connection.getClientInfo(name); 356 } catch (final SQLException e) { 357 handleException(e); 358 return null; 359 } 360 } 361 362 /** 363 * Gets the default query timeout that will be used for {@link Statement}s created from this connection. 364 * <code>null</code> means that the driver default will be used. 365 * 366 * @return query timeout limit in seconds; zero means there is no limit. 367 */ 368 public Integer getDefaultQueryTimeout() { 369 return defaultQueryTimeoutSeconds; 370 } 371 372 /** 373 * Returns my underlying {@link Connection}. 374 * 375 * @return my underlying {@link Connection}. 376 */ 377 public C getDelegate() { 378 return getDelegateInternal(); 379 } 380 381 /** 382 * Gets the delegate connection. 383 * 384 * @return the delegate connection. 385 */ 386 protected final C getDelegateInternal() { 387 return connection; 388 } 389 390 @Override 391 public int getHoldability() throws SQLException { 392 checkOpen(); 393 try { 394 return connection.getHoldability(); 395 } catch (final SQLException e) { 396 handleException(e); 397 return 0; 398 } 399 } 400 401 /** 402 * If my underlying {@link Connection} is not a {@code DelegatingConnection}, returns it, otherwise recursively 403 * invokes this method on my delegate. 404 * <p> 405 * Hence this method will return the first delegate that is not a {@code DelegatingConnection}, or {@code null} when 406 * no non-{@code DelegatingConnection} delegate can be found by traversing this chain. 407 * </p> 408 * <p> 409 * This method is useful when you may have nested {@code DelegatingConnection}s, and you want to make sure to obtain 410 * a "genuine" {@link Connection}. 411 * </p> 412 * 413 * @return innermost delegate. 414 */ 415 public Connection getInnermostDelegate() { 416 return getInnermostDelegateInternal(); 417 } 418 419 /** 420 * Although this method is public, it is part of the internal API and should not be used by clients. The signature 421 * of this method may change at any time including in ways that break backwards compatibility. 422 * 423 * @return innermost delegate. 424 */ 425 @SuppressWarnings("resource") 426 public final Connection getInnermostDelegateInternal() { 427 Connection conn = connection; 428 while (conn instanceof DelegatingConnection) { 429 conn = ((DelegatingConnection<?>) conn).getDelegateInternal(); 430 if (this == conn) { 431 return null; 432 } 433 } 434 return conn; 435 } 436 437 @Override 438 public DatabaseMetaData getMetaData() throws SQLException { 439 checkOpen(); 440 try { 441 return new DelegatingDatabaseMetaData(this, connection.getMetaData()); 442 } catch (final SQLException e) { 443 handleException(e); 444 return null; 445 } 446 } 447 448 @Override 449 public int getNetworkTimeout() throws SQLException { 450 checkOpen(); 451 try { 452 return Jdbc41Bridge.getNetworkTimeout(connection); 453 } catch (final SQLException e) { 454 handleException(e); 455 return 0; 456 } 457 } 458 459 @Override 460 public String getSchema() throws SQLException { 461 checkOpen(); 462 if (cacheState && cachedSchema != null) { 463 return cachedSchema; 464 } 465 try { 466 cachedSchema = Jdbc41Bridge.getSchema(connection); 467 return cachedSchema; 468 } catch (final SQLException e) { 469 handleException(e); 470 return null; 471 } 472 } 473 474 @Override 475 public int getTransactionIsolation() throws SQLException { 476 checkOpen(); 477 try { 478 return connection.getTransactionIsolation(); 479 } catch (final SQLException e) { 480 handleException(e); 481 return -1; 482 } 483 } 484 485 @Override 486 public Map<String, Class<?>> getTypeMap() throws SQLException { 487 checkOpen(); 488 try { 489 return connection.getTypeMap(); 490 } catch (final SQLException e) { 491 handleException(e); 492 return null; 493 } 494 } 495 496 @Override 497 public SQLWarning getWarnings() throws SQLException { 498 checkOpen(); 499 try { 500 return connection.getWarnings(); 501 } catch (final SQLException e) { 502 handleException(e); 503 return null; 504 } 505 } 506 507 /** 508 * Handles the given exception by throwing it. 509 * 510 * @param e the exception to throw. 511 * @throws SQLException the exception to throw. 512 */ 513 protected void handleException(final SQLException e) throws SQLException { 514 throw e; 515 } 516 517 /** 518 * Handles the given {@code SQLException}. 519 * 520 * @param <T> The throwable type. 521 * @param e The SQLException 522 * @return the given {@code SQLException} 523 * @since 2.7.0 524 */ 525 protected <T extends Throwable> T handleExceptionNoThrow(final T e) { 526 return e; 527 } 528 529 /** 530 * Initializes the given statement with this connection's settings. 531 * 532 * @param <T> The DelegatingStatement type. 533 * @param delegatingStatement The DelegatingStatement to initialize. 534 * @return The given DelegatingStatement. 535 * @throws SQLException if a database access error occurs, this method is called on a closed Statement. 536 */ 537 private <T extends DelegatingStatement> T init(final T delegatingStatement) throws SQLException { 538 if (defaultQueryTimeoutSeconds != null && defaultQueryTimeoutSeconds != delegatingStatement.getQueryTimeout()) { 539 delegatingStatement.setQueryTimeout(defaultQueryTimeoutSeconds); 540 } 541 return delegatingStatement; 542 } 543 544 /** 545 * Compares innermost delegate to the given connection. 546 * 547 * @param c 548 * connection to compare innermost delegate with 549 * @return true if innermost delegate equals <code>c</code> 550 */ 551 @SuppressWarnings("resource") 552 public boolean innermostDelegateEquals(final Connection c) { 553 final Connection innerCon = getInnermostDelegateInternal(); 554 if (innerCon == null) { 555 return c == null; 556 } 557 return innerCon.equals(c); 558 } 559 560 @Override 561 public boolean isClosed() throws SQLException { 562 return closed || connection == null || connection.isClosed(); 563 } 564 565 protected boolean isClosedInternal() { 566 return closed; 567 } 568 569 @Override 570 public boolean isReadOnly() throws SQLException { 571 checkOpen(); 572 if (cacheState && cachedReadOnly != null) { 573 return cachedReadOnly; 574 } 575 try { 576 cachedReadOnly = connection.isReadOnly(); 577 return cachedReadOnly; 578 } catch (final SQLException e) { 579 handleException(e); 580 return false; 581 } 582 } 583 584 @Override 585 public boolean isValid(final int timeoutSeconds) throws SQLException { 586 if (isClosed()) { 587 return false; 588 } 589 try { 590 return connection.isValid(timeoutSeconds); 591 } catch (final SQLException e) { 592 handleException(e); 593 return false; 594 } 595 } 596 597 @Override 598 public boolean isWrapperFor(final Class<?> iface) throws SQLException { 599 if (iface.isAssignableFrom(getClass())) { 600 return true; 601 } 602 if (iface.isAssignableFrom(connection.getClass())) { 603 return true; 604 } 605 return connection.isWrapperFor(iface); 606 } 607 608 @Override 609 public String nativeSQL(final String sql) throws SQLException { 610 checkOpen(); 611 try { 612 return connection.nativeSQL(sql); 613 } catch (final SQLException e) { 614 handleException(e); 615 return null; 616 } 617 } 618 619 protected void passivate() throws SQLException { 620 // The JDBC specification requires that a Connection close any open 621 // Statement's when it is closed. 622 // DBCP-288. Not all the traced objects will be statements 623 final List<AbandonedTrace> traces = getTrace(); 624 if (traces != null && !traces.isEmpty()) { 625 final List<Exception> thrownList = new ArrayList<>(); 626 for (final Object trace : traces) { 627 if (trace instanceof Statement) { 628 try { 629 ((Statement) trace).close(); 630 } catch (final Exception e) { 631 thrownList.add(e); 632 } 633 } else if (trace instanceof ResultSet) { 634 // DBCP-265: Need to close the result sets that are 635 // generated via DatabaseMetaData 636 try { 637 ((ResultSet) trace).close(); 638 } catch (final Exception e) { 639 thrownList.add(e); 640 } 641 } 642 } 643 clearTrace(); 644 if (!thrownList.isEmpty()) { 645 throw new SQLExceptionList(thrownList); 646 } 647 } 648 setLastUsed(0); 649 } 650 651 @SuppressWarnings("resource") // Caller is responsible for closing the resource. 652 @Override 653 public CallableStatement prepareCall(final String sql) throws SQLException { 654 checkOpen(); 655 try { 656 return init(new DelegatingCallableStatement(this, connection.prepareCall(sql))); 657 } catch (final SQLException e) { 658 handleException(e); 659 return null; 660 } 661 } 662 663 @SuppressWarnings("resource") // Caller is responsible for closing the resource. 664 @Override 665 public CallableStatement prepareCall(final String sql, final int resultSetType, final int resultSetConcurrency) 666 throws SQLException { 667 checkOpen(); 668 try { 669 return init(new DelegatingCallableStatement(this, 670 connection.prepareCall(sql, resultSetType, resultSetConcurrency))); 671 } catch (final SQLException e) { 672 handleException(e); 673 return null; 674 } 675 } 676 677 @SuppressWarnings("resource") // Caller is responsible for closing the resource. 678 @Override 679 public CallableStatement prepareCall(final String sql, final int resultSetType, final int resultSetConcurrency, 680 final int resultSetHoldability) throws SQLException { 681 checkOpen(); 682 try { 683 return init(new DelegatingCallableStatement(this, 684 connection.prepareCall(sql, resultSetType, resultSetConcurrency, resultSetHoldability))); 685 } catch (final SQLException e) { 686 handleException(e); 687 return null; 688 } 689 } 690 691 @SuppressWarnings("resource") // Caller is responsible for closing the resource. 692 @Override 693 public PreparedStatement prepareStatement(final String sql) throws SQLException { 694 checkOpen(); 695 try { 696 return init(new DelegatingPreparedStatement(this, connection.prepareStatement(sql))); 697 } catch (final SQLException e) { 698 handleException(e); 699 return null; 700 } 701 } 702 703 @SuppressWarnings("resource") // Caller is responsible for closing the resource. 704 @Override 705 public PreparedStatement prepareStatement(final String sql, final int autoGeneratedKeys) throws SQLException { 706 checkOpen(); 707 try { 708 return init(new DelegatingPreparedStatement(this, connection.prepareStatement(sql, autoGeneratedKeys))); 709 } catch (final SQLException e) { 710 handleException(e); 711 return null; 712 } 713 } 714 715 @SuppressWarnings("resource") // Caller is responsible for closing the resource. 716 @Override 717 public PreparedStatement prepareStatement(final String sql, final int resultSetType, final int resultSetConcurrency) 718 throws SQLException { 719 checkOpen(); 720 try { 721 return init(new DelegatingPreparedStatement(this, 722 connection.prepareStatement(sql, resultSetType, resultSetConcurrency))); 723 } catch (final SQLException e) { 724 handleException(e); 725 return null; 726 } 727 } 728 729 @SuppressWarnings("resource") // Caller is responsible for closing the resource. 730 @Override 731 public PreparedStatement prepareStatement(final String sql, final int resultSetType, final int resultSetConcurrency, 732 final int resultSetHoldability) throws SQLException { 733 checkOpen(); 734 try { 735 return init(new DelegatingPreparedStatement(this, 736 connection.prepareStatement(sql, resultSetType, resultSetConcurrency, resultSetHoldability))); 737 } catch (final SQLException e) { 738 handleException(e); 739 return null; 740 } 741 } 742 743 @SuppressWarnings("resource") // Caller is responsible for closing the resource. 744 @Override 745 public PreparedStatement prepareStatement(final String sql, final int[] columnIndexes) throws SQLException { 746 checkOpen(); 747 try { 748 return init(new DelegatingPreparedStatement(this, connection.prepareStatement(sql, columnIndexes))); 749 } catch (final SQLException e) { 750 handleException(e); 751 return null; 752 } 753 } 754 755 @SuppressWarnings("resource") // Caller is responsible for closing the resource. 756 @Override 757 public PreparedStatement prepareStatement(final String sql, final String[] columnNames) throws SQLException { 758 checkOpen(); 759 try { 760 return init(new DelegatingPreparedStatement(this, connection.prepareStatement(sql, columnNames))); 761 } catch (final SQLException e) { 762 handleException(e); 763 return null; 764 } 765 } 766 767 @Override 768 public void releaseSavepoint(final Savepoint savepoint) throws SQLException { 769 checkOpen(); 770 try { 771 connection.releaseSavepoint(savepoint); 772 } catch (final SQLException e) { 773 handleException(e); 774 } 775 } 776 777 @Override 778 public void rollback() throws SQLException { 779 checkOpen(); 780 try { 781 connection.rollback(); 782 } catch (final SQLException e) { 783 handleException(e); 784 } 785 } 786 787 @Override 788 public void rollback(final Savepoint savepoint) throws SQLException { 789 checkOpen(); 790 try { 791 connection.rollback(savepoint); 792 } catch (final SQLException e) { 793 handleException(e); 794 } 795 } 796 797 @Override 798 public void setAutoCommit(final boolean autoCommit) throws SQLException { 799 checkOpen(); 800 try { 801 connection.setAutoCommit(autoCommit); 802 if (cacheState) { 803 cachedAutoCommit = connection.getAutoCommit(); 804 } 805 } catch (final SQLException e) { 806 cachedAutoCommit = null; 807 handleException(e); 808 } 809 } 810 811 /** 812 * Sets the state caching flag. 813 * 814 * @param cacheState 815 * The new value for the state caching flag 816 */ 817 public void setCacheState(final boolean cacheState) { 818 this.cacheState = cacheState; 819 } 820 821 @Override 822 public void setCatalog(final String catalog) throws SQLException { 823 checkOpen(); 824 try { 825 connection.setCatalog(catalog); 826 if (cacheState) { 827 cachedCatalog = connection.getCatalog(); 828 } 829 } catch (final SQLException e) { 830 cachedCatalog = null; 831 handleException(e); 832 } 833 } 834 835 @Override 836 public void setClientInfo(final Properties properties) throws SQLClientInfoException { 837 try { 838 checkOpen(); 839 connection.setClientInfo(properties); 840 } catch (final SQLClientInfoException e) { 841 throw e; 842 } catch (final SQLException e) { 843 throw new SQLClientInfoException("Connection is closed.", EMPTY_FAILED_PROPERTIES, e); 844 } 845 } 846 847 @Override 848 public void setClientInfo(final String name, final String value) throws SQLClientInfoException { 849 try { 850 checkOpen(); 851 connection.setClientInfo(name, value); 852 } catch (final SQLClientInfoException e) { 853 throw e; 854 } catch (final SQLException e) { 855 throw new SQLClientInfoException("Connection is closed.", EMPTY_FAILED_PROPERTIES, e); 856 } 857 } 858 859 protected void setClosedInternal(final boolean closed) { 860 this.closed = closed; 861 } 862 863 /** 864 * Sets the default query timeout that will be used for {@link Statement}s created from this connection. 865 * <code>null</code> means that the driver default will be used. 866 * 867 * @param defaultQueryTimeoutSeconds 868 * the new query timeout limit in seconds; zero means there is no limit 869 */ 870 public void setDefaultQueryTimeout(final Integer defaultQueryTimeoutSeconds) { 871 this.defaultQueryTimeoutSeconds = defaultQueryTimeoutSeconds; 872 } 873 874 /** 875 * Sets my delegate. 876 * 877 * @param connection 878 * my delegate. 879 */ 880 public void setDelegate(final C connection) { 881 this.connection = connection; 882 } 883 884 @Override 885 public void setHoldability(final int holdability) throws SQLException { 886 checkOpen(); 887 try { 888 connection.setHoldability(holdability); 889 } catch (final SQLException e) { 890 handleException(e); 891 } 892 } 893 894 @Override 895 public void setNetworkTimeout(final Executor executor, final int milliseconds) throws SQLException { 896 checkOpen(); 897 try { 898 Jdbc41Bridge.setNetworkTimeout(connection, executor, milliseconds); 899 } catch (final SQLException e) { 900 handleException(e); 901 } 902 } 903 904 @Override 905 public void setReadOnly(final boolean readOnly) throws SQLException { 906 checkOpen(); 907 try { 908 connection.setReadOnly(readOnly); 909 if (cacheState) { 910 cachedReadOnly = connection.isReadOnly(); 911 } 912 } catch (final SQLException e) { 913 cachedReadOnly = null; 914 handleException(e); 915 } 916 } 917 918 @Override 919 public Savepoint setSavepoint() throws SQLException { 920 checkOpen(); 921 try { 922 return connection.setSavepoint(); 923 } catch (final SQLException e) { 924 handleException(e); 925 return null; 926 } 927 } 928 929 @Override 930 public Savepoint setSavepoint(final String name) throws SQLException { 931 checkOpen(); 932 try { 933 return connection.setSavepoint(name); 934 } catch (final SQLException e) { 935 handleException(e); 936 return null; 937 } 938 } 939 940 @Override 941 public void setSchema(final String schema) throws SQLException { 942 checkOpen(); 943 try { 944 Jdbc41Bridge.setSchema(connection, schema); 945 if (cacheState) { 946 cachedSchema = connection.getSchema(); 947 } 948 } catch (final SQLException e) { 949 cachedSchema = null; 950 handleException(e); 951 } 952 } 953 954 @Override 955 public void setTransactionIsolation(final int level) throws SQLException { 956 checkOpen(); 957 try { 958 connection.setTransactionIsolation(level); 959 } catch (final SQLException e) { 960 handleException(e); 961 } 962 } 963 964 @Override 965 public void setTypeMap(final Map<String, Class<?>> map) throws SQLException { 966 checkOpen(); 967 try { 968 connection.setTypeMap(map); 969 } catch (final SQLException e) { 970 handleException(e); 971 } 972 } 973 974 /** 975 * Returns a string representation of the metadata associated with the innermost delegate connection. 976 */ 977 @SuppressWarnings("resource") 978 @Override 979 public synchronized String toString() { 980 String str = null; 981 982 final Connection conn = this.getInnermostDelegateInternal(); 983 if (conn != null) { 984 try { 985 if (conn.isClosed()) { 986 str = "connection is closed"; 987 } else { 988 final StringBuilder sb = new StringBuilder(); 989 sb.append(hashCode()); 990 final DatabaseMetaData meta = conn.getMetaData(); 991 if (meta != null) { 992 sb.append(", URL="); 993 sb.append(meta.getURL()); 994 sb.append(", "); 995 sb.append(meta.getDriverName()); 996 str = sb.toString(); 997 } 998 } 999 } catch (final SQLException ex) { 1000 // Ignore 1001 } 1002 } 1003 return str != null ? str : super.toString(); 1004 } 1005 1006 @Override 1007 public <T> T unwrap(final Class<T> iface) throws SQLException { 1008 if (iface.isAssignableFrom(getClass())) { 1009 return iface.cast(this); 1010 } 1011 if (iface.isAssignableFrom(connection.getClass())) { 1012 return iface.cast(connection); 1013 } 1014 return connection.unwrap(iface); 1015 } 1016}