View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    * 
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   * 
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  
18  package org.apache.commons.dbcp;
19  
20  import java.sql.Connection;
21  import java.sql.SQLException;
22  import org.apache.commons.pool.ObjectPool;
23  
24  /**
25   * A delegating connection that, rather than closing the underlying
26   * connection, returns itself to an {@link ObjectPool} when
27   * closed.
28   *
29   * @author Rodney Waldhoff
30   * @author Glenn L. Nielsen
31   * @author James House
32   * @version $Revision: 1023401 $ $Date: 2010-10-16 21:54:24 -0400 (Sat, 16 Oct 2010) $
33   */
34  public class PoolableConnection extends DelegatingConnection {
35      /** The pool to which I should return. */
36      // TODO: Correct use of the pool requires that this connection is only every returned to the pool once.
37      protected ObjectPool _pool = null;
38  
39      /**
40       *
41       * @param conn my underlying connection
42       * @param pool the pool to which I should return when closed
43       */
44      public PoolableConnection(Connection conn, ObjectPool pool) {
45          super(conn);
46          _pool = pool;
47      }
48  
49      /**
50       *
51       * @param conn my underlying connection
52       * @param pool the pool to which I should return when closed
53       * @param config the abandoned configuration settings
54       */
55      public PoolableConnection(Connection conn, ObjectPool pool, AbandonedConfig config) {
56          super(conn, config);
57          _pool = pool;
58      }
59  
60  
61      /**
62       * Returns me to my pool.
63       */
64       public synchronized void close() throws SQLException {
65          if (_closed) {
66              // already closed
67              return;
68          }
69  
70          boolean isUnderlyingConectionClosed;
71          try {
72              isUnderlyingConectionClosed = _conn.isClosed();
73          } catch (SQLException e) {
74              try {
75                  _pool.invalidateObject(this); // XXX should be guarded to happen at most once
76              } catch(IllegalStateException ise) {
77                  // pool is closed, so close the connection
78                  passivate();
79                  getInnermostDelegate().close();
80              } catch (Exception ie) {
81                  // DO NOTHING the original exception will be rethrown
82              }
83              throw (SQLException) new SQLException("Cannot close connection (isClosed check failed)").initCause(e);
84          }
85  
86          if (!isUnderlyingConectionClosed) {
87              // Normal close: underlying connection is still open, so we
88              // simply need to return this proxy to the pool
89              try {
90                  _pool.returnObject(this); // XXX should be guarded to happen at most once
91              } catch(IllegalStateException e) {
92                  // pool is closed, so close the connection
93                  passivate();
94                  getInnermostDelegate().close();
95              } catch(SQLException e) {
96                  throw e;
97              } catch(RuntimeException e) {
98                  throw e;
99              } 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