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