KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > commons > dbcp > cpdsadapter > PooledConnectionImpl


1 /*
2  * Copyright 1999-2004 The Apache Software Foundation.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16
17 package org.apache.commons.dbcp.cpdsadapter;
18
19 import java.sql.Connection JavaDoc;
20 import java.sql.PreparedStatement JavaDoc;
21 import java.sql.SQLException JavaDoc;
22 import java.util.Iterator JavaDoc;
23 import java.util.Vector JavaDoc;
24
25 import javax.sql.ConnectionEvent JavaDoc;
26 import javax.sql.ConnectionEventListener JavaDoc;
27 import javax.sql.PooledConnection JavaDoc;
28
29 import org.apache.commons.dbcp.DelegatingConnection;
30 import org.apache.commons.dbcp.DelegatingPreparedStatement;
31 import org.apache.commons.dbcp.SQLNestedException;
32 import org.apache.commons.pool.KeyedObjectPool;
33 import org.apache.commons.pool.KeyedPoolableObjectFactory;
34
35 /**
36  * Implementation of PooledConnection that is returned by
37  * PooledConnectionDataSource.
38  *
39  * @author John D. McNally
40  * @version $Revision: 1.16 $ $Date: 2004/03/07 11:19:25 $
41  */

42 class PooledConnectionImpl
43         implements PooledConnection JavaDoc, KeyedPoolableObjectFactory {
44     private static final String JavaDoc CLOSED
45             = "Attempted to use PooledConnection after closed() was called.";
46
47     /**
48      * The JDBC database connection that represents the physical db connection.
49      */

50     private Connection JavaDoc connection = null;
51     
52     /**
53      * A DelegatingConnection used to create a PoolablePreparedStatementStub
54      */

55     private DelegatingConnection delegatingConnection = null;
56
57     /**
58      * The JDBC database logical connection.
59      */

60     private Connection JavaDoc logicalConnection = null;
61
62     /**
63      * ConnectionEventListeners
64      */

65     private Vector JavaDoc eventListeners;
66
67     /**
68      * flag set to true, once close() is called.
69      */

70     boolean isClosed;
71
72     /** My pool of {*link PreparedStatement}s. */
73     protected KeyedObjectPool pstmtPool = null;
74
75
76     /**
77      * Wrap the real connection.
78      */

79     PooledConnectionImpl(Connection JavaDoc connection, KeyedObjectPool pool) {
80         this.connection = connection;
81         if (connection instanceof DelegatingConnection) {
82             this.delegatingConnection = (DelegatingConnection) connection;
83         } else {
84             this.delegatingConnection = new DelegatingConnection(connection);
85         }
86         eventListeners = new Vector JavaDoc();
87         isClosed = false;
88         if (pool != null) {
89             pstmtPool = pool;
90             pstmtPool.setFactory(this);
91         }
92     }
93
94     /**
95      * Add an event listener.
96      */

97     public void addConnectionEventListener(ConnectionEventListener JavaDoc listener) {
98         if (!eventListeners.contains(listener)) {
99             eventListeners.add(listener);
100         }
101     }
102
103     /**
104      * Closes the physical connection and marks this
105      * <code>PooledConnection</code> so that it may not be used
106      * to generate any more logical <code>Connection</code>s.
107      *
108      * @exception SQLException if an error occurs
109      */

110     public void close() throws SQLException JavaDoc {
111         assertOpen();
112         isClosed = true;
113         try {
114             if (pstmtPool != null) {
115                 try {
116                     pstmtPool.close();
117                 } finally {
118                     pstmtPool = null;
119                 }
120             }
121         } catch (RuntimeException JavaDoc e) {
122             throw e;
123         } catch (Exception JavaDoc e) {
124             throw new SQLNestedException("Cannot close connection (return to pool failed)", e);
125         } finally {
126             try {
127                 connection.close();
128             } finally {
129                 connection = null;
130             }
131         }
132     }
133
134     /**
135      * Throws an SQLException, if isClosed() is true
136      */

137     private void assertOpen() throws SQLException JavaDoc {
138         if (isClosed) {
139             throw new SQLException JavaDoc(CLOSED);
140         }
141     }
142
143     /**
144      * Returns a JDBC connection.
145      *
146      * @return The database connection.
147      */

148     public Connection JavaDoc getConnection() throws SQLException JavaDoc {
149         assertOpen();
150         // make sure the last connection is marked as closed
151
if (logicalConnection != null && !logicalConnection.isClosed()) {
152             // should notify pool of error so the pooled connection can
153
// be removed !FIXME!
154
throw new SQLException JavaDoc("PooledConnection was reused, without"
155                     + "its previous Connection being closed.");
156         }
157
158         // the spec requires that this return a new Connection instance.
159
logicalConnection = new ConnectionImpl(this, connection);
160         return logicalConnection;
161     }
162
163     /**
164      * Remove an event listener.
165      */

166     public void removeConnectionEventListener(
167             ConnectionEventListener JavaDoc listener) {
168         eventListeners.remove(listener);
169     }
170
171     /**
172      * Closes the physical connection and checks that the logical connection
173      * was closed as well.
174      */

175     protected void finalize() throws Throwable JavaDoc {
176         // Closing the Connection ensures that if anyone tries to use it,
177
// an error will occur.
178
try {
179             connection.close();
180         } catch (Exception JavaDoc ignored) {
181         }
182
183         // make sure the last connection is marked as closed
184
if (logicalConnection != null && !logicalConnection.isClosed()) {
185             throw new SQLException JavaDoc("PooledConnection was gc'ed, without"
186                     + "its last Connection being closed.");
187         }
188     }
189
190     /**
191      * sends a connectionClosed event.
192      */

193     void notifyListeners() {
194         ConnectionEvent JavaDoc event = new ConnectionEvent JavaDoc(this);
195         Iterator JavaDoc i = eventListeners.iterator();
196         while (i.hasNext()) {
197             ((ConnectionEventListener JavaDoc) i.next()).connectionClosed(event);
198         }
199     }
200
201     // -------------------------------------------------------------------
202
// The following code implements a PreparedStatement pool
203

204     /**
205      * Create or obtain a {*link PreparedStatement} from my pool.
206      * @return a {*link PoolablePreparedStatement}
207      */

208     PreparedStatement JavaDoc prepareStatement(String JavaDoc sql) throws SQLException JavaDoc {
209         if (pstmtPool == null) {
210             return connection.prepareStatement(sql);
211         } else {
212             try {
213                 return (PreparedStatement JavaDoc)
214                         pstmtPool.borrowObject(createKey(sql));
215             } catch (RuntimeException JavaDoc e) {
216                 throw e;
217             } catch (Exception JavaDoc e) {
218                 throw new SQLNestedException("Borrow prepareStatement from pool failed", e);
219             }
220         }
221     }
222
223     /**
224      * Create or obtain a {*link PreparedStatement} from my pool.
225      * @return a {*link PoolablePreparedStatement}
226      */

227     PreparedStatement JavaDoc prepareStatement(String JavaDoc sql, int resultSetType,
228                                        int resultSetConcurrency)
229             throws SQLException JavaDoc {
230         if (pstmtPool == null) {
231             return connection.prepareStatement(sql, resultSetType, resultSetConcurrency);
232         } else {
233             try {
234                 return (PreparedStatement JavaDoc) pstmtPool.borrowObject(
235                     createKey(sql,resultSetType,resultSetConcurrency));
236             } catch (RuntimeException JavaDoc e) {
237                 throw e;
238             } catch (Exception JavaDoc e) {
239                 throw new SQLNestedException("Borrow prepareStatement from pool failed", e);
240             }
241         }
242     }
243
244     /**
245      * Create a {*link PooledConnectionImpl.PStmtKey} for the given arguments.
246      */

247     protected Object JavaDoc createKey(String JavaDoc sql, int resultSetType,
248                                int resultSetConcurrency) {
249         return new PStmtKey(normalizeSQL(sql), resultSetType,
250                             resultSetConcurrency);
251     }
252
253     /**
254      * Create a {*link PooledConnectionImpl.PStmtKey} for the given arguments.
255      */

256     protected Object JavaDoc createKey(String JavaDoc sql) {
257         return new PStmtKey(normalizeSQL(sql));
258     }
259
260     /**
261      * Normalize the given SQL statement, producing a
262      * cannonical form that is semantically equivalent to the original.
263      */

264     protected String JavaDoc normalizeSQL(String JavaDoc sql) {
265         return sql.trim();
266     }
267
268     /**
269      * My {*link KeyedPoolableObjectFactory} method for creating
270      * {*link PreparedStatement}s.
271      * @param obj the key for the {*link PreparedStatement} to be created
272      */

273     public Object JavaDoc makeObject(Object JavaDoc obj) throws Exception JavaDoc {
274         if (null == obj || !(obj instanceof PStmtKey)) {
275             throw new IllegalArgumentException JavaDoc();
276         } else {
277             // _openPstmts++;
278
PStmtKey key = (PStmtKey)obj;
279             if (null == key._resultSetType
280                     && null == key._resultSetConcurrency) {
281                 return new PoolablePreparedStatementStub(
282                         connection.prepareStatement(key._sql),
283                         key, pstmtPool, delegatingConnection);
284             } else {
285                 return new PoolablePreparedStatementStub(
286                         connection.prepareStatement(key._sql,
287                         key._resultSetType.intValue(),
288                         key._resultSetConcurrency.intValue()),
289                         key, pstmtPool, delegatingConnection);
290             }
291         }
292     }
293
294     /**
295      * My {*link KeyedPoolableObjectFactory} method for destroying
296      * {*link PreparedStatement}s.
297      * @param key ignored
298      * @param obj the {*link PreparedStatement} to be destroyed.
299      */

300     public void destroyObject(Object JavaDoc key, Object JavaDoc obj) throws Exception JavaDoc {
301         //_openPstmts--;
302
if (obj instanceof DelegatingPreparedStatement) {
303             ((DelegatingPreparedStatement) obj).getInnermostDelegate().close();
304         } else {
305             ((PreparedStatement JavaDoc) obj).close();
306         }
307     }
308
309     /**
310      * My {*link KeyedPoolableObjectFactory} method for validating
311      * {*link PreparedStatement}s.
312      * @param key ignored
313      * @param obj ignored
314      * @return <tt>true</tt>
315      */

316     public boolean validateObject(Object JavaDoc key, Object JavaDoc obj) {
317         return true;
318     }
319
320     /**
321      * My {*link KeyedPoolableObjectFactory} method for activating
322      * {*link PreparedStatement}s.
323      * @param key ignored
324      * @param obj ignored
325      */

326     public void activateObject(Object JavaDoc key, Object JavaDoc obj) throws Exception JavaDoc {
327         ((PoolablePreparedStatementStub) obj).activate();
328     }
329
330     /**
331      * My {*link KeyedPoolableObjectFactory} method for passivating
332      * {*link PreparedStatement}s. Currently invokes {*link PreparedStatement#clearParameters}.
333      * @param key ignored
334      * @param obj a {*link PreparedStatement}
335      */

336     public void passivateObject(Object JavaDoc key, Object JavaDoc obj) throws Exception JavaDoc {
337         ((PreparedStatement JavaDoc) obj).clearParameters();
338         ((PoolablePreparedStatementStub) obj).passivate();
339     }
340
341     /**
342      * A key uniquely identifying {*link PreparedStatement}s.
343      */

344     class PStmtKey {
345         protected String JavaDoc _sql = null;
346         protected Integer JavaDoc _resultSetType = null;
347         protected Integer JavaDoc _resultSetConcurrency = null;
348
349         PStmtKey(String JavaDoc sql) {
350             _sql = sql;
351         }
352
353         PStmtKey(String JavaDoc sql, int resultSetType, int resultSetConcurrency) {
354             _sql = sql;
355             _resultSetType = new Integer JavaDoc(resultSetType);
356             _resultSetConcurrency = new Integer JavaDoc(resultSetConcurrency);
357         }
358
359         public boolean equals(Object JavaDoc that) {
360             try {
361                 PStmtKey key = (PStmtKey) that;
362                 return(((null == _sql && null == key._sql) || _sql.equals(key._sql)) &&
363                        ((null == _resultSetType && null == key._resultSetType) || _resultSetType.equals(key._resultSetType)) &&
364                        ((null == _resultSetConcurrency && null == key._resultSetConcurrency) || _resultSetConcurrency.equals(key._resultSetConcurrency))
365                       );
366             } catch (ClassCastException JavaDoc e) {
367                 return false;
368             } catch (NullPointerException JavaDoc e) {
369                 return false;
370             }
371         }
372
373         public int hashCode() {
374             return(null == _sql ? 0 : _sql.hashCode());
375         }
376
377         public String JavaDoc toString() {
378             StringBuffer JavaDoc buf = new StringBuffer JavaDoc();
379             buf.append("PStmtKey: sql=");
380             buf.append(_sql);
381             buf.append(", resultSetType=");
382             buf.append(_resultSetType);
383             buf.append(", resultSetConcurrency=");
384             buf.append(_resultSetConcurrency);
385             return buf.toString();
386         }
387     }
388 }
389
Popular Tags