    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}