001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.commons.dbcp2.datasources; 018 019import java.io.IOException; 020import java.io.ObjectInputStream; 021import java.sql.Connection; 022import java.sql.SQLException; 023import java.util.HashMap; 024import java.util.Map; 025import java.util.NoSuchElementException; 026 027import javax.naming.NamingException; 028import javax.naming.Reference; 029import javax.naming.StringRefAddr; 030import javax.sql.ConnectionPoolDataSource; 031 032import org.apache.commons.dbcp2.SwallowedExceptionLogger; 033import org.apache.commons.logging.Log; 034import org.apache.commons.logging.LogFactory; 035import org.apache.commons.pool2.ObjectPool; 036import org.apache.commons.pool2.impl.GenericObjectPool; 037 038/** 039 * <p>A pooling <code>DataSource</code> appropriate for deployment within 040 * J2EE environment. There are many configuration options, most of which are 041 * defined in the parent class. This datasource uses individual pools per 042 * user, and some properties can be set specifically for a given user, if the 043 * deployment environment can support initialization of mapped properties. 044 * So for example, a pool of admin or write-access Connections can be 045 * guaranteed a certain number of connections, separate from a maximum 046 * set for users with read-only connections.</p> 047 * 048 * <p>User passwords can be changed without re-initializing the datasource. 049 * When a <code>getConnection(username, password)</code> request is processed 050 * with a password that is different from those used to create connections in 051 * the pool associated with <code>username</code>, an attempt is made to create 052 * a new connection using the supplied password and if this succeeds, the 053 * existing pool is cleared and a new pool is created for connections using the 054 * new password.</p> 055 * 056 * @author John D. McNally 057 * @version $Revision: 1572242 $ $Date: 2014-02-26 20:34:39 +0000 (Wed, 26 Feb 2014) $ 058 * @since 2.0 059 */ 060public class PerUserPoolDataSource extends InstanceKeyDataSource { 061 062 private static final long serialVersionUID = 7872747993848065028L; 063 064 private static final Log log = 065 LogFactory.getLog(PerUserPoolDataSource.class); 066 067 // Per user pool properties 068 private Map<String,Boolean> perUserBlockWhenExhausted = null; 069 private Map<String,String> perUserEvictionPolicyClassName = null; 070 private Map<String,Boolean> perUserLifo = null; 071 private Map<String,Integer> perUserMaxIdle = null; 072 private Map<String,Integer> perUserMaxTotal = null; 073 private Map<String,Long> perUserMaxWaitMillis = null; 074 private Map<String,Long> perUserMinEvictableIdleTimeMillis = null; 075 private Map<String,Integer> perUserMinIdle = null; 076 private Map<String,Integer> perUserNumTestsPerEvictionRun = null; 077 private Map<String,Long> perUserSoftMinEvictableIdleTimeMillis = null; 078 private Map<String,Boolean> perUserTestOnCreate = null; 079 private Map<String,Boolean> perUserTestOnBorrow = null; 080 private Map<String,Boolean> perUserTestOnReturn = null; 081 private Map<String,Boolean> perUserTestWhileIdle = null; 082 private Map<String,Long> perUserTimeBetweenEvictionRunsMillis = null; 083 084 // Per user connection properties 085 private Map<String,Boolean> perUserDefaultAutoCommit = null; 086 private Map<String,Integer> perUserDefaultTransactionIsolation = null; 087 private Map<String,Boolean> perUserDefaultReadOnly = null; 088 089 /** 090 * Map to keep track of Pools for a given user 091 */ 092 private transient Map<PoolKey, PooledConnectionManager> managers = 093 new HashMap<>(); 094 095 /** 096 * Default no-arg constructor for Serialization 097 */ 098 public PerUserPoolDataSource() { 099 } 100 101 /** 102 * Close pool(s) being maintained by this datasource. 103 */ 104 @Override 105 public void close() { 106 for (PooledConnectionManager manager : managers.values()) { 107 try { 108 ((CPDSConnectionFactory) manager).getPool().close(); 109 } catch (Exception closePoolException) { 110 //ignore and try to close others. 111 } 112 } 113 InstanceKeyDataSourceFactory.removeInstance(getInstanceKey()); 114 } 115 116 // ------------------------------------------------------------------- 117 // Properties 118 119 /** 120 * Gets the user specific value for 121 * {@link GenericObjectPool#getBlockWhenExhausted()} for the 122 * specified user's pool or the default if no user specific value is defined. 123 */ 124 public boolean getPerUserBlockWhenExhausted(String key) { 125 Boolean value = null; 126 if (perUserBlockWhenExhausted != null) { 127 value = perUserBlockWhenExhausted.get(key); 128 } 129 if (value == null) { 130 return getDefaultBlockWhenExhausted(); 131 } 132 return value.booleanValue(); 133 } 134 135 /** 136 * Sets a user specific value for 137 * {@link GenericObjectPool#getBlockWhenExhausted()} for the specified 138 * user's pool. 139 */ 140 public void setPerUserBlockWhenExhausted(String username, 141 Boolean value) { 142 assertInitializationAllowed(); 143 if (perUserBlockWhenExhausted == null) { 144 perUserBlockWhenExhausted = new HashMap<>(); 145 } 146 perUserBlockWhenExhausted.put(username, value); 147 } 148 149 void setPerUserBlockWhenExhausted( 150 Map<String,Boolean> userDefaultBlockWhenExhausted) { 151 assertInitializationAllowed(); 152 if (perUserBlockWhenExhausted == null) { 153 perUserBlockWhenExhausted = new HashMap<>(); 154 } else { 155 perUserBlockWhenExhausted.clear(); 156 } 157 perUserBlockWhenExhausted.putAll(userDefaultBlockWhenExhausted); 158 } 159 160 161 /** 162 * Gets the user specific value for 163 * {@link GenericObjectPool#getEvictionPolicyClassName()} for the 164 * specified user's pool or the default if no user specific value is defined. 165 */ 166 public String getPerUserEvictionPolicyClassName(String key) { 167 String value = null; 168 if (perUserEvictionPolicyClassName != null) { 169 value = perUserEvictionPolicyClassName.get(key); 170 } 171 if (value == null) { 172 return getDefaultEvictionPolicyClassName(); 173 } 174 return value; 175 } 176 177 /** 178 * Sets a user specific value for 179 * {@link GenericObjectPool#getEvictionPolicyClassName()} for the specified 180 * user's pool. 181 */ 182 public void setPerUserEvictionPolicyClassName(String username, 183 String value) { 184 assertInitializationAllowed(); 185 if (perUserEvictionPolicyClassName == null) { 186 perUserEvictionPolicyClassName = new HashMap<>(); 187 } 188 perUserEvictionPolicyClassName.put(username, value); 189 } 190 191 void setPerUserEvictionPolicyClassName( 192 Map<String,String> userDefaultEvictionPolicyClassName) { 193 assertInitializationAllowed(); 194 if (perUserEvictionPolicyClassName == null) { 195 perUserEvictionPolicyClassName = new HashMap<>(); 196 } else { 197 perUserEvictionPolicyClassName.clear(); 198 } 199 perUserEvictionPolicyClassName.putAll(userDefaultEvictionPolicyClassName); 200 } 201 202 203 /** 204 * Gets the user specific value for {@link GenericObjectPool#getLifo()} for 205 * the specified user's pool or the default if no user specific value is 206 * defined. 207 */ 208 public boolean getPerUserLifo(String key) { 209 Boolean value = null; 210 if (perUserLifo != null) { 211 value = perUserLifo.get(key); 212 } 213 if (value == null) { 214 return getDefaultLifo(); 215 } 216 return value.booleanValue(); 217 } 218 219 /** 220 * Sets a user specific value for 221 * {@link GenericObjectPool#getLifo()} for the specified 222 * user's pool. 223 */ 224 public void setPerUserLifo(String username, Boolean value) { 225 assertInitializationAllowed(); 226 if (perUserLifo == null) { 227 perUserLifo = new HashMap<>(); 228 } 229 perUserLifo.put(username, value); 230 } 231 232 void setPerUserLifo(Map<String,Boolean> userDefaultLifo) { 233 assertInitializationAllowed(); 234 if (perUserLifo == null) { 235 perUserLifo = new HashMap<>(); 236 } else { 237 perUserLifo.clear(); 238 } 239 perUserLifo.putAll(userDefaultLifo); 240 } 241 242 243 /** 244 * Gets the user specific value for 245 * {@link GenericObjectPool#getMaxIdle()} for the 246 * specified user's pool or the default if no user specific value is defined. 247 */ 248 public int getPerUserMaxIdle(String key) { 249 Integer value = null; 250 if (perUserMaxIdle != null) { 251 value = perUserMaxIdle.get(key); 252 } 253 if (value == null) { 254 return getDefaultMaxIdle(); 255 } 256 return value.intValue(); 257 } 258 259 /** 260 * Sets a user specific value for 261 * {@link GenericObjectPool#getMaxIdle()} for the specified 262 * user's pool. 263 */ 264 public void setPerUserMaxIdle(String username, Integer value) { 265 assertInitializationAllowed(); 266 if (perUserMaxIdle == null) { 267 perUserMaxIdle = new HashMap<>(); 268 } 269 perUserMaxIdle.put(username, value); 270 } 271 272 void setPerUserMaxIdle(Map<String,Integer> userDefaultMaxIdle) { 273 assertInitializationAllowed(); 274 if (perUserMaxIdle == null) { 275 perUserMaxIdle = new HashMap<>(); 276 } else { 277 perUserMaxIdle.clear(); 278 } 279 perUserMaxIdle.putAll(userDefaultMaxIdle); 280 } 281 282 283 /** 284 * Gets the user specific value for 285 * {@link GenericObjectPool#getMaxTotal()} for the 286 * specified user's pool or the default if no user specific value is defined. 287 */ 288 public int getPerUserMaxTotal(String key) { 289 Integer value = null; 290 if (perUserMaxTotal != null) { 291 value = perUserMaxTotal.get(key); 292 } 293 if (value == null) { 294 return getDefaultMaxTotal(); 295 } 296 return value.intValue(); 297 } 298 299 /** 300 * Sets a user specific value for 301 * {@link GenericObjectPool#getMaxTotal()} for the specified 302 * user's pool. 303 */ 304 public void setPerUserMaxTotal(String username, Integer value) { 305 assertInitializationAllowed(); 306 if (perUserMaxTotal == null) { 307 perUserMaxTotal = new HashMap<>(); 308 } 309 perUserMaxTotal.put(username, value); 310 } 311 312 void setPerUserMaxTotal(Map<String,Integer> userDefaultMaxTotal) { 313 assertInitializationAllowed(); 314 if (perUserMaxTotal == null) { 315 perUserMaxTotal = new HashMap<>(); 316 } else { 317 perUserMaxTotal.clear(); 318 } 319 perUserMaxTotal.putAll(userDefaultMaxTotal); 320 } 321 322 323 /** 324 * Gets the user specific value for 325 * {@link GenericObjectPool#getMaxWaitMillis()} for the 326 * specified user's pool or the default if no user specific value is defined. 327 */ 328 public long getPerUserMaxWaitMillis(String key) { 329 Long value = null; 330 if (perUserMaxWaitMillis != null) { 331 value = perUserMaxWaitMillis.get(key); 332 } 333 if (value == null) { 334 return getDefaultMaxWaitMillis(); 335 } 336 return value.longValue(); 337 } 338 339 /** 340 * Sets a user specific value for 341 * {@link GenericObjectPool#getMaxWaitMillis()} for the specified 342 * user's pool. 343 */ 344 public void setPerUserMaxWaitMillis(String username, Long value) { 345 assertInitializationAllowed(); 346 if (perUserMaxWaitMillis == null) { 347 perUserMaxWaitMillis = new HashMap<>(); 348 } 349 perUserMaxWaitMillis.put(username, value); 350 } 351 352 void setPerUserMaxWaitMillis( 353 Map<String,Long> userDefaultMaxWaitMillis) { 354 assertInitializationAllowed(); 355 if (perUserMaxWaitMillis == null) { 356 perUserMaxWaitMillis = new HashMap<>(); 357 } else { 358 perUserMaxWaitMillis.clear(); 359 } 360 perUserMaxWaitMillis.putAll(userDefaultMaxWaitMillis); 361 } 362 363 364 /** 365 * Gets the user specific value for 366 * {@link GenericObjectPool#getMinEvictableIdleTimeMillis()} for the 367 * specified user's pool or the default if no user specific value is defined. 368 */ 369 public long getPerUserMinEvictableIdleTimeMillis(String key) { 370 Long value = null; 371 if (perUserMinEvictableIdleTimeMillis != null) { 372 value = perUserMinEvictableIdleTimeMillis.get(key); 373 } 374 if (value == null) { 375 return getDefaultMinEvictableIdleTimeMillis(); 376 } 377 return value.longValue(); 378 } 379 380 /** 381 * Sets a user specific value for 382 * {@link GenericObjectPool#getMinEvictableIdleTimeMillis()} for the 383 * specified user's pool. 384 */ 385 public void setPerUserMinEvictableIdleTimeMillis(String username, 386 Long value) { 387 assertInitializationAllowed(); 388 if (perUserMinEvictableIdleTimeMillis == null) { 389 perUserMinEvictableIdleTimeMillis = new HashMap<>(); 390 } 391 perUserMinEvictableIdleTimeMillis.put(username, value); 392 } 393 394 void setPerUserMinEvictableIdleTimeMillis( 395 Map<String,Long> userDefaultMinEvictableIdleTimeMillis) { 396 assertInitializationAllowed(); 397 if (perUserMinEvictableIdleTimeMillis == null) { 398 perUserMinEvictableIdleTimeMillis = new HashMap<>(); 399 } else { 400 perUserMinEvictableIdleTimeMillis.clear(); 401 } 402 perUserMinEvictableIdleTimeMillis.putAll( 403 userDefaultMinEvictableIdleTimeMillis); 404 } 405 406 407 /** 408 * Gets the user specific value for 409 * {@link GenericObjectPool#getMinIdle()} for the 410 * specified user's pool or the default if no user specific value is defined. 411 */ 412 public int getPerUserMinIdle(String key) { 413 Integer value = null; 414 if (perUserMinIdle != null) { 415 value = perUserMinIdle.get(key); 416 } 417 if (value == null) { 418 return getDefaultMinIdle(); 419 } 420 return value.intValue(); 421 } 422 423 /** 424 * Sets a user specific value for 425 * {@link GenericObjectPool#getMinIdle()} for the specified 426 * user's pool. 427 */ 428 public void setPerUserMinIdle(String username, Integer value) { 429 assertInitializationAllowed(); 430 if (perUserMinIdle == null) { 431 perUserMinIdle = new HashMap<>(); 432 } 433 perUserMinIdle.put(username, value); 434 } 435 436 void setPerUserMinIdle(Map<String,Integer> userDefaultMinIdle) { 437 assertInitializationAllowed(); 438 if (perUserMinIdle == null) { 439 perUserMinIdle = new HashMap<>(); 440 } else { 441 perUserMinIdle.clear(); 442 } 443 perUserMinIdle.putAll(userDefaultMinIdle); 444 } 445 446 447 /** 448 * Gets the user specific value for 449 * {@link GenericObjectPool#getNumTestsPerEvictionRun()} for the 450 * specified user's pool or the default if no user specific value is defined. 451 */ 452 public int getPerUserNumTestsPerEvictionRun(String key) { 453 Integer value = null; 454 if (perUserNumTestsPerEvictionRun != null) { 455 value = perUserNumTestsPerEvictionRun.get(key); 456 } 457 if (value == null) { 458 return getDefaultNumTestsPerEvictionRun(); 459 } 460 return value.intValue(); 461 } 462 463 /** 464 * Sets a user specific value for 465 * {@link GenericObjectPool#getNumTestsPerEvictionRun()} for the specified 466 * user's pool. 467 */ 468 public void setPerUserNumTestsPerEvictionRun(String username, 469 Integer value) { 470 assertInitializationAllowed(); 471 if (perUserNumTestsPerEvictionRun == null) { 472 perUserNumTestsPerEvictionRun = new HashMap<>(); 473 } 474 perUserNumTestsPerEvictionRun.put(username, value); 475 } 476 477 void setPerUserNumTestsPerEvictionRun( 478 Map<String,Integer> userDefaultNumTestsPerEvictionRun) { 479 assertInitializationAllowed(); 480 if (perUserNumTestsPerEvictionRun == null) { 481 perUserNumTestsPerEvictionRun = new HashMap<>(); 482 } else { 483 perUserNumTestsPerEvictionRun.clear(); 484 } 485 perUserNumTestsPerEvictionRun.putAll(userDefaultNumTestsPerEvictionRun); 486 } 487 488 489 /** 490 * Gets the user specific value for 491 * {@link GenericObjectPool#getSoftMinEvictableIdleTimeMillis()} for the 492 * specified user's pool or the default if no user specific value is defined. 493 */ 494 public long getPerUserSoftMinEvictableIdleTimeMillis(String key) { 495 Long value = null; 496 if (perUserSoftMinEvictableIdleTimeMillis != null) { 497 value = perUserSoftMinEvictableIdleTimeMillis.get(key); 498 } 499 if (value == null) { 500 return getDefaultSoftMinEvictableIdleTimeMillis(); 501 } 502 return value.longValue(); 503 } 504 505 /** 506 * Sets a user specific value for 507 * {@link GenericObjectPool#getSoftMinEvictableIdleTimeMillis()} for the 508 * specified user's pool. 509 */ 510 public void setPerUserSoftMinEvictableIdleTimeMillis(String username, 511 Long value) { 512 assertInitializationAllowed(); 513 if (perUserSoftMinEvictableIdleTimeMillis == null) { 514 perUserSoftMinEvictableIdleTimeMillis = new HashMap<>(); 515 } 516 perUserSoftMinEvictableIdleTimeMillis.put(username, value); 517 } 518 519 void setPerUserSoftMinEvictableIdleTimeMillis( 520 Map<String,Long> userDefaultSoftMinEvictableIdleTimeMillis) { 521 assertInitializationAllowed(); 522 if (perUserSoftMinEvictableIdleTimeMillis == null) { 523 perUserSoftMinEvictableIdleTimeMillis = new HashMap<>(); 524 } else { 525 perUserSoftMinEvictableIdleTimeMillis.clear(); 526 } 527 perUserSoftMinEvictableIdleTimeMillis.putAll(userDefaultSoftMinEvictableIdleTimeMillis); 528 } 529 530 531 /** 532 * Gets the user specific value for 533 * {@link GenericObjectPool#getTestOnCreate()} for the 534 * specified user's pool or the default if no user specific value is defined. 535 */ 536 public boolean getPerUserTestOnCreate(String key) { 537 Boolean value = null; 538 if (perUserTestOnCreate != null) { 539 value = perUserTestOnCreate.get(key); 540 } 541 if (value == null) { 542 return getDefaultTestOnCreate(); 543 } 544 return value.booleanValue(); 545 } 546 547 /** 548 * Sets a user specific value for 549 * {@link GenericObjectPool#getTestOnCreate()} for the specified 550 * user's pool. 551 */ 552 public void setPerUserTestOnCreate(String username, Boolean value) { 553 assertInitializationAllowed(); 554 if (perUserTestOnCreate == null) { 555 perUserTestOnCreate = new HashMap<>(); 556 } 557 perUserTestOnCreate.put(username, value); 558 } 559 560 void setPerUserTestOnCreate(Map<String,Boolean> userDefaultTestOnCreate) { 561 assertInitializationAllowed(); 562 if (perUserTestOnCreate == null) { 563 perUserTestOnCreate = new HashMap<>(); 564 } else { 565 perUserTestOnCreate.clear(); 566 } 567 perUserTestOnCreate.putAll(userDefaultTestOnCreate); 568 } 569 570 571 /** 572 * Gets the user specific value for 573 * {@link GenericObjectPool#getTestOnBorrow()} for the 574 * specified user's pool or the default if no user specific value is defined. 575 */ 576 public boolean getPerUserTestOnBorrow(String key) { 577 Boolean value = null; 578 if (perUserTestOnBorrow != null) { 579 value = perUserTestOnBorrow.get(key); 580 } 581 if (value == null) { 582 return getDefaultTestOnBorrow(); 583 } 584 return value.booleanValue(); 585 } 586 587 /** 588 * Sets a user specific value for 589 * {@link GenericObjectPool#getTestOnBorrow()} for the specified 590 * user's pool. 591 */ 592 public void setPerUserTestOnBorrow(String username, Boolean value) { 593 assertInitializationAllowed(); 594 if (perUserTestOnBorrow == null) { 595 perUserTestOnBorrow = new HashMap<>(); 596 } 597 perUserTestOnBorrow.put(username, value); 598 } 599 600 void setPerUserTestOnBorrow(Map<String,Boolean> userDefaultTestOnBorrow) { 601 assertInitializationAllowed(); 602 if (perUserTestOnBorrow == null) { 603 perUserTestOnBorrow = new HashMap<>(); 604 } else { 605 perUserTestOnBorrow.clear(); 606 } 607 perUserTestOnBorrow.putAll(userDefaultTestOnBorrow); 608 } 609 610 611 /** 612 * Gets the user specific value for 613 * {@link GenericObjectPool#getTestOnReturn()} for the 614 * specified user's pool or the default if no user specific value is defined. 615 */ 616 public boolean getPerUserTestOnReturn(String key) { 617 Boolean value = null; 618 if (perUserTestOnReturn != null) { 619 value = perUserTestOnReturn.get(key); 620 } 621 if (value == null) { 622 return getDefaultTestOnReturn(); 623 } 624 return value.booleanValue(); 625 } 626 627 /** 628 * Sets a user specific value for 629 * {@link GenericObjectPool#getTestOnReturn()} for the specified 630 * user's pool. 631 */ 632 public void setPerUserTestOnReturn(String username, Boolean value) { 633 assertInitializationAllowed(); 634 if (perUserTestOnReturn == null) { 635 perUserTestOnReturn = new HashMap<>(); 636 } 637 perUserTestOnReturn.put(username, value); 638 } 639 640 void setPerUserTestOnReturn( 641 Map<String,Boolean> userDefaultTestOnReturn) { 642 assertInitializationAllowed(); 643 if (perUserTestOnReturn == null) { 644 perUserTestOnReturn = new HashMap<>(); 645 } else { 646 perUserTestOnReturn.clear(); 647 } 648 perUserTestOnReturn.putAll(userDefaultTestOnReturn); 649 } 650 651 652 /** 653 * Gets the user specific value for 654 * {@link GenericObjectPool#getTestWhileIdle()} for the 655 * specified user's pool or the default if no user specific value is defined. 656 */ 657 public boolean getPerUserTestWhileIdle(String key) { 658 Boolean value = null; 659 if (perUserTestWhileIdle != null) { 660 value = perUserTestWhileIdle.get(key); 661 } 662 if (value == null) { 663 return getDefaultTestWhileIdle(); 664 } 665 return value.booleanValue(); 666 } 667 668 /** 669 * Sets a user specific value for 670 * {@link GenericObjectPool#getTestWhileIdle()} for the specified 671 * user's pool. 672 */ 673 public void setPerUserTestWhileIdle(String username, Boolean value) { 674 assertInitializationAllowed(); 675 if (perUserTestWhileIdle == null) { 676 perUserTestWhileIdle = new HashMap<>(); 677 } 678 perUserTestWhileIdle.put(username, value); 679 } 680 681 void setPerUserTestWhileIdle( 682 Map<String,Boolean> userDefaultTestWhileIdle) { 683 assertInitializationAllowed(); 684 if (perUserTestWhileIdle == null) { 685 perUserTestWhileIdle = new HashMap<>(); 686 } else { 687 perUserTestWhileIdle.clear(); 688 } 689 perUserTestWhileIdle.putAll(userDefaultTestWhileIdle); 690 } 691 692 693 /** 694 * Gets the user specific value for 695 * {@link GenericObjectPool#getTimeBetweenEvictionRunsMillis()} for the 696 * specified user's pool or the default if no user specific value is defined. 697 */ 698 public long getPerUserTimeBetweenEvictionRunsMillis(String key) { 699 Long value = null; 700 if (perUserTimeBetweenEvictionRunsMillis != null) { 701 value = perUserTimeBetweenEvictionRunsMillis.get(key); 702 } 703 if (value == null) { 704 return getDefaultTimeBetweenEvictionRunsMillis(); 705 } 706 return value.longValue(); 707 } 708 709 /** 710 * Sets a user specific value for 711 * {@link GenericObjectPool#getTimeBetweenEvictionRunsMillis ()} for the specified 712 * user's pool. 713 */ 714 public void setPerUserTimeBetweenEvictionRunsMillis(String username, 715 Long value) { 716 assertInitializationAllowed(); 717 if (perUserTimeBetweenEvictionRunsMillis == null) { 718 perUserTimeBetweenEvictionRunsMillis = new HashMap<>(); 719 } 720 perUserTimeBetweenEvictionRunsMillis.put(username, value); 721 } 722 723 void setPerUserTimeBetweenEvictionRunsMillis( 724 Map<String,Long> userDefaultTimeBetweenEvictionRunsMillis ) { 725 assertInitializationAllowed(); 726 if (perUserTimeBetweenEvictionRunsMillis == null) { 727 perUserTimeBetweenEvictionRunsMillis = new HashMap<>(); 728 } else { 729 perUserTimeBetweenEvictionRunsMillis.clear(); 730 } 731 perUserTimeBetweenEvictionRunsMillis.putAll( 732 userDefaultTimeBetweenEvictionRunsMillis ); 733 } 734 735 736 /** 737 * Gets the user specific default value for 738 * {@link Connection#setAutoCommit(boolean)} for the specified user's pool. 739 */ 740 public Boolean getPerUserDefaultAutoCommit(String key) { 741 Boolean value = null; 742 if (perUserDefaultAutoCommit != null) { 743 value = perUserDefaultAutoCommit.get(key); 744 } 745 return value; 746 } 747 748 /** 749 * Sets a user specific default value for 750 * {@link Connection#setAutoCommit(boolean)} for the specified user's pool. 751 */ 752 public void setPerUserDefaultAutoCommit(String username, Boolean value) { 753 assertInitializationAllowed(); 754 if (perUserDefaultAutoCommit == null) { 755 perUserDefaultAutoCommit = new HashMap<>(); 756 } 757 perUserDefaultAutoCommit.put(username, value); 758 } 759 760 void setPerUserDefaultAutoCommit(Map<String,Boolean> userDefaultAutoCommit) { 761 assertInitializationAllowed(); 762 if (perUserDefaultAutoCommit == null) { 763 perUserDefaultAutoCommit = new HashMap<>(); 764 } else { 765 perUserDefaultAutoCommit.clear(); 766 } 767 perUserDefaultAutoCommit.putAll(userDefaultAutoCommit); 768 } 769 770 771 /** 772 * Gets the user specific default value for 773 * {@link Connection#setReadOnly(boolean)} for the specified user's pool. 774 */ 775 public Boolean getPerUserDefaultReadOnly(String key) { 776 Boolean value = null; 777 if (perUserDefaultReadOnly != null) { 778 value = perUserDefaultReadOnly.get(key); 779 } 780 return value; 781 } 782 783 /** 784 * Sets a user specific default value for 785 * {@link Connection#setReadOnly(boolean)} for the specified user's pool. 786 */ 787 public void setPerUserDefaultReadOnly(String username, Boolean value) { 788 assertInitializationAllowed(); 789 if (perUserDefaultReadOnly == null) { 790 perUserDefaultReadOnly = new HashMap<>(); 791 } 792 perUserDefaultReadOnly.put(username, value); 793 } 794 795 void setPerUserDefaultReadOnly(Map<String,Boolean> userDefaultReadOnly) { 796 assertInitializationAllowed(); 797 if (perUserDefaultReadOnly == null) { 798 perUserDefaultReadOnly = new HashMap<>(); 799 } else { 800 perUserDefaultReadOnly.clear(); 801 } 802 perUserDefaultReadOnly.putAll(userDefaultReadOnly); 803 } 804 805 806 /** 807 * Gets the user specific default value for 808 * {@link Connection#setTransactionIsolation(int)} for the specified user's pool. 809 */ 810 public Integer getPerUserDefaultTransactionIsolation(String key) { 811 Integer value = null; 812 if (perUserDefaultTransactionIsolation != null) { 813 value = perUserDefaultTransactionIsolation.get(key); 814 } 815 return value; 816 } 817 818 /** 819 * Sets a user specific default value for 820 * {@link Connection#setTransactionIsolation(int)} for the specified user's pool. 821 */ 822 public void setPerUserDefaultTransactionIsolation(String username, 823 Integer value) { 824 assertInitializationAllowed(); 825 if (perUserDefaultTransactionIsolation == null) { 826 perUserDefaultTransactionIsolation = new HashMap<>(); 827 } 828 perUserDefaultTransactionIsolation.put(username, value); 829 } 830 831 void setPerUserDefaultTransactionIsolation( 832 Map<String,Integer> userDefaultTransactionIsolation) { 833 assertInitializationAllowed(); 834 if (perUserDefaultTransactionIsolation == null) { 835 perUserDefaultTransactionIsolation = new HashMap<>(); 836 } else { 837 perUserDefaultTransactionIsolation.clear(); 838 } 839 perUserDefaultTransactionIsolation.putAll(userDefaultTransactionIsolation); 840 } 841 842 843 // ---------------------------------------------------------------------- 844 // Instrumentation Methods 845 846 /** 847 * Get the number of active connections in the default pool. 848 */ 849 public int getNumActive() { 850 return getNumActive(null); 851 } 852 853 /** 854 * Get the number of active connections in the pool for a given user. 855 */ 856 public int getNumActive(String username) { 857 ObjectPool<PooledConnectionAndInfo> pool = 858 getPool(getPoolKey(username)); 859 return pool == null ? 0 : pool.getNumActive(); 860 } 861 862 /** 863 * Get the number of idle connections in the default pool. 864 */ 865 public int getNumIdle() { 866 return getNumIdle(null); 867 } 868 869 /** 870 * Get the number of idle connections in the pool for a given user. 871 */ 872 public int getNumIdle(String username) { 873 ObjectPool<PooledConnectionAndInfo> pool = 874 getPool(getPoolKey(username)); 875 return pool == null ? 0 : pool.getNumIdle(); 876 } 877 878 879 // ---------------------------------------------------------------------- 880 // Inherited abstract methods 881 882 @Override 883 protected PooledConnectionAndInfo 884 getPooledConnectionAndInfo(String username, String password) 885 throws SQLException { 886 887 final PoolKey key = getPoolKey(username); 888 ObjectPool<PooledConnectionAndInfo> pool; 889 PooledConnectionManager manager; 890 synchronized(this) { 891 manager = managers.get(key); 892 if (manager == null) { 893 try { 894 registerPool(username, password); 895 manager = managers.get(key); 896 } catch (NamingException e) { 897 throw new SQLException("RegisterPool failed", e); 898 } 899 } 900 pool = ((CPDSConnectionFactory) manager).getPool(); 901 } 902 903 PooledConnectionAndInfo info = null; 904 try { 905 info = pool.borrowObject(); 906 } 907 catch (NoSuchElementException ex) { 908 throw new SQLException( 909 "Could not retrieve connection info from pool", ex); 910 } 911 catch (Exception e) { 912 // See if failure is due to CPDSConnectionFactory authentication failure 913 try { 914 testCPDS(username, password); 915 } catch (Exception ex) { 916 throw new SQLException( 917 "Could not retrieve connection info from pool", ex); 918 } 919 // New password works, so kill the old pool, create a new one, and borrow 920 manager.closePool(username); 921 synchronized (this) { 922 managers.remove(key); 923 } 924 try { 925 registerPool(username, password); 926 pool = getPool(key); 927 } catch (NamingException ne) { 928 throw new SQLException("RegisterPool failed", ne); 929 } 930 try { 931 info = pool.borrowObject(); 932 } catch (Exception ex) { 933 throw new SQLException( 934 "Could not retrieve connection info from pool", ex); 935 } 936 } 937 return info; 938 } 939 940 @Override 941 protected void setupDefaults(Connection con, String username) 942 throws SQLException { 943 Boolean defaultAutoCommit = isDefaultAutoCommit(); 944 if (username != null) { 945 Boolean userMax = getPerUserDefaultAutoCommit(username); 946 if (userMax != null) { 947 defaultAutoCommit = userMax; 948 } 949 } 950 951 Boolean defaultReadOnly = isDefaultReadOnly(); 952 if (username != null) { 953 Boolean userMax = getPerUserDefaultReadOnly(username); 954 if (userMax != null) { 955 defaultReadOnly = userMax; 956 } 957 } 958 959 int defaultTransactionIsolation = getDefaultTransactionIsolation(); 960 if (username != null) { 961 Integer userMax = getPerUserDefaultTransactionIsolation(username); 962 if (userMax != null) { 963 defaultTransactionIsolation = userMax.intValue(); 964 } 965 } 966 967 if (defaultAutoCommit != null && 968 con.getAutoCommit() != defaultAutoCommit.booleanValue()) { 969 con.setAutoCommit(defaultAutoCommit.booleanValue()); 970 } 971 972 if (defaultTransactionIsolation != UNKNOWN_TRANSACTIONISOLATION) { 973 con.setTransactionIsolation(defaultTransactionIsolation); 974 } 975 976 if (defaultReadOnly != null && 977 con.isReadOnly() != defaultReadOnly.booleanValue()) { 978 con.setReadOnly(defaultReadOnly.booleanValue()); 979 } 980 } 981 982 @Override 983 protected PooledConnectionManager getConnectionManager(UserPassKey upkey) { 984 return managers.get(getPoolKey(upkey.getUsername())); 985 } 986 987 /** 988 * Returns a <code>PerUserPoolDataSource</code> {@link Reference}. 989 */ 990 @Override 991 public Reference getReference() throws NamingException { 992 Reference ref = new Reference(getClass().getName(), 993 PerUserPoolDataSourceFactory.class.getName(), null); 994 ref.add(new StringRefAddr("instanceKey", getInstanceKey())); 995 return ref; 996 } 997 998 /** 999 * Create a pool key from the provided parameters. 1000 * 1001 * @param username User name 1002 * @return The pool key 1003 */ 1004 private PoolKey getPoolKey(String username) { 1005 return new PoolKey(getDataSourceName(), username); 1006 } 1007 1008 private synchronized void registerPool(String username, String password) 1009 throws NamingException, SQLException { 1010 1011 ConnectionPoolDataSource cpds = testCPDS(username, password); 1012 1013 // Set up the factory we will use (passing the pool associates 1014 // the factory with the pool, so we do not have to do so 1015 // explicitly) 1016 CPDSConnectionFactory factory = new CPDSConnectionFactory(cpds, 1017 getValidationQuery(), getValidationQueryTimeout(), 1018 isRollbackAfterValidation(), username, password); 1019 factory.setMaxConnLifetimeMillis(getMaxConnLifetimeMillis()); 1020 1021 // Create an object pool to contain our PooledConnections 1022 GenericObjectPool<PooledConnectionAndInfo> pool = 1023 new GenericObjectPool<>(factory); 1024 factory.setPool(pool); 1025 pool.setBlockWhenExhausted(getPerUserBlockWhenExhausted(username)); 1026 pool.setEvictionPolicyClassName( 1027 getPerUserEvictionPolicyClassName(username)); 1028 pool.setLifo(getPerUserLifo(username)); 1029 pool.setMaxIdle(getPerUserMaxIdle(username)); 1030 pool.setMaxTotal(getPerUserMaxTotal(username)); 1031 pool.setMaxWaitMillis(getPerUserMaxWaitMillis(username)); 1032 pool.setMinEvictableIdleTimeMillis( 1033 getPerUserMinEvictableIdleTimeMillis(username)); 1034 pool.setMinIdle(getPerUserMinIdle(username)); 1035 pool.setNumTestsPerEvictionRun( 1036 getPerUserNumTestsPerEvictionRun(username)); 1037 pool.setSoftMinEvictableIdleTimeMillis( 1038 getPerUserSoftMinEvictableIdleTimeMillis(username)); 1039 pool.setTestOnCreate(getPerUserTestOnCreate(username)); 1040 pool.setTestOnBorrow(getPerUserTestOnBorrow(username)); 1041 pool.setTestOnReturn(getPerUserTestOnReturn(username)); 1042 pool.setTestWhileIdle(getPerUserTestWhileIdle(username)); 1043 pool.setTimeBetweenEvictionRunsMillis( 1044 getPerUserTimeBetweenEvictionRunsMillis(username)); 1045 1046 pool.setSwallowedExceptionListener(new SwallowedExceptionLogger(log)); 1047 1048 Object old = managers.put(getPoolKey(username), factory); 1049 if (old != null) { 1050 throw new IllegalStateException("Pool already contains an entry for this user/password: " + username); 1051 } 1052 } 1053 1054 /** 1055 * Supports Serialization interface. 1056 * 1057 * @param in a <code>java.io.ObjectInputStream</code> value 1058 * @exception IOException if an error occurs 1059 * @exception ClassNotFoundException if an error occurs 1060 */ 1061 private void readObject(ObjectInputStream in) 1062 throws IOException, ClassNotFoundException { 1063 try 1064 { 1065 in.defaultReadObject(); 1066 PerUserPoolDataSource oldDS = (PerUserPoolDataSource) 1067 new PerUserPoolDataSourceFactory() 1068 .getObjectInstance(getReference(), null, null, null); 1069 this.managers = oldDS.managers; 1070 } 1071 catch (NamingException e) 1072 { 1073 throw new IOException("NamingException: " + e); 1074 } 1075 } 1076 1077 /** 1078 * Returns the object pool associated with the given PoolKey. 1079 * 1080 * @param key PoolKey identifying the pool 1081 * @return the GenericObjectPool pooling connections for the username and datasource 1082 * specified by the PoolKey 1083 */ 1084 private ObjectPool<PooledConnectionAndInfo> getPool(PoolKey key) { 1085 CPDSConnectionFactory mgr = (CPDSConnectionFactory) managers.get(key); 1086 return mgr == null ? null : mgr.getPool(); 1087 } 1088}