1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.commons.dbcp.datasources;
19
20 import java.io.IOException;
21 import java.io.ObjectInputStream;
22 import java.sql.Connection;
23 import java.sql.SQLException;
24 import java.util.HashMap;
25 import java.util.Iterator;
26 import java.util.Map;
27 import java.util.NoSuchElementException;
28
29 import javax.naming.NamingException;
30 import javax.naming.Reference;
31 import javax.naming.StringRefAddr;
32 import javax.sql.ConnectionPoolDataSource;
33
34 import org.apache.commons.dbcp.SQLNestedException;
35
36 import org.apache.commons.pool.ObjectPool;
37 import org.apache.commons.pool.impl.GenericObjectPool;
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60 public class PerUserPoolDataSource
61 extends InstanceKeyDataSource {
62
63 private static final long serialVersionUID = -3104731034410444060L;
64
65 private int defaultMaxActive = GenericObjectPool.DEFAULT_MAX_ACTIVE;
66 private int defaultMaxIdle = GenericObjectPool.DEFAULT_MAX_IDLE;
67 private int defaultMaxWait = (int)Math.min(Integer.MAX_VALUE,
68 GenericObjectPool.DEFAULT_MAX_WAIT);
69 Map perUserDefaultAutoCommit = null;
70 Map perUserDefaultTransactionIsolation = null;
71 Map perUserMaxActive = null;
72 Map perUserMaxIdle = null;
73 Map perUserMaxWait = null;
74 Map perUserDefaultReadOnly = null;
75
76
77
78
79 private transient Map
80
81
82
83
84 public PerUserPoolDataSource() {
85 }
86
87
88
89
90 public void close() {
91 for (Iterator poolIter = managers.values().iterator();
92 poolIter.hasNext();) {
93 try {
94 ((CPDSConnectionFactory) poolIter.next()).getPool().close();
95 } catch (Exception closePoolException) {
96
97 }
98 }
99 InstanceKeyObjectFactory.removeInstance(instanceKey);
100 }
101
102
103
104
105
106
107
108
109
110
111 public int getDefaultMaxActive() {
112 return (this.defaultMaxActive);
113 }
114
115
116
117
118
119
120
121 public void setDefaultMaxActive(int maxActive) {
122 assertInitializationAllowed();
123 this.defaultMaxActive = maxActive;
124 }
125
126
127
128
129
130
131
132 public int getDefaultMaxIdle() {
133 return (this.defaultMaxIdle);
134 }
135
136
137
138
139
140
141
142 public void setDefaultMaxIdle(int defaultMaxIdle) {
143 assertInitializationAllowed();
144 this.defaultMaxIdle = defaultMaxIdle;
145 }
146
147
148
149
150
151
152
153
154
155 public int getDefaultMaxWait() {
156 return (this.defaultMaxWait);
157 }
158
159
160
161
162
163
164
165
166
167 public void setDefaultMaxWait(int defaultMaxWait) {
168 assertInitializationAllowed();
169 this.defaultMaxWait = defaultMaxWait;
170 }
171
172
173
174
175
176 public Boolean getPerUserDefaultAutoCommit(String key) {
177 Boolean value = null;
178 if (perUserDefaultAutoCommit != null) {
179 value = (Boolean) perUserDefaultAutoCommit.get(key);
180 }
181 return value;
182 }
183
184
185
186
187
188 public void setPerUserDefaultAutoCommit(String username, Boolean value) {
189 assertInitializationAllowed();
190 if (perUserDefaultAutoCommit == null) {
191 perUserDefaultAutoCommit = new HashMap();
192 }
193 perUserDefaultAutoCommit.put(username, value);
194 }
195
196
197
198
199
200 public Integer getPerUserDefaultTransactionIsolation(String username) {
201 Integer value = null;
202 if (perUserDefaultTransactionIsolation != null) {
203 value = (Integer) perUserDefaultTransactionIsolation.get(username);
204 }
205 return value;
206 }
207
208
209
210
211
212 public void setPerUserDefaultTransactionIsolation(String username,
213 Integer value) {
214 assertInitializationAllowed();
215 if (perUserDefaultTransactionIsolation == null) {
216 perUserDefaultTransactionIsolation = new HashMap();
217 }
218 perUserDefaultTransactionIsolation.put(username, value);
219 }
220
221
222
223
224
225
226
227 public Integer getPerUserMaxActive(String username) {
228 Integer value = null;
229 if (perUserMaxActive != null) {
230 value = (Integer) perUserMaxActive.get(username);
231 }
232 return value;
233 }
234
235
236
237
238
239
240
241 public void setPerUserMaxActive(String username, Integer value) {
242 assertInitializationAllowed();
243 if (perUserMaxActive == null) {
244 perUserMaxActive = new HashMap();
245 }
246 perUserMaxActive.put(username, value);
247 }
248
249
250
251
252
253
254
255
256 public Integer getPerUserMaxIdle(String username) {
257 Integer value = null;
258 if (perUserMaxIdle != null) {
259 value = (Integer) perUserMaxIdle.get(username);
260 }
261 return value;
262 }
263
264
265
266
267
268
269
270 public void setPerUserMaxIdle(String username, Integer value) {
271 assertInitializationAllowed();
272 if (perUserMaxIdle == null) {
273 perUserMaxIdle = new HashMap();
274 }
275 perUserMaxIdle.put(username, value);
276 }
277
278
279
280
281
282
283
284
285
286 public Integer getPerUserMaxWait(String username) {
287 Integer value = null;
288 if (perUserMaxWait != null) {
289 value = (Integer) perUserMaxWait.get(username);
290 }
291 return value;
292 }
293
294
295
296
297
298
299
300
301
302 public void setPerUserMaxWait(String username, Integer value) {
303 assertInitializationAllowed();
304 if (perUserMaxWait == null) {
305 perUserMaxWait = new HashMap();
306 }
307 perUserMaxWait.put(username, value);
308 }
309
310
311
312
313
314 public Boolean getPerUserDefaultReadOnly(String username) {
315 Boolean value = null;
316 if (perUserDefaultReadOnly != null) {
317 value = (Boolean) perUserDefaultReadOnly.get(username);
318 }
319 return value;
320 }
321
322
323
324
325
326 public void setPerUserDefaultReadOnly(String username, Boolean value) {
327 assertInitializationAllowed();
328 if (perUserDefaultReadOnly == null) {
329 perUserDefaultReadOnly = new HashMap();
330 }
331 perUserDefaultReadOnly.put(username, value);
332 }
333
334
335
336
337
338
339
340 public int getNumActive() {
341 return getNumActive(null, null);
342 }
343
344
345
346
347 public int getNumActive(String username, String password) {
348 ObjectPool pool = getPool(getPoolKey(username,password));
349 return (pool == null) ? 0 : pool.getNumActive();
350 }
351
352
353
354
355 public int getNumIdle() {
356 return getNumIdle(null, null);
357 }
358
359
360
361
362 public int getNumIdle(String username, String password) {
363 ObjectPool pool = getPool(getPoolKey(username,password));
364 return (pool == null) ? 0 : pool.getNumIdle();
365 }
366
367
368
369
370
371 protected PooledConnectionAndInfo
372 getPooledConnectionAndInfo(String username, String password)
373 throws SQLException {
374
375 final PoolKey key = getPoolKey(username,password);
376 ObjectPool pool;
377 PooledConnectionManager manager;
378 synchronized(this) {
379 manager = (PooledConnectionManager) managers.get(key);
380 if (manager == null) {
381 try {
382 registerPool(username, password);
383 manager = (PooledConnectionManager) managers.get(key);
384 } catch (NamingException e) {
385 throw new SQLNestedException("RegisterPool failed", e);
386 }
387 }
388 pool = ((CPDSConnectionFactory) manager).getPool();
389 }
390
391 PooledConnectionAndInfo info = null;
392 try {
393 info = (PooledConnectionAndInfo) pool.borrowObject();
394 }
395 catch (NoSuchElementException ex) {
396 throw new SQLNestedException(
397 "Could not retrieve connection info from pool", ex);
398 }
399 catch (Exception e) {
400
401 try {
402 testCPDS(username, password);
403 } catch (Exception ex) {
404 throw (SQLException) new SQLException(
405 "Could not retrieve connection info from pool").initCause(ex);
406 }
407
408 manager.closePool(username);
409 synchronized (this) {
410 managers.remove(key);
411 }
412 try {
413 registerPool(username, password);
414 pool = getPool(key);
415 } catch (NamingException ne) {
416 throw new SQLNestedException("RegisterPool failed", ne);
417 }
418 try {
419 info = (PooledConnectionAndInfo)((ObjectPool) pool).borrowObject();
420 } catch (Exception ex) {
421 throw (SQLException) new SQLException(
422 "Could not retrieve connection info from pool").initCause(ex);
423 }
424 }
425 return info;
426 }
427
428 protected void setupDefaults(Connection con, String username)
429 throws SQLException {
430 boolean defaultAutoCommit = isDefaultAutoCommit();
431 if (username != null) {
432 Boolean userMax = getPerUserDefaultAutoCommit(username);
433 if (userMax != null) {
434 defaultAutoCommit = userMax.booleanValue();
435 }
436 }
437
438 boolean defaultReadOnly = isDefaultReadOnly();
439 if (username != null) {
440 Boolean userMax = getPerUserDefaultReadOnly(username);
441 if (userMax != null) {
442 defaultReadOnly = userMax.booleanValue();
443 }
444 }
445
446 int defaultTransactionIsolation = getDefaultTransactionIsolation();
447 if (username != null) {
448 Integer userMax = getPerUserDefaultTransactionIsolation(username);
449 if (userMax != null) {
450 defaultTransactionIsolation = userMax.intValue();
451 }
452 }
453
454 if (con.getAutoCommit() != defaultAutoCommit) {
455 con.setAutoCommit(defaultAutoCommit);
456 }
457
458 if (defaultTransactionIsolation != UNKNOWN_TRANSACTIONISOLATION) {
459 con.setTransactionIsolation(defaultTransactionIsolation);
460 }
461
462 if (con.isReadOnly() != defaultReadOnly) {
463 con.setReadOnly(defaultReadOnly);
464 }
465 }
466
467 protected PooledConnectionManager getConnectionManager(UserPassKey upkey) {
468 return (PooledConnectionManager) managers.get(getPoolKey(
469 upkey.getUsername(), upkey.getPassword()));
470 }
471
472
473
474
475
476
477 public Reference getReference() throws NamingException {
478 Reference ref = new Reference(getClass().getName(),
479 PerUserPoolDataSourceFactory.class.getName(), null);
480 ref.add(new StringRefAddr("instanceKey", instanceKey));
481 return ref;
482 }
483
484 private PoolKey getPoolKey(String username, String password) {
485 return new PoolKey(getDataSourceName(), username);
486 }
487
488 private synchronized void registerPool(
489 String username, String password)
490 throws javax.naming.NamingException, SQLException {
491
492 ConnectionPoolDataSource cpds = testCPDS(username, password);
493
494 Integer userMax = getPerUserMaxActive(username);
495 int maxActive = (userMax == null) ?
496 getDefaultMaxActive() : userMax.intValue();
497 userMax = getPerUserMaxIdle(username);
498 int maxIdle = (userMax == null) ?
499 getDefaultMaxIdle() : userMax.intValue();
500 userMax = getPerUserMaxWait(username);
501 int maxWait = (userMax == null) ?
502 getDefaultMaxWait() : userMax.intValue();
503
504
505 GenericObjectPool pool = new GenericObjectPool(null);
506 pool.setMaxActive(maxActive);
507 pool.setMaxIdle(maxIdle);
508 pool.setMaxWait(maxWait);
509 pool.setWhenExhaustedAction(whenExhaustedAction(maxActive, maxWait));
510 pool.setTestOnBorrow(getTestOnBorrow());
511 pool.setTestOnReturn(getTestOnReturn());
512 pool.setTimeBetweenEvictionRunsMillis(
513 getTimeBetweenEvictionRunsMillis());
514 pool.setNumTestsPerEvictionRun(getNumTestsPerEvictionRun());
515 pool.setMinEvictableIdleTimeMillis(getMinEvictableIdleTimeMillis());
516 pool.setTestWhileIdle(getTestWhileIdle());
517
518
519
520
521 CPDSConnectionFactory factory = new CPDSConnectionFactory(cpds, pool, getValidationQuery(),
522 isRollbackAfterValidation(), username, password);
523
524 Object old = managers.put(getPoolKey(username,password), factory);
525 if (old != null) {
526 throw new IllegalStateException("Pool already contains an entry for this user/password: "+username);
527 }
528 }
529
530
531
532
533
534
535
536
537 private void readObject(ObjectInputStream in)
538 throws IOException, ClassNotFoundException {
539 try
540 {
541 in.defaultReadObject();
542 PerUserPoolDataSource oldDS = (PerUserPoolDataSource)
543 new PerUserPoolDataSourceFactory()
544 .getObjectInstance(getReference(), null, null, null);
545 this.managers = oldDS.managers;
546 }
547 catch (NamingException e)
548 {
549 throw new IOException("NamingException: " + e);
550 }
551 }
552
553
554
555
556
557
558
559
560 private GenericObjectPool getPool(PoolKey key) {
561 CPDSConnectionFactory mgr = (CPDSConnectionFactory) managers.get(key);
562 return mgr == null ? null : (GenericObjectPool) mgr.getPool();
563 }
564 }