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