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 try { 228 connection.close(); 229 } finally { 230 closed = true; 231 } 232 } else { 233 closed = true; 234 } 235 } 236 } 237 238 protected void handleException(final SQLException e) throws SQLException { 239 throw e; 240 } 241 242 private void initializeStatement(final DelegatingStatement ds) throws SQLException { 243 if (defaultQueryTimeoutSeconds != null && defaultQueryTimeoutSeconds.intValue() != ds.getQueryTimeout()) { 244 ds.setQueryTimeout(defaultQueryTimeoutSeconds.intValue()); 245 } 246 } 247 248 @Override 249 public Statement createStatement() throws SQLException { 250 checkOpen(); 251 try { 252 final DelegatingStatement ds = new DelegatingStatement(this, connection.createStatement()); 253 initializeStatement(ds); 254 return ds; 255 } catch (final SQLException e) { 256 handleException(e); 257 return null; 258 } 259 } 260 261 @Override 262 public Statement createStatement(final int resultSetType, final int resultSetConcurrency) throws SQLException { 263 checkOpen(); 264 try { 265 final DelegatingStatement ds = new DelegatingStatement(this, 266 connection.createStatement(resultSetType, resultSetConcurrency)); 267 initializeStatement(ds); 268 return ds; 269 } catch (final SQLException e) { 270 handleException(e); 271 return null; 272 } 273 } 274 275 @Override 276 public PreparedStatement prepareStatement(final String sql) throws SQLException { 277 checkOpen(); 278 try { 279 final DelegatingPreparedStatement dps = new DelegatingPreparedStatement(this, 280 connection.prepareStatement(sql)); 281 initializeStatement(dps); 282 return dps; 283 } catch (final SQLException e) { 284 handleException(e); 285 return null; 286 } 287 } 288 289 @Override 290 public PreparedStatement prepareStatement(final String sql, final int resultSetType, final int resultSetConcurrency) 291 throws SQLException { 292 checkOpen(); 293 try { 294 final DelegatingPreparedStatement dps = new DelegatingPreparedStatement(this, 295 connection.prepareStatement(sql, resultSetType, resultSetConcurrency)); 296 initializeStatement(dps); 297 return dps; 298 } catch (final SQLException e) { 299 handleException(e); 300 return null; 301 } 302 } 303 304 @Override 305 public CallableStatement prepareCall(final String sql) throws SQLException { 306 checkOpen(); 307 try { 308 final DelegatingCallableStatement dcs = new DelegatingCallableStatement(this, connection.prepareCall(sql)); 309 initializeStatement(dcs); 310 return dcs; 311 } catch (final SQLException e) { 312 handleException(e); 313 return null; 314 } 315 } 316 317 @Override 318 public CallableStatement prepareCall(final String sql, final int resultSetType, final int resultSetConcurrency) 319 throws SQLException { 320 checkOpen(); 321 try { 322 final DelegatingCallableStatement dcs = new DelegatingCallableStatement(this, 323 connection.prepareCall(sql, resultSetType, resultSetConcurrency)); 324 initializeStatement(dcs); 325 return dcs; 326 } catch (final SQLException e) { 327 handleException(e); 328 return null; 329 } 330 } 331 332 @Override 333 public void clearWarnings() throws SQLException { 334 checkOpen(); 335 try { 336 connection.clearWarnings(); 337 } catch (final SQLException e) { 338 handleException(e); 339 } 340 } 341 342 @Override 343 public void commit() throws SQLException { 344 checkOpen(); 345 try { 346 connection.commit(); 347 } catch (final SQLException e) { 348 handleException(e); 349 } 350 } 351 352 /** 353 * Returns the state caching flag. 354 * 355 * @return the state caching flag 356 */ 357 public boolean getCacheState() { 358 return cacheState; 359 } 360 361 @Override 362 public boolean getAutoCommit() throws SQLException { 363 checkOpen(); 364 if (cacheState && autoCommitCached != null) { 365 return autoCommitCached.booleanValue(); 366 } 367 try { 368 autoCommitCached = Boolean.valueOf(connection.getAutoCommit()); 369 return autoCommitCached.booleanValue(); 370 } catch (final SQLException e) { 371 handleException(e); 372 return false; 373 } 374 } 375 376 @Override 377 public String getCatalog() throws SQLException { 378 checkOpen(); 379 try { 380 return connection.getCatalog(); 381 } catch (final SQLException e) { 382 handleException(e); 383 return null; 384 } 385 } 386 387 @Override 388 public DatabaseMetaData getMetaData() throws SQLException { 389 checkOpen(); 390 try { 391 return new DelegatingDatabaseMetaData(this, connection.getMetaData()); 392 } catch (final SQLException e) { 393 handleException(e); 394 return null; 395 } 396 } 397 398 @Override 399 public int getTransactionIsolation() throws SQLException { 400 checkOpen(); 401 try { 402 return connection.getTransactionIsolation(); 403 } catch (final SQLException e) { 404 handleException(e); 405 return -1; 406 } 407 } 408 409 @Override 410 public Map<String, Class<?>> getTypeMap() throws SQLException { 411 checkOpen(); 412 try { 413 return connection.getTypeMap(); 414 } catch (final SQLException e) { 415 handleException(e); 416 return null; 417 } 418 } 419 420 @Override 421 public SQLWarning getWarnings() throws SQLException { 422 checkOpen(); 423 try { 424 return connection.getWarnings(); 425 } catch (final SQLException e) { 426 handleException(e); 427 return null; 428 } 429 } 430 431 @Override 432 public boolean isReadOnly() throws SQLException { 433 checkOpen(); 434 if (cacheState && readOnlyCached != null) { 435 return readOnlyCached.booleanValue(); 436 } 437 try { 438 readOnlyCached = Boolean.valueOf(connection.isReadOnly()); 439 return readOnlyCached.booleanValue(); 440 } catch (final SQLException e) { 441 handleException(e); 442 return false; 443 } 444 } 445 446 @Override 447 public String nativeSQL(final String sql) throws SQLException { 448 checkOpen(); 449 try { 450 return connection.nativeSQL(sql); 451 } catch (final SQLException e) { 452 handleException(e); 453 return null; 454 } 455 } 456 457 @Override 458 public void rollback() throws SQLException { 459 checkOpen(); 460 try { 461 connection.rollback(); 462 } catch (final SQLException e) { 463 handleException(e); 464 } 465 } 466 467 /** 468 * Gets the default query timeout that will be used for {@link Statement}s created from this connection. 469 * <code>null</code> means that the driver default will be used. 470 * 471 * @return query timeout limit in seconds; zero means there is no limit. 472 */ 473 public Integer getDefaultQueryTimeout() { 474 return defaultQueryTimeoutSeconds; 475 } 476 477 /** 478 * Sets the default query timeout that will be used for {@link Statement}s created from this connection. 479 * <code>null</code> means that the driver default will be used. 480 * 481 * @param defaultQueryTimeoutSeconds 482 * the new query timeout limit in seconds; zero means there is no limit 483 */ 484 public void setDefaultQueryTimeout(final Integer defaultQueryTimeoutSeconds) { 485 this.defaultQueryTimeoutSeconds = defaultQueryTimeoutSeconds; 486 } 487 488 /** 489 * Sets the state caching flag. 490 * 491 * @param cacheState 492 * The new value for the state caching flag 493 */ 494 public void setCacheState(final boolean cacheState) { 495 this.cacheState = cacheState; 496 } 497 498 /** 499 * Can be used to clear cached state when it is known that the underlying connection may have been accessed 500 * directly. 501 */ 502 public void clearCachedState() { 503 autoCommitCached = null; 504 readOnlyCached = null; 505 if (connection instanceof DelegatingConnection) { 506 ((DelegatingConnection<?>) connection).clearCachedState(); 507 } 508 } 509 510 @Override 511 public void setAutoCommit(final boolean autoCommit) throws SQLException { 512 checkOpen(); 513 try { 514 connection.setAutoCommit(autoCommit); 515 if (cacheState) { 516 autoCommitCached = Boolean.valueOf(autoCommit); 517 } 518 } catch (final SQLException e) { 519 autoCommitCached = null; 520 handleException(e); 521 } 522 } 523 524 @Override 525 public void setCatalog(final String catalog) throws SQLException { 526 checkOpen(); 527 try { 528 connection.setCatalog(catalog); 529 } catch (final SQLException e) { 530 handleException(e); 531 } 532 } 533 534 @Override 535 public void setReadOnly(final boolean readOnly) throws SQLException { 536 checkOpen(); 537 try { 538 connection.setReadOnly(readOnly); 539 if (cacheState) { 540 readOnlyCached = Boolean.valueOf(readOnly); 541 } 542 } catch (final SQLException e) { 543 readOnlyCached = null; 544 handleException(e); 545 } 546 } 547 548 @Override 549 public void setTransactionIsolation(final int level) throws SQLException { 550 checkOpen(); 551 try { 552 connection.setTransactionIsolation(level); 553 } catch (final SQLException e) { 554 handleException(e); 555 } 556 } 557 558 @Override 559 public void setTypeMap(final Map<String, Class<?>> map) throws SQLException { 560 checkOpen(); 561 try { 562 connection.setTypeMap(map); 563 } catch (final SQLException e) { 564 handleException(e); 565 } 566 } 567 568 @Override 569 public boolean isClosed() throws SQLException { 570 return closed || connection == null || connection.isClosed(); 571 } 572 573 protected void checkOpen() throws SQLException { 574 if (closed) { 575 if (null != connection) { 576 String label = ""; 577 try { 578 label = connection.toString(); 579 } catch (final Exception ex) { 580 // ignore, leave label empty 581 } 582 throw new SQLException("Connection " + label + " is closed."); 583 } 584 throw new SQLException("Connection is null."); 585 } 586 } 587 588 protected void activate() { 589 closed = false; 590 setLastUsed(); 591 if (connection instanceof DelegatingConnection) { 592 ((DelegatingConnection<?>) connection).activate(); 593 } 594 } 595 596 protected void passivate() throws SQLException { 597 // The JDBC spec requires that a Connection close any open 598 // Statement's when it is closed. 599 // DBCP-288. Not all the traced objects will be statements 600 final List<AbandonedTrace> traces = getTrace(); 601 if (traces != null && traces.size() > 0) { 602 final Iterator<AbandonedTrace> traceIter = traces.iterator(); 603 while (traceIter.hasNext()) { 604 final Object trace = traceIter.next(); 605 if (trace instanceof Statement) { 606 ((Statement) trace).close(); 607 } else if (trace instanceof ResultSet) { 608 // DBCP-265: Need to close the result sets that are 609 // generated via DatabaseMetaData 610 ((ResultSet) trace).close(); 611 } 612 } 613 clearTrace(); 614 } 615 setLastUsed(0); 616 } 617 618 @Override 619 public int getHoldability() throws SQLException { 620 checkOpen(); 621 try { 622 return connection.getHoldability(); 623 } catch (final SQLException e) { 624 handleException(e); 625 return 0; 626 } 627 } 628 629 @Override 630 public void setHoldability(final int holdability) throws SQLException { 631 checkOpen(); 632 try { 633 connection.setHoldability(holdability); 634 } catch (final SQLException e) { 635 handleException(e); 636 } 637 } 638 639 @Override 640 public Savepoint setSavepoint() throws SQLException { 641 checkOpen(); 642 try { 643 return connection.setSavepoint(); 644 } catch (final SQLException e) { 645 handleException(e); 646 return null; 647 } 648 } 649 650 @Override 651 public Savepoint setSavepoint(final String name) throws SQLException { 652 checkOpen(); 653 try { 654 return connection.setSavepoint(name); 655 } catch (final SQLException e) { 656 handleException(e); 657 return null; 658 } 659 } 660 661 @Override 662 public void rollback(final Savepoint savepoint) throws SQLException { 663 checkOpen(); 664 try { 665 connection.rollback(savepoint); 666 } catch (final SQLException e) { 667 handleException(e); 668 } 669 } 670 671 @Override 672 public void releaseSavepoint(final Savepoint savepoint) throws SQLException { 673 checkOpen(); 674 try { 675 connection.releaseSavepoint(savepoint); 676 } catch (final SQLException e) { 677 handleException(e); 678 } 679 } 680 681 @Override 682 public Statement createStatement(final int resultSetType, final int resultSetConcurrency, 683 final int resultSetHoldability) throws SQLException { 684 checkOpen(); 685 try { 686 final DelegatingStatement ds = new DelegatingStatement(this, 687 connection.createStatement(resultSetType, resultSetConcurrency, resultSetHoldability)); 688 initializeStatement(ds); 689 return ds; 690 } catch (final SQLException e) { 691 handleException(e); 692 return null; 693 } 694 } 695 696 @Override 697 public PreparedStatement prepareStatement(final String sql, final int resultSetType, final int resultSetConcurrency, 698 final int resultSetHoldability) throws SQLException { 699 checkOpen(); 700 try { 701 final DelegatingPreparedStatement dps = new DelegatingPreparedStatement(this, 702 connection.prepareStatement(sql, resultSetType, resultSetConcurrency, resultSetHoldability)); 703 initializeStatement(dps); 704 return dps; 705 } catch (final SQLException e) { 706 handleException(e); 707 return null; 708 } 709 } 710 711 @Override 712 public CallableStatement prepareCall(final String sql, final int resultSetType, final int resultSetConcurrency, 713 final int resultSetHoldability) throws SQLException { 714 checkOpen(); 715 try { 716 final DelegatingCallableStatement dcs = new DelegatingCallableStatement(this, 717 connection.prepareCall(sql, resultSetType, resultSetConcurrency, resultSetHoldability)); 718 initializeStatement(dcs); 719 return dcs; 720 } catch (final SQLException e) { 721 handleException(e); 722 return null; 723 } 724 } 725 726 @Override 727 public PreparedStatement prepareStatement(final String sql, final int autoGeneratedKeys) throws SQLException { 728 checkOpen(); 729 try { 730 final DelegatingPreparedStatement dps = new DelegatingPreparedStatement(this, 731 connection.prepareStatement(sql, autoGeneratedKeys)); 732 initializeStatement(dps); 733 return dps; 734 } catch (final SQLException e) { 735 handleException(e); 736 return null; 737 } 738 } 739 740 @Override 741 public PreparedStatement prepareStatement(final String sql, final int columnIndexes[]) throws SQLException { 742 checkOpen(); 743 try { 744 final DelegatingPreparedStatement dps = new DelegatingPreparedStatement(this, 745 connection.prepareStatement(sql, columnIndexes)); 746 initializeStatement(dps); 747 return dps; 748 } catch (final SQLException e) { 749 handleException(e); 750 return null; 751 } 752 } 753 754 @Override 755 public PreparedStatement prepareStatement(final String sql, final String columnNames[]) throws SQLException { 756 checkOpen(); 757 try { 758 final DelegatingPreparedStatement dps = new DelegatingPreparedStatement(this, 759 connection.prepareStatement(sql, columnNames)); 760 initializeStatement(dps); 761 return dps; 762 } catch (final SQLException e) { 763 handleException(e); 764 return null; 765 } 766 } 767 768 @Override 769 public boolean isWrapperFor(final Class<?> iface) throws SQLException { 770 if (iface.isAssignableFrom(getClass())) { 771 return true; 772 } else if (iface.isAssignableFrom(connection.getClass())) { 773 return true; 774 } else { 775 return connection.isWrapperFor(iface); 776 } 777 } 778 779 @Override 780 public <T> T unwrap(final Class<T> iface) throws SQLException { 781 if (iface.isAssignableFrom(getClass())) { 782 return iface.cast(this); 783 } else if (iface.isAssignableFrom(connection.getClass())) { 784 return iface.cast(connection); 785 } else { 786 return connection.unwrap(iface); 787 } 788 } 789 790 @Override 791 public Array createArrayOf(final String typeName, final Object[] elements) throws SQLException { 792 checkOpen(); 793 try { 794 return connection.createArrayOf(typeName, elements); 795 } catch (final SQLException e) { 796 handleException(e); 797 return null; 798 } 799 } 800 801 @Override 802 public Blob createBlob() throws SQLException { 803 checkOpen(); 804 try { 805 return connection.createBlob(); 806 } catch (final SQLException e) { 807 handleException(e); 808 return null; 809 } 810 } 811 812 @Override 813 public Clob createClob() throws SQLException { 814 checkOpen(); 815 try { 816 return connection.createClob(); 817 } catch (final SQLException e) { 818 handleException(e); 819 return null; 820 } 821 } 822 823 @Override 824 public NClob createNClob() throws SQLException { 825 checkOpen(); 826 try { 827 return connection.createNClob(); 828 } catch (final SQLException e) { 829 handleException(e); 830 return null; 831 } 832 } 833 834 @Override 835 public SQLXML createSQLXML() throws SQLException { 836 checkOpen(); 837 try { 838 return connection.createSQLXML(); 839 } catch (final SQLException e) { 840 handleException(e); 841 return null; 842 } 843 } 844 845 @Override 846 public Struct createStruct(final String typeName, final Object[] attributes) throws SQLException { 847 checkOpen(); 848 try { 849 return connection.createStruct(typeName, attributes); 850 } catch (final SQLException e) { 851 handleException(e); 852 return null; 853 } 854 } 855 856 @Override 857 public boolean isValid(final int timeoutSeconds) throws SQLException { 858 if (isClosed()) { 859 return false; 860 } 861 try { 862 return connection.isValid(timeoutSeconds); 863 } catch (final SQLException e) { 864 handleException(e); 865 return false; 866 } 867 } 868 869 @Override 870 public void setClientInfo(final String name, final String value) throws SQLClientInfoException { 871 try { 872 checkOpen(); 873 connection.setClientInfo(name, value); 874 } catch (final SQLClientInfoException e) { 875 throw e; 876 } catch (final SQLException e) { 877 throw new SQLClientInfoException("Connection is closed.", EMPTY_FAILED_PROPERTIES, e); 878 } 879 } 880 881 @Override 882 public void setClientInfo(final Properties properties) throws SQLClientInfoException { 883 try { 884 checkOpen(); 885 connection.setClientInfo(properties); 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 Properties getClientInfo() throws SQLException { 895 checkOpen(); 896 try { 897 return connection.getClientInfo(); 898 } catch (final SQLException e) { 899 handleException(e); 900 return null; 901 } 902 } 903 904 @Override 905 public String getClientInfo(final String name) throws SQLException { 906 checkOpen(); 907 try { 908 return connection.getClientInfo(name); 909 } catch (final SQLException e) { 910 handleException(e); 911 return null; 912 } 913 } 914 915 @Override 916 public void setSchema(final String schema) throws SQLException { 917 checkOpen(); 918 try { 919 connection.setSchema(schema); 920 } catch (final SQLException e) { 921 handleException(e); 922 } 923 } 924 925 @Override 926 public String getSchema() throws SQLException { 927 checkOpen(); 928 try { 929 return connection.getSchema(); 930 } catch (final SQLException e) { 931 handleException(e); 932 return null; 933 } 934 } 935 936 @Override 937 public void abort(final Executor executor) throws SQLException { 938 checkOpen(); 939 try { 940 connection.abort(executor); 941 } catch (final SQLException e) { 942 handleException(e); 943 } 944 } 945 946 @Override 947 public void setNetworkTimeout(final Executor executor, final int milliseconds) throws SQLException { 948 checkOpen(); 949 try { 950 connection.setNetworkTimeout(executor, milliseconds); 951 } catch (final SQLException e) { 952 handleException(e); 953 } 954 } 955 956 @Override 957 public int getNetworkTimeout() throws SQLException { 958 checkOpen(); 959 try { 960 return connection.getNetworkTimeout(); 961 } catch (final SQLException e) { 962 handleException(e); 963 return 0; 964 } 965 } 966}