KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > commons > dbcp > datasources > KeyedCPDSConnectionFactory


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.datasources;
18
19 import java.sql.Connection JavaDoc;
20 import java.sql.ResultSet JavaDoc;
21 import java.sql.SQLException JavaDoc;
22 import java.sql.Statement JavaDoc;
23 import java.util.HashMap JavaDoc;
24 import java.util.Map JavaDoc;
25 import java.util.WeakHashMap JavaDoc;
26
27 import javax.sql.ConnectionEvent JavaDoc;
28 import javax.sql.ConnectionEventListener JavaDoc;
29 import javax.sql.ConnectionPoolDataSource JavaDoc;
30 import javax.sql.PooledConnection JavaDoc;
31
32 import org.apache.commons.dbcp.SQLNestedException;
33 import org.apache.commons.pool.KeyedObjectPool;
34 import org.apache.commons.pool.KeyedPoolableObjectFactory;
35
36 /**
37  * A {*link PoolableObjectFactory} that creates
38  * {*link PoolableConnection}s.
39  *
40  * @author John D. McNally
41  * @version $Revision: 1.6 $ $Date: 2004/03/07 11:19:25 $
42  */

43 class KeyedCPDSConnectionFactory
44     implements KeyedPoolableObjectFactory, ConnectionEventListener JavaDoc {
45
46     private static final String JavaDoc NO_KEY_MESSAGE
47             = "close() was called on a Connection, but "
48             + "I have no record of the underlying PooledConnection.";
49
50     protected ConnectionPoolDataSource JavaDoc _cpds = null;
51     protected String JavaDoc _validationQuery = null;
52     protected KeyedObjectPool _pool = null;
53     private Map JavaDoc validatingMap = new HashMap JavaDoc();
54     private WeakHashMap JavaDoc pcMap = new WeakHashMap JavaDoc();
55
56     /**
57      * Create a new <tt>KeyedPoolableConnectionFactory</tt>.
58      * @param cpds the ConnectionPoolDataSource from which to obtain PooledConnection's
59      * @param pool the {*link ObjectPool} in which to pool those {*link Connection}s
60      * @param validationQuery a query to use to {*link #validateObject validate} {*link Connection}s. Should return at least one row. May be <tt>null</tt>
61      */

62     public KeyedCPDSConnectionFactory(ConnectionPoolDataSource JavaDoc cpds,
63                                       KeyedObjectPool pool,
64                                       String JavaDoc validationQuery) {
65         _cpds = cpds;
66         _pool = pool;
67         _pool.setFactory(this);
68         _validationQuery = validationQuery;
69     }
70
71     /**
72      * Sets the {*link ConnectionFactory} from which to obtain base {*link Connection}s.
73      * @param connFactory the {*link ConnectionFactory} from which to obtain base {*link Connection}s
74      */

75     synchronized public void setCPDS(ConnectionPoolDataSource JavaDoc cpds) {
76         _cpds = cpds;
77     }
78
79     /**
80      * Sets the query I use to {*link #validateObject validate} {*link Connection}s.
81      * Should return at least one row.
82      * May be <tt>null</tt>
83      * @param validationQuery a query to use to {*link #validateObject validate} {*link Connection}s.
84      */

85     synchronized public void setValidationQuery(String JavaDoc validationQuery) {
86         _validationQuery = validationQuery;
87     }
88
89     /**
90      * Sets the {*link ObjectPool} in which to pool {*link Connection}s.
91      * @param pool the {*link ObjectPool} in which to pool those {*link Connection}s
92      */

93     synchronized public void setPool(KeyedObjectPool pool)
94         throws SQLException JavaDoc {
95         if (null != _pool && pool != _pool) {
96             try {
97                 _pool.close();
98             } catch (RuntimeException JavaDoc e) {
99                 throw e;
100             } catch (Exception JavaDoc e) {
101                 throw new SQLNestedException("Cannot set the pool on this factory", e);
102             }
103         }
104         _pool = pool;
105     }
106
107     public KeyedObjectPool getPool() {
108         return _pool;
109     }
110
111     /**
112      * @param key
113      * @throws SQLException if the connection could not be created.
114      * @see org.apache.commons.pool.KeyedPoolableObjectFactory#makeObject(java.lang.Object)
115      */

116     public synchronized Object JavaDoc makeObject(Object JavaDoc key) throws Exception JavaDoc {
117         Object JavaDoc obj = null;
118         UserPassKey upkey = (UserPassKey)key;
119
120         PooledConnection JavaDoc pc = null;
121         String JavaDoc username = upkey.getUsername();
122         String JavaDoc password = upkey.getPassword();
123         if (username == null) {
124             pc = _cpds.getPooledConnection();
125         } else {
126             pc = _cpds.getPooledConnection(username, password);
127         }
128         // should we add this object as a listener or the pool.
129
// consider the validateObject method in decision
130
pc.addConnectionEventListener(this);
131         obj = new PooledConnectionAndInfo(pc, username, password);
132         pcMap.put(pc, obj);
133  
134         return obj;
135     }
136
137     public void destroyObject(Object JavaDoc key, Object JavaDoc obj) throws Exception JavaDoc {
138         if (obj instanceof PooledConnectionAndInfo) {
139             PooledConnection JavaDoc pc = ((PooledConnectionAndInfo)obj).getPooledConnection();
140             pcMap.remove(pc);
141             pc.close();
142         }
143     }
144
145     public boolean validateObject(Object JavaDoc key, Object JavaDoc obj) {
146         boolean valid = false;
147         if (obj instanceof PooledConnectionAndInfo) {
148             PooledConnection JavaDoc pconn =
149                 ((PooledConnectionAndInfo)obj).getPooledConnection();
150             String JavaDoc query = _validationQuery;
151             if (null != query) {
152                 Connection JavaDoc conn = null;
153                 Statement JavaDoc stmt = null;
154                 ResultSet JavaDoc rset = null;
155                 // logical Connection from the PooledConnection must be closed
156
// before another one can be requested and closing it will
157
// generate an event. Keep track so we know not to return
158
// the PooledConnection
159
validatingMap.put(pconn, null);
160                 try {
161                     conn = pconn.getConnection();
162                     stmt = conn.createStatement();
163                     rset = stmt.executeQuery(query);
164                     if (rset.next()) {
165                         valid = true;
166                     } else {
167                         valid = false;
168                     }
169                 } catch(Exception JavaDoc e) {
170                     valid = false;
171                 } finally {
172                     try {
173                         rset.close();
174                     } catch (Throwable JavaDoc t) {
175                         // ignore
176
}
177                     try {
178                         stmt.close();
179                     } catch (Throwable JavaDoc t) {
180                         // ignore
181
}
182                     try {
183                         conn.close();
184                     } catch (Throwable JavaDoc t) {
185                         // ignore
186
}
187                     validatingMap.remove(pconn);
188                 }
189             } else {
190                 valid = true;
191             }
192         } else {
193             valid = false;
194         }
195         return valid;
196     }
197
198     public void passivateObject(Object JavaDoc key, Object JavaDoc obj) {
199     }
200
201     public void activateObject(Object JavaDoc key, Object JavaDoc obj) {
202     }
203
204     // ***********************************************************************
205
// java.sql.ConnectionEventListener implementation
206
// ***********************************************************************
207

208     /**
209      * This will be called if the Connection returned by the getConnection
210      * method came from a PooledConnection, and the user calls the close()
211      * method of this connection object. What we need to do here is to
212      * release this PooledConnection from our pool...
213      */

214     public void connectionClosed(ConnectionEvent JavaDoc event) {
215         PooledConnection JavaDoc pc = (PooledConnection JavaDoc)event.getSource();
216         // if this event occured becase we were validating, ignore it
217
// otherwise return the connection to the pool.
218
if (!validatingMap.containsKey(pc)) {
219             PooledConnectionAndInfo info =
220                 (PooledConnectionAndInfo) pcMap.get(pc);
221             if (info == null) {
222                 throw new IllegalStateException JavaDoc(NO_KEY_MESSAGE);
223             }
224             try {
225                 _pool.returnObject(info.getUserPassKey(), info);
226             } catch (Exception JavaDoc e) {
227                 System.err.println("CLOSING DOWN CONNECTION AS IT COULD " +
228                                    "NOT BE RETURNED TO THE POOL");
229                 try {
230                     destroyObject(info.getUserPassKey(), info);
231                 } catch (Exception JavaDoc e2) {
232                     System.err.println("EXCEPTION WHILE DESTROYING OBJECT " +
233                                        info);
234                     e2.printStackTrace();
235                 }
236             }
237         }
238     }
239
240     /**
241      * If a fatal error occurs, close the underlying physical connection so as
242      * not to be returned in the future
243      */

244     public void connectionErrorOccurred(ConnectionEvent JavaDoc event) {
245         PooledConnection JavaDoc pc = (PooledConnection JavaDoc)event.getSource();
246         try {
247             if (null != event.getSQLException()) {
248                 System.err
249                     .println("CLOSING DOWN CONNECTION DUE TO INTERNAL ERROR (" +
250                              event.getSQLException() + ")");
251             }
252             //remove this from the listener list because we are no more
253
//interested in errors since we are about to close this connection
254
pc.removeConnectionEventListener(this);
255         } catch (Exception JavaDoc ignore) {
256             // ignore
257
}
258
259         PooledConnectionAndInfo info = (PooledConnectionAndInfo) pcMap.get(pc);
260         if (info == null) {
261             throw new IllegalStateException JavaDoc(NO_KEY_MESSAGE);
262         }
263         try {
264             destroyObject(info.getUserPassKey(), info);
265         } catch (Exception JavaDoc e) {
266             System.err.println("EXCEPTION WHILE DESTROYING OBJECT " + info);
267             e.printStackTrace();
268         }
269     }
270 }
271
Popular Tags