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 }