KickJava   Java API By Example, From Geeks To Geeks.

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


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.io.IOException JavaDoc;
20 import java.io.ObjectInputStream JavaDoc;
21 import java.sql.Connection JavaDoc;
22 import java.sql.SQLException JavaDoc;
23 import java.util.HashMap JavaDoc;
24 import java.util.Iterator JavaDoc;
25 import java.util.Map JavaDoc;
26
27 import javax.naming.NamingException JavaDoc;
28 import javax.sql.ConnectionPoolDataSource JavaDoc;
29
30 import org.apache.commons.pool.ObjectPool;
31 import org.apache.commons.pool.impl.GenericObjectPool;
32 import org.apache.commons.dbcp.SQLNestedException;
33
34 /**
35  * <p>
36  * A pooling <code>DataSource</code> appropriate for deployment within
37  * J2EE environment. There are many configuration options, most of which are
38  * defined in the parent class. This datasource uses individual pools per
39  * user, and some properties can be set specifically for a given user, if the
40  * deployment environment can support initialization of mapped properties.
41  * So for example, a pool of admin or write-access Connections can be
42  * guaranteed a certain number of connections, separate from a maximum
43  * set for users with read-only connections.
44  * </p>
45  *
46  * @author John D. McNally
47  * @version $Revision: 1.10 $ $Date: 2004/02/28 12:18:17 $
48  */

