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 */ 017 018 package org.apache.commons.pool.impl; 019 020 import java.util.HashMap; 021 import java.util.Iterator; 022 import java.util.Map; 023 import java.util.NoSuchElementException; 024 import java.util.Stack; 025 026 import org.apache.commons.pool.BaseKeyedObjectPool; 027 import org.apache.commons.pool.KeyedObjectPool; 028 import org.apache.commons.pool.KeyedPoolableObjectFactory; 029 import org.apache.commons.pool.PoolUtils; 030 031 /** 032 * A simple, <code>Stack</code>-based <code>KeyedObjectPool</code> implementation. 033 * <p> 034 * Given a {@link KeyedPoolableObjectFactory}, this class will maintain 035 * a simple pool of instances. A finite number of "sleeping" 036 * or inactive instances is enforced, but when the pool is 037 * empty, new instances are created to support the new load. 038 * Hence this class places no limit on the number of "active" 039 * instances created by the pool, but is quite useful for 040 * re-using <code>Object</code>s without introducing 041 * artificial limits. 042 * </p> 043 * 044 * @param <K> the type of keys in this pool 045 * @param <V> the type of objects held in this pool 046 * 047 * @author Rodney Waldhoff 048 * @author Sandy McArthur 049 * @version $Revision: 1222710 $ $Date: 2011-12-23 10:58:12 -0500 (Fri, 23 Dec 2011) $ 050 * @see Stack 051 * @since Pool 1.0 052 */ 053 public class StackKeyedObjectPool<K, V> extends BaseKeyedObjectPool<K, V> implements KeyedObjectPool<K, V> { 054 /** 055 * Create a new pool using no factory. 056 * Clients must first set the {@link #setFactory factory} or 057 * may populate the pool using {@link #returnObject returnObject} 058 * before they can be {@link #borrowObject borrowed}. 059 * 060 * @see #StackKeyedObjectPool(KeyedPoolableObjectFactory) 061 * @see #setFactory(KeyedPoolableObjectFactory) 062 */ 063 public StackKeyedObjectPool() { 064 this(null,DEFAULT_MAX_SLEEPING,DEFAULT_INIT_SLEEPING_CAPACITY); 065 } 066 067 /** 068 * Create a new pool using no factory. 069 * Clients must first set the {@link #setFactory factory} or 070 * may populate the pool using {@link #returnObject returnObject} 071 * before they can be {@link #borrowObject borrowed}. 072 * 073 * @param max cap on the number of "sleeping" instances in the pool 074 * @see #StackKeyedObjectPool(KeyedPoolableObjectFactory, int) 075 * @see #setFactory(KeyedPoolableObjectFactory) 076 */ 077 public StackKeyedObjectPool(int max) { 078 this(null,max,DEFAULT_INIT_SLEEPING_CAPACITY); 079 } 080 081 /** 082 * Create a new pool using no factory. 083 * Clients must first set the {@link #setFactory factory} or 084 * may populate the pool using {@link #returnObject returnObject} 085 * before they can be {@link #borrowObject borrowed}. 086 * 087 * @param max cap on the number of "sleeping" instances in the pool 088 * @param init initial size of the pool (this specifies the size of the container, 089 * it does not cause the pool to be pre-populated.) 090 * @see #StackKeyedObjectPool(KeyedPoolableObjectFactory, int, int) 091 * @see #setFactory(KeyedPoolableObjectFactory) 092 */ 093 public StackKeyedObjectPool(int max, int init) { 094 this(null,max,init); 095 } 096 097 /** 098 * Create a new <code>SimpleKeyedObjectPool</code> using 099 * the specified <code>factory</code> to create new instances. 100 * 101 * @param factory the {@link KeyedPoolableObjectFactory} used to populate the pool 102 */ 103 public StackKeyedObjectPool(KeyedPoolableObjectFactory<K, V> factory) { 104 this(factory,DEFAULT_MAX_SLEEPING); 105 } 106 107 /** 108 * Create a new <code>SimpleKeyedObjectPool</code> using 109 * the specified <code>factory</code> to create new instances. 110 * capping the number of "sleeping" instances to <code>max</code> 111 * 112 * @param factory the {@link KeyedPoolableObjectFactory} used to populate the pool 113 * @param max cap on the number of "sleeping" instances in the pool 114 */ 115 public StackKeyedObjectPool(KeyedPoolableObjectFactory<K, V> factory, int max) { 116 this(factory,max,DEFAULT_INIT_SLEEPING_CAPACITY); 117 } 118 119 /** 120 * Create a new <code>SimpleKeyedObjectPool</code> using 121 * the specified <code>factory</code> to create new instances. 122 * capping the number of "sleeping" instances to <code>max</code>, 123 * and initially allocating a container capable of containing 124 * at least <code>init</code> instances. 125 * 126 * @param factory the {@link KeyedPoolableObjectFactory} used to populate the pool 127 * @param max cap on the number of "sleeping" instances in the pool 128 * @param init initial size of the pool (this specifies the size of the container, 129 * it does not cause the pool to be pre-populated.) 130 */ 131 public StackKeyedObjectPool(KeyedPoolableObjectFactory<K, V> factory, int max, int init) { 132 _factory = factory; 133 _maxSleeping = (max < 0 ? DEFAULT_MAX_SLEEPING : max); 134 _initSleepingCapacity = (init < 1 ? DEFAULT_INIT_SLEEPING_CAPACITY : init); 135 _pools = new HashMap<K, Stack<V>>(); 136 _activeCount = new HashMap<K, Integer>(); 137 } 138 139 /** 140 * Borrows an object with the given key. If there are no idle instances under the 141 * given key, a new one is created. 142 * 143 * @param key the pool key 144 * @return keyed poolable object instance 145 */ 146 @Override 147 public synchronized V borrowObject(K key) throws Exception { 148 assertOpen(); 149 Stack<V> stack = (_pools.get(key)); 150 if(null == stack) { 151 stack = new Stack<V>(); 152 stack.ensureCapacity( _initSleepingCapacity > _maxSleeping ? _maxSleeping : _initSleepingCapacity); 153 _pools.put(key,stack); 154 } 155 V obj = null; 156 do { 157 boolean newlyMade = false; 158 if (!stack.empty()) { 159 obj = stack.pop(); 160 _totIdle--; 161 } else { 162 if(null == _factory) { 163 throw new NoSuchElementException("pools without a factory cannot create new objects as needed."); 164 } else { 165 obj = _factory.makeObject(key); 166 newlyMade = true; 167 } 168 } 169 if (null != _factory && null != obj) { 170 try { 171 _factory.activateObject(key, obj); 172 if (!_factory.validateObject(key, obj)) { 173 throw new Exception("ValidateObject failed"); 174 } 175 } catch (Throwable t) { 176 PoolUtils.checkRethrow(t); 177 try { 178 _factory.destroyObject(key,obj); 179 } catch (Throwable t2) { 180 PoolUtils.checkRethrow(t2); 181 // swallowed 182 } finally { 183 obj = null; 184 } 185 if (newlyMade) { 186 throw new NoSuchElementException( 187 "Could not create a validated object, cause: " + 188 t.getMessage()); 189 } 190 } 191 } 192 } while (obj == null); 193 incrementActiveCount(key); 194 return obj; 195 } 196 197 /** 198 * Returns <code>obj</code> to the pool under <code>key</code>. If adding the 199 * returning instance to the pool results in {@link #_maxSleeping maxSleeping} 200 * exceeded for the given key, the oldest instance in the idle object pool 201 * is destroyed to make room for the returning instance. 202 * 203 * @param key the pool key 204 * @param obj returning instance 205 */ 206 @Override 207 public synchronized void returnObject(K key, V obj) throws Exception { 208 decrementActiveCount(key); 209 if (null != _factory) { 210 if (_factory.validateObject(key, obj)) { 211 try { 212 _factory.passivateObject(key, obj); 213 } catch (Exception ex) { 214 _factory.destroyObject(key, obj); 215 return; 216 } 217 } else { 218 return; 219 } 220 } 221 222 if (isClosed()) { 223 if (null != _factory) { 224 try { 225 _factory.destroyObject(key, obj); 226 } catch (Exception e) { 227 // swallowed 228 } 229 } 230 return; 231 } 232 233 Stack<V> stack = _pools.get(key); 234 if(null == stack) { 235 stack = new Stack<V>(); 236 stack.ensureCapacity( _initSleepingCapacity > _maxSleeping ? _maxSleeping : _initSleepingCapacity); 237 _pools.put(key,stack); 238 } 239 final int stackSize = stack.size(); 240 if (stackSize >= _maxSleeping) { 241 final V staleObj; 242 if (stackSize > 0) { 243 staleObj = stack.remove(0); 244 _totIdle--; 245 } else { 246 staleObj = obj; 247 } 248 if(null != _factory) { 249 try { 250 _factory.destroyObject(key, staleObj); 251 } catch (Exception e) { 252 // swallowed 253 } 254 } 255 } 256 stack.push(obj); 257 _totIdle++; 258 } 259 260 /** 261 * {@inheritDoc} 262 */ 263 @Override 264 public synchronized void invalidateObject(K key, V obj) throws Exception { 265 decrementActiveCount(key); 266 if(null != _factory) { 267 _factory.destroyObject(key,obj); 268 } 269 notifyAll(); // _totalActive has changed 270 } 271 272 /** 273 * Create an object using the {@link KeyedPoolableObjectFactory#makeObject factory}, 274 * passivate it, and then placed in the idle object pool. 275 * <code>addObject</code> is useful for "pre-loading" a pool with idle objects. 276 * 277 * @param key the key a new instance should be added to 278 * @throws Exception when {@link KeyedPoolableObjectFactory#makeObject} fails. 279 * @throws IllegalStateException when no {@link #setFactory factory} has been set or after {@link #close} has been called on this pool. 280 */ 281 @Override 282 public synchronized void addObject(K key) throws Exception { 283 assertOpen(); 284 if (_factory == null) { 285 throw new IllegalStateException("Cannot add objects without a factory."); 286 } 287 V obj = _factory.makeObject(key); 288 try { 289 if (!_factory.validateObject(key, obj)) { 290 return; 291 } 292 } catch (Exception e) { 293 try { 294 _factory.destroyObject(key, obj); 295 } catch (Exception e2) { 296 // swallowed 297 } 298 return; 299 } 300 _factory.passivateObject(key, obj); 301 302 Stack<V> stack = _pools.get(key); 303 if(null == stack) { 304 stack = new Stack<V>(); 305 stack.ensureCapacity( _initSleepingCapacity > _maxSleeping ? _maxSleeping : _initSleepingCapacity); 306 _pools.put(key,stack); 307 } 308 309 final int stackSize = stack.size(); 310 if (stackSize >= _maxSleeping) { 311 final V staleObj; 312 if (stackSize > 0) { 313 staleObj = stack.remove(0); 314 _totIdle--; 315 } else { 316 staleObj = obj; 317 } 318 try { 319 _factory.destroyObject(key, staleObj); 320 } catch (Exception e) { 321 // Don't swallow destroying the newly created object. 322 if (obj == staleObj) { 323 throw e; 324 } 325 } 326 } else { 327 stack.push(obj); 328 _totIdle++; 329 } 330 } 331 332 /** 333 * Returns the total number of instances currently idle in this pool. 334 * 335 * @return the total number of instances currently idle in this pool 336 */ 337 @Override 338 public synchronized int getNumIdle() { 339 return _totIdle; 340 } 341 342 /** 343 * Returns the total number of instances current borrowed from this pool but not yet returned. 344 * 345 * @return the total number of instances currently borrowed from this pool 346 */ 347 @Override 348 public synchronized int getNumActive() { 349 return _totActive; 350 } 351 352 /** 353 * Returns the number of instances currently borrowed from but not yet returned 354 * to the pool corresponding to the given <code>key</code>. 355 * 356 * @param key the key to query 357 * @return the number of instances corresponding to the given <code>key</code> currently borrowed in this pool 358 */ 359 @Override 360 public synchronized int getNumActive(K key) { 361 return getActiveCount(key); 362 } 363 364 /** 365 * Returns the number of instances corresponding to the given <code>key</code> currently idle in this pool. 366 * 367 * @param key the key to query 368 * @return the number of instances corresponding to the given <code>key</code> currently idle in this pool 369 */ 370 @Override 371 public synchronized int getNumIdle(K key) { 372 try { 373 return(_pools.get(key)).size(); 374 } catch(Exception e) { 375 return 0; 376 } 377 } 378 379 /** 380 * Clears the pool, removing all pooled instances. 381 */ 382 @Override 383 public synchronized void clear() { 384 Iterator<K> it = _pools.keySet().iterator(); 385 while(it.hasNext()) { 386 K key = it.next(); 387 Stack<V> stack = _pools.get(key); 388 destroyStack(key,stack); 389 } 390 _totIdle = 0; 391 _pools.clear(); 392 _activeCount.clear(); 393 } 394 395 /** 396 * Clears the specified pool, removing all pooled instances corresponding to the given <code>key</code>. 397 * 398 * @param key the key to clear 399 */ 400 @Override 401 public synchronized void clear(K key) { 402 Stack<V> stack = _pools.remove(key); 403 destroyStack(key,stack); 404 } 405 406 /** 407 * Destroys all instances in the stack and clears the stack. 408 * 409 * @param key key passed to factory when destroying instances 410 * @param stack stack to destroy 411 */ 412 private synchronized void destroyStack(K key, Stack<V> stack) { 413 if(null == stack) { 414 return; 415 } else { 416 if(null != _factory) { 417 Iterator<V> it = stack.iterator(); 418 while(it.hasNext()) { 419 try { 420 _factory.destroyObject(key,it.next()); 421 } catch(Exception e) { 422 // ignore error, keep destroying the rest 423 } 424 } 425 } 426 _totIdle -= stack.size(); 427 _activeCount.remove(key); 428 stack.clear(); 429 } 430 } 431 432 /** 433 * Returns a string representation of this StackKeyedObjectPool, including 434 * the number of pools, the keys and the size of each keyed pool. 435 * 436 * @return Keys and pool sizes 437 */ 438 @Override 439 public synchronized String toString() { 440 StringBuffer buf = new StringBuffer(); 441 buf.append(getClass().getName()); 442 buf.append(" contains ").append(_pools.size()).append(" distinct pools: "); 443 Iterator<K> it = _pools.keySet().iterator(); 444 while(it.hasNext()) { 445 K key = it.next(); 446 buf.append(" |").append(key).append("|="); 447 Stack<V> s = _pools.get(key); 448 buf.append(s.size()); 449 } 450 return buf.toString(); 451 } 452 453 /** 454 * Close this pool, and free any resources associated with it. 455 * <p> 456 * Calling {@link #addObject addObject} or {@link #borrowObject borrowObject} after invoking 457 * this method on a pool will cause them to throw an {@link IllegalStateException}. 458 * </p> 459 * 460 * @throws Exception <strong>deprecated</strong>: implementations should silently fail if not all resources can be freed. 461 */ 462 @Override 463 public void close() throws Exception { 464 super.close(); 465 clear(); 466 } 467 468 /** 469 * Sets the {@link KeyedPoolableObjectFactory factory} the pool uses 470 * to create new instances. 471 * Trying to change the <code>factory</code> after a pool has been used will frequently 472 * throw an {@link UnsupportedOperationException}. 473 * 474 * @param factory the {@link KeyedPoolableObjectFactory} used to manage object instances 475 * @throws IllegalStateException when the factory cannot be set at this time 476 * @deprecated to be removed in pool 2.0 477 */ 478 @Deprecated 479 @Override 480 public synchronized void setFactory(KeyedPoolableObjectFactory<K, V> factory) throws IllegalStateException { 481 if(0 < getNumActive()) { 482 throw new IllegalStateException("Objects are already active"); 483 } else { 484 clear(); 485 _factory = factory; 486 } 487 } 488 489 /** 490 * @return the {@link KeyedPoolableObjectFactory} used by this pool to manage object instances. 491 * @since 1.5.5 492 */ 493 public synchronized KeyedPoolableObjectFactory<K, V> getFactory() { 494 return _factory; 495 } 496 497 /** 498 * Returns the active instance count for the given key. 499 * 500 * @param key pool key 501 * @return active count 502 */ 503 private int getActiveCount(K key) { 504 try { 505 return _activeCount.get(key).intValue(); 506 } catch(NoSuchElementException e) { 507 return 0; 508 } catch(NullPointerException e) { 509 return 0; 510 } 511 } 512 513 /** 514 * Increment the active count for the given key. Also 515 * increments the total active count. 516 * 517 * @param key pool key 518 */ 519 private void incrementActiveCount(K key) { 520 _totActive++; 521 Integer old = _activeCount.get(key); 522 if(null == old) { 523 _activeCount.put(key,new Integer(1)); 524 } else { 525 _activeCount.put(key,new Integer(old.intValue() + 1)); 526 } 527 } 528 529 /** 530 * Decrements the active count for the given key. 531 * Also decrements the total active count. 532 * 533 * @param key pool key 534 */ 535 private void decrementActiveCount(K key) { 536 _totActive--; 537 Integer active = _activeCount.get(key); 538 if(null == active) { 539 // do nothing, either null or zero is OK 540 } else if(active.intValue() <= 1) { 541 _activeCount.remove(key); 542 } else { 543 _activeCount.put(key, new Integer(active.intValue() - 1)); 544 } 545 } 546 547 548 /** 549 * @return map of keyed pools 550 * @since 1.5.5 551 */ 552 public Map<K, Stack<V>> getPools() { 553 return _pools; 554 } 555 556 /** 557 * @return the cap on the number of "sleeping" instances in <code>each</code> pool. 558 * @since 1.5.5 559 */ 560 public int getMaxSleeping() { 561 return _maxSleeping; 562 } 563 564 /** 565 * @return the initial capacity of each pool. 566 * @since 1.5.5 567 */ 568 public int getInitSleepingCapacity() { 569 return _initSleepingCapacity; 570 } 571 572 /** 573 * @return the _totActive 574 */ 575 public int getTotActive() { 576 return _totActive; 577 } 578 579 /** 580 * @return the _totIdle 581 */ 582 public int getTotIdle() { 583 return _totIdle; 584 } 585 586 /** 587 * @return the _activeCount 588 * @since 1.5.5 589 */ 590 public Map<K, Integer> getActiveCount() { 591 return _activeCount; 592 } 593 594 595 /** The default cap on the number of "sleeping" instances in the pool. */ 596 protected static final int DEFAULT_MAX_SLEEPING = 8; 597 598 /** 599 * The default initial size of the pool 600 * (this specifies the size of the container, it does not 601 * cause the pool to be pre-populated.) 602 */ 603 protected static final int DEFAULT_INIT_SLEEPING_CAPACITY = 4; 604 605 /** 606 * My named-set of pools. 607 * @deprecated to be removed in pool 2.0. Use {@link #getPools()} 608 */ 609 @Deprecated 610 protected HashMap<K, Stack<V>> _pools = null; 611 612 /** 613 * My {@link KeyedPoolableObjectFactory}. 614 * @deprecated to be removed in pool 2.0. Use {@link #getFactory()} 615 */ 616 @Deprecated 617 protected KeyedPoolableObjectFactory<K, V> _factory = null; 618 619 /** 620 * The cap on the number of "sleeping" instances in <code>each</code> pool. 621 * @deprecated to be removed in pool 2.0. Use {@link #getMaxSleeping()} 622 */ 623 @Deprecated 624 protected int _maxSleeping = DEFAULT_MAX_SLEEPING; 625 626 /** 627 * The initial capacity of each pool. 628 * @deprecated to be removed in pool 2.0. Use {@link #getInitSleepingCapacity()}. 629 */ 630 @Deprecated 631 protected int _initSleepingCapacity = DEFAULT_INIT_SLEEPING_CAPACITY; 632 633 /** 634 * Total number of object borrowed and not yet returned for all pools. 635 * @deprecated to be removed in pool 2.0. Use {@link #getTotActive()}. 636 */ 637 @Deprecated 638 protected int _totActive = 0; 639 640 /** 641 * Total number of objects "sleeping" for all pools 642 * @deprecated to be removed in pool 2.0. Use {@link #getTotIdle()}. 643 */ 644 @Deprecated 645 protected int _totIdle = 0; 646 647 /** 648 * Number of active objects borrowed and not yet returned by pool 649 * @deprecated to be removed in pool 2.0. Use {@link #getActiveCount()}. 650 */ 651 @Deprecated 652 protected HashMap<K, Integer> _activeCount = null; 653 654 }