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
018 package org.apache.commons.dbcp;
019
020 import java.sql.Connection;
021 import java.sql.SQLException;
022 import org.apache.commons.pool.ObjectPool;
023
024 /**
025 * A delegating connection that, rather than closing the underlying
026 * connection, returns itself to an {@link ObjectPool} when
027 * closed.
028 *
029 * @author Rodney Waldhoff
030 * @author Glenn L. Nielsen
031 * @author James House
032 * @version $Revision: 892307 $ $Date: 2013-12-31 23:27:28 +0000 (Tue, 31 Dec 2013) $
033 */
034 public class PoolableConnection extends DelegatingConnection {
035 /** The pool to which I should return. */
036 // TODO: Correct use of the pool requires that this connection is only every returned to the pool once.
037 protected ObjectPool _pool = null;
038
039 /**
040 *
041 * @param conn my underlying connection
042 * @param pool the pool to which I should return when closed
043 */
044 public PoolableConnection(Connection conn, ObjectPool pool) {
045 super(conn);
046 _pool = pool;
047 }
048
049 /**
050 *
051 * @param conn my underlying connection
052 * @param pool the pool to which I should return when closed
053 * @param config the abandoned configuration settings
054 */
055 public PoolableConnection(Connection conn, ObjectPool pool, AbandonedConfig config) {
056 super(conn, config);
057 _pool = pool;
058 }
059
060
061 /**
062 * Returns me to my pool.
063 */
064 public synchronized void close() throws SQLException {
065 if (_closed) {
066 // already closed
067 return;
068 }
069
070 boolean isUnderlyingConectionClosed;
071 try {
072 isUnderlyingConectionClosed = _conn.isClosed();
073 } catch (SQLException e) {
074 try {
075 _pool.invalidateObject(this); // XXX should be guarded to happen at most once
076 } catch(IllegalStateException ise) {
077 // pool is closed, so close the connection
078 passivate();
079 getInnermostDelegate().close();
080 } catch (Exception ie) {
081 // DO NOTHING the original exception will be rethrown
082 }
083 throw (SQLException) new SQLException("Cannot close connection (isClosed check failed)").initCause(e);
084 }
085
086 if (!isUnderlyingConectionClosed) {
087 // Normal close: underlying connection is still open, so we
088 // simply need to return this proxy to the pool
089 try {
090 _pool.returnObject(this); // XXX should be guarded to happen at most once
091 } catch(IllegalStateException e) {
092 // pool is closed, so close the connection
093 passivate();
094 getInnermostDelegate().close();
095 } catch(SQLException e) {
096 throw e;
097 } catch(RuntimeException e) {
098 throw e;
099 } catch(Exception e) {
100 throw (SQLException) new SQLException("Cannot close connection (return to pool failed)").initCause(e);
101 }
102 } else {
103 // Abnormal close: underlying connection closed unexpectedly, so we
104 // must destroy this proxy
105 try {
106 _pool.invalidateObject(this); // XXX should be guarded to happen at most once
107 } catch(IllegalStateException e) {
108 // pool is closed, so close the connection
109 passivate();
110 getInnermostDelegate().close();
111 } catch (Exception ie) {
112 // DO NOTHING, "Already closed" exception thrown below
113 }
114 throw new SQLException("Already closed.");
115 }
116 }
117
118 /**
119 * Actually close my underlying {@link Connection}.
120 */
121 public void reallyClose() throws SQLException {
122 super.close();
123 }
124 }
125