49 public class PerUserPoolDataSource
50     extends InstanceKeyDataSource {
51     private static final Map JavaDoc poolKeys = new HashMap JavaDoc();
52
53     private int defaultMaxActive = GenericObjectPool.DEFAULT_MAX_ACTIVE;
54     private int defaultMaxIdle = GenericObjectPool.DEFAULT_MAX_IDLE;
55     private int defaultMaxWait = (int)Math.min((long)Integer.MAX_VALUE,
56         GenericObjectPool.DEFAULT_MAX_WAIT);
57     Map JavaDoc perUserDefaultAutoCommit = null;
58     Map JavaDoc perUserDefaultTransactionIsolation = null;
59     Map JavaDoc perUserMaxActive = null;
60     Map JavaDoc perUserMaxIdle = null;
61     Map JavaDoc perUserMaxWait = null;
62     Map JavaDoc perUserDefaultReadOnly = null;
63
64     private transient Map JavaDoc pools = new HashMap JavaDoc();
65
66     /**
67      * Default no-arg constructor for Serialization
68      */

69     public PerUserPoolDataSource() {
70     }
71
72     /**
73      * Close all pools in the given Map.
74      */

75     private static void close(Map JavaDoc poolMap) {
76     }
77
78     /**
79      * Close pool(s) being maintained by this datasource.
80      */

81     public void close() {
82         for (Iterator JavaDoc poolIter = pools.values().iterator();
83              poolIter.hasNext();) {
84             try {
85                 ((ObjectPool) poolIter.next()).close();
86             } catch (Exception JavaDoc closePoolException) {
87                     //ignore and try to close others.
88
}
89         }
90         InstanceKeyObjectFactory.removeInstance(instanceKey);
91     }
92
93     // -------------------------------------------------------------------
94
// Properties
95

96     /**
97      * The maximum number of active connections that can be allocated from
98      * this pool at the same time, or zero for no limit.
99      * This value is used for any username which is not specified
100      * in perUserMaxConnections. The default is 0.
101      */

102     public int getDefaultMaxActive() {
103         return (this.defaultMaxActive);
104     }
105
106     /**
107      * The maximum number of active connections that can be allocated from
108      * this pool at the same time, or zero for no limit.
109      * This value is used for any username which is not specified
110      * in perUserMaxConnections. The default is 0.
111      */

112     public void setDefaultMaxActive(int maxActive) {
113         assertInitializationAllowed();
114         this.defaultMaxActive = maxActive;
115     }
116
117     /**
118      * The maximum number of active connections that can remain idle in the
119      * pool, without extra ones being released, or zero for no limit.
120      * This value is used for any username which is not specified
121      * in perUserMaxIdle. The default is 0.
122      */

123     public int getDefaultMaxIdle() {
124         return (this.defaultMaxIdle);
125     }
126
127     /**
128      * The maximum number of active connections that can remain idle in the
129      * pool, without extra ones being released, or zero for no limit.
130      * This value is used for any username which is not specified
131      * in perUserMaxIdle. The default is 0.
132      */

133     public void setDefaultMaxIdle(int defaultMaxIdle) {
134         assertInitializationAllowed();
135         this.defaultMaxIdle = defaultMaxIdle;
136     }
137
138     /**
139      * The maximum number of milliseconds that the pool will wait (when there
140      * are no available connections) for a connection to be returned before
141      * throwing an exception, or -1 to wait indefinitely. Will fail
142      * immediately if value is 0.
143      * This value is used for any username which is not specified
144      * in perUserMaxWait. The default is -1.
145      */

146     public int getDefaultMaxWait() {
147         return (this.defaultMaxWait);
148     }
149
150     /**
151      * The maximum number of milliseconds that the pool will wait (when there
152      * are no available connections) for a connection to be returned before
153      * throwing an exception, or -1 to wait indefinitely. Will fail
154      * immediately if value is 0.
155      * This value is used for any username which is not specified
156      * in perUserMaxWait. The default is -1.
157      */

158     public void setDefaultMaxWait(int defaultMaxWait) {
159         assertInitializationAllowed();
160         this.defaultMaxWait = defaultMaxWait;
161     }
162
163     /**
164      * The keys are usernames and the value is the --. Any
165      * username specified here will override the value of defaultAutoCommit.
166      */

167     public Boolean JavaDoc getPerUserDefaultAutoCommit(String JavaDoc key) {
168         Boolean JavaDoc value = null;
169         if (perUserDefaultAutoCommit != null) {
170             value = (Boolean JavaDoc) perUserDefaultAutoCommit.get(key);
171         }
172         return value;
173     }
174     
175     /**
176      * The keys are usernames and the value is the --. Any
177      * username specified here will override the value of defaultAutoCommit.
178      */

179     public void setPerUserDefaultAutoCommit(String JavaDoc username, Boolean JavaDoc value) {
180         assertInitializationAllowed();
181         if (perUserDefaultAutoCommit == null) {
182             perUserDefaultAutoCommit = new HashMap JavaDoc();
183         }
184         perUserDefaultAutoCommit.put(username, value);
185     }
186
187     /**
188      * The isolation level of connections when returned from getConnection.
189      * If null, the username will use the value of defaultTransactionIsolation.
190      */

191     public Integer JavaDoc getPerUserDefaultTransactionIsolation(String JavaDoc username) {
192         Integer JavaDoc value = null;
193         if (perUserDefaultTransactionIsolation != null) {
194             value = (Integer JavaDoc) perUserDefaultTransactionIsolation.get(username);
195         }
196         return value;
197     }
198
199     /**
200      * The isolation level of connections when returned from getConnection.
201      * Valid values are the constants defined in Connection.
202      */

203     public void setPerUserDefaultTransactionIsolation(String JavaDoc username,
204                                                       Integer JavaDoc value) {
205         assertInitializationAllowed();
206         if (perUserDefaultTransactionIsolation == null) {
207             perUserDefaultTransactionIsolation = new HashMap JavaDoc();
208         }
209         perUserDefaultTransactionIsolation.put(username, value);
210     }
211
212     /**
213      * The maximum number of active connections that can be allocated from
214      * this pool at the same time, or zero for no limit.
215      * The keys are usernames and the value is the maximum connections. Any
216      * username specified here will override the value of defaultMaxActive.
217      */

218     public Integer JavaDoc getPerUserMaxActive(String JavaDoc username) {
219         Integer JavaDoc value = null;
220         if (perUserMaxActive != null) {
221             value = (Integer JavaDoc) perUserMaxActive.get(username);
222         }
223         return value;
224     }
225     
226     /**
227      * The maximum number of active connections that can be allocated from
228      * this pool at the same time, or zero for no limit.
229      * The keys are usernames and the value is the maximum connections. Any
230      * username specified here will override the value of defaultMaxActive.
231      */

232     public void setPerUserMaxActive(String JavaDoc username, Integer JavaDoc value) {
233         assertInitializationAllowed();
234         if (perUserMaxActive == null) {
235             perUserMaxActive = new HashMap JavaDoc();
236         }
237         perUserMaxActive.put(username, value);
238     }
239
240
241     /**
242      * The maximum number of active connections that can remain idle in the
243      * pool, without extra ones being released, or zero for no limit.
244      * The keys are usernames and the value is the maximum connections. Any
245      * username specified here will override the value of defaultMaxIdle.
246      */

247     public Integer JavaDoc getPerUserMaxIdle(String JavaDoc username) {
248         Integer JavaDoc value = null;
249         if (perUserMaxIdle != null) {
250             value = (Integer JavaDoc) perUserMaxIdle.get(username);
251         }
252         return value;
253     }
254     
255     /**
256      * The maximum number of active connections that can remain idle in the
257      * pool, without extra ones being released, or zero for no limit.
258      * The keys are usernames and the value is the maximum connections. Any
259      * username specified here will override the value of defaultMaxIdle.
260      */

261     public void setPerUserMaxIdle(String JavaDoc username, Integer JavaDoc value) {
262         assertInitializationAllowed();
263         if (perUserMaxIdle == null) {
264             perUserMaxIdle = new HashMap JavaDoc();
265         }
266         perUserMaxIdle.put(username, value);
267     }
268     
269     /**
270      * The maximum number of milliseconds that the pool will wait (when there
271      * are no available connections) for a connection to be returned before
272      * throwing an exception, or -1 to wait indefinitely. Will fail
273      * immediately if value is 0.
274      * The keys are usernames and the value is the maximum connections. Any
275      * username specified here will override the value of defaultMaxWait.
276      */

277     public Integer JavaDoc getPerUserMaxWait(String JavaDoc username) {
278         Integer JavaDoc value = null;
279         if (perUserMaxWait != null) {
280             value = (Integer JavaDoc) perUserMaxWait.get(username);
281         }
282         return value;
283     }
284     
285     /**
286      * The maximum number of milliseconds that the pool will wait (when there
287      * are no available connections) for a connection to be returned before
288      * throwing an exception, or -1 to wait indefinitely. Will fail
289      * immediately if value is 0.
290      * The keys are usernames and the value is the maximum connections. Any
291      * username specified here will override the value of defaultMaxWait.
292      */

293     public void setPerUserMaxWait(String JavaDoc username, Integer JavaDoc value) {
294         assertInitializationAllowed();
295         if (perUserMaxWait == null) {
296             perUserMaxWait = new HashMap JavaDoc();
297         }
298         perUserMaxWait.put(username, value);
299     }
300
301     /**
302      * The keys are usernames and the value is the --. Any
303      * username specified here will override the value of defaultReadOnly.
304      */

305     public Boolean JavaDoc getPerUserDefaultReadOnly(String JavaDoc username) {
306         Boolean JavaDoc value = null;
307         if (perUserDefaultReadOnly != null) {
308             value = (Boolean JavaDoc) perUserDefaultReadOnly.get(username);
309         }
310         return value;
311     }
312     
313     /**
314      * The keys are usernames and the value is the --. Any
315      * username specified here will override the value of defaultReadOnly.
316      */

317     public void setPerUserDefaultReadOnly(String JavaDoc username, Boolean JavaDoc value) {
318         assertInitializationAllowed();
319         if (perUserDefaultReadOnly == null) {
320             perUserDefaultReadOnly = new HashMap JavaDoc();
321         }
322         perUserDefaultReadOnly.put(username, value);
323     }
324
325     // ----------------------------------------------------------------------
326
// Instrumentation Methods
327

328     /**
329      * Get the number of active connections in the default pool.
330      */

331     public int getNumActive() {
332         return getNumActive(null, null);
333     }
334
335     /**
336      * Get the number of active connections in the pool for a given user.
337      */

338     public int getNumActive(String JavaDoc username, String JavaDoc password) {
339         ObjectPool pool = (ObjectPool)pools.get(getPoolKey(username));
340         return (pool == null) ? 0 : pool.getNumActive();
341     }
342
343     /**
344      * Get the number of idle connections in the default pool.
345      */

346     public int getNumIdle() {
347         return getNumIdle(null, null);
348     }
349
350     /**
351      * Get the number of idle connections in the pool for a given user.
352      */

353     public int getNumIdle(String JavaDoc username, String JavaDoc password) {
354         ObjectPool pool = (ObjectPool)pools.get(getPoolKey(username));
355         return (pool == null) ? 0 : pool.getNumIdle();
356     }
357
358
359     // ----------------------------------------------------------------------
360
// Inherited abstract methods
361

362     protected synchronized PooledConnectionAndInfo
363         getPooledConnectionAndInfo(String JavaDoc username, String JavaDoc password)
364         throws SQLException JavaDoc {
365
366         PoolKey key = getPoolKey(username);
367         Object JavaDoc pool = pools.get(key);
368         if (pool == null) {
369             try {
370                 registerPool(username, password);
371                 pool = pools.get(key);
372             } catch (NamingException JavaDoc e) {
373                 throw new SQLNestedException("RegisterPool failed", e);
374             }
375         }
376
377         PooledConnectionAndInfo info = null;
378         try {
379             info = (PooledConnectionAndInfo)((ObjectPool) pool).borrowObject();
380         }
381         catch (Exception JavaDoc e) {
382             throw new SQLNestedException(
383                 "Could not retrieve connection info from pool", e);
384         }
385         
386         return info;
387     }
388
389     protected void setupDefaults(Connection JavaDoc con, String JavaDoc username)
390         throws SQLException JavaDoc {
391         boolean defaultAutoCommit = isDefaultAutoCommit();
392         if (username != null) {
393             Boolean JavaDoc userMax = getPerUserDefaultAutoCommit(username);
394             if (userMax != null) {
395                 defaultAutoCommit = userMax.booleanValue();
396             }
397         }
398
399         boolean defaultReadOnly = isDefaultReadOnly();
400         if (username != null) {
401             Boolean JavaDoc userMax = getPerUserDefaultReadOnly(username);
402             if (userMax != null) {
403                 defaultReadOnly = userMax.booleanValue();
404             }
405         }
406
407         int defaultTransactionIsolation = getDefaultTransactionIsolation();
408         if (username != null) {
409             Integer JavaDoc userMax = getPerUserDefaultTransactionIsolation(username);
410             if (userMax != null) {
411                 defaultTransactionIsolation = userMax.intValue();
412             }
413         }
414
415         con.setAutoCommit(defaultAutoCommit);
416         con.setReadOnly(defaultReadOnly);
417         if (defaultTransactionIsolation != UNKNOWN_TRANSACTIONISOLATION) {
418             con.setTransactionIsolation(defaultTransactionIsolation);
419         }
420     }
421
422     private PoolKey getPoolKey(String JavaDoc username) {
423         PoolKey key = null;
424         String JavaDoc dsName = getDataSourceName();
425         Map JavaDoc dsMap = (Map JavaDoc) poolKeys.get(dsName);
426         if (dsMap != null) {
427             key = (PoolKey) dsMap.get(username);
428         }
429         
430         if (key == null) {
431             key = new PoolKey(dsName, username);
432             if (dsMap == null) {
433                 dsMap = new HashMap JavaDoc();
434                 poolKeys.put(dsName, dsMap);
435             }
436             dsMap.put(username, key);
437         }
438         return key;
439     }
440
441     private synchronized void registerPool(
442         String JavaDoc username, String JavaDoc password)
443         throws javax.naming.NamingException JavaDoc, SQLException JavaDoc {
444
445         ConnectionPoolDataSource JavaDoc cpds = testCPDS(username, password);
446
447         Integer JavaDoc userMax = getPerUserMaxActive(username);
448         int maxActive = (userMax == null) ?
449             getDefaultMaxActive() : userMax.intValue();
450         userMax = getPerUserMaxIdle(username);
451         int maxIdle = (userMax == null) ?
452             getDefaultMaxIdle() : userMax.intValue();
453         userMax = getPerUserMaxWait(username);
454         int maxWait = (userMax == null) ?
455             getDefaultMaxWait() : userMax.intValue();
456
457         // Create an object pool to contain our PooledConnections
458
GenericObjectPool pool = new GenericObjectPool(null);
459         pool.setMaxActive(maxActive);
460         pool.setMaxIdle(maxIdle);
461         pool.setMaxWait(maxWait);
462         pool.setWhenExhaustedAction(whenExhaustedAction(maxActive, maxWait));
463         pool.setTestOnBorrow(getTestOnBorrow());
464         pool.setTestOnReturn(getTestOnReturn());
465         pool.setTimeBetweenEvictionRunsMillis(
466             getTimeBetweenEvictionRunsMillis());
467         pool.setNumTestsPerEvictionRun(getNumTestsPerEvictionRun());
468         pool.setMinEvictableIdleTimeMillis(getMinEvictableIdleTimeMillis());
469         pool.setTestWhileIdle(getTestWhileIdle());
470                 
471         // Set up the factory we will use (passing the pool associates
472
// the factory with the pool, so we do not have to do so
473
// explicitly)
474
new CPDSConnectionFactory(cpds, pool, getValidationQuery(),
475                                   username, password);
476            
477         pools.put(getPoolKey(username), pool);
478     }
479
480     /**
481      * Supports Serialization interface.
482      *
483      * @param in a <code>java.io.ObjectInputStream</code> value
484      * @exception IOException if an error occurs
485      * @exception ClassNotFoundException if an error occurs
486      */

487     private void readObject(ObjectInputStream JavaDoc in)
488         throws IOException JavaDoc, ClassNotFoundException JavaDoc {
489         try
490         {
491             in.defaultReadObject();
492             PerUserPoolDataSource oldDS = (PerUserPoolDataSource)
493                 new PerUserPoolDataSourceFactory()
494                     .getObjectInstance(getReference(), null, null, null);
495             this.pools = oldDS.pools;
496         }
497         catch (NamingException JavaDoc e)
498         {
499             throw new IOException JavaDoc("NamingException: " + e);
500         }
501     }
502 }
503
Popular Tags