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