Coverage Report - org.apache.commons.pool.impl.StackKeyedObjectPool
 
Classes in this File Line Coverage Branch Coverage Complexity
StackKeyedObjectPool
0%
0/193
0%
0/74
3.783
 
 1  
 /*
 2  
  * Licensed to the Apache Software Foundation (ASF) under one or more
 3  
  * contributor license agreements.  See the NOTICE file distributed with
 4  
  * this work for additional information regarding copyright ownership.
 5  
  * The ASF licenses this file to You under the Apache License, Version 2.0
 6  
  * (the "License"); you may not use this file except in compliance with
 7  
  * the License.  You may obtain a copy of the License at
 8  
  *
 9  
  *      http://www.apache.org/licenses/LICENSE-2.0
 10  
  *
 11  
  * Unless required by applicable law or agreed to in writing, software
 12  
  * distributed under the License is distributed on an "AS IS" BASIS,
 13  
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 14  
  * See the License for the specific language governing permissions and
 15  
  * limitations under the License.
 16  
  */
 17  
 
 18  
 package org.apache.commons.pool.impl;
 19  
 
 20  
 import org.apache.commons.pool.BaseKeyedObjectPool;
 21  
 import org.apache.commons.pool.KeyedObjectPool;
 22  
 import org.apache.commons.pool.KeyedPoolableObjectFactory;
 23  
 
 24  
 import java.util.HashMap;
 25  
 import java.util.Iterator;
 26  
 import java.util.NoSuchElementException;
 27  
 import java.util.Stack;
 28  
 
 29  
 /**
 30  
  * A simple, <code>Stack</code>-based <code>KeyedObjectPool</code> implementation.
 31  
  * <p>
 32  
  * Given a {@link KeyedPoolableObjectFactory}, this class will maintain
 33  
  * a simple pool of instances.  A finite number of "sleeping"
 34  
  * or inactive instances is enforced, but when the pool is
 35  
  * empty, new instances are created to support the new load.
 36  
  * Hence this class places no limit on the number of "active"
 37  
  * instances created by the pool, but is quite useful for
 38  
  * re-using <code>Object</code>s without introducing
 39  
  * artificial limits.
 40  
  * </p>
 41  
  *
 42  
  * @author Rodney Waldhoff
 43  
  * @author Sandy McArthur
 44  
  * @version $Revision: 778880 $ $Date: 2009-05-26 16:46:22 -0400 (Tue, 26 May 2009) $
 45  
  * @see Stack
 46  
  * @since Pool 1.0
 47  
  */
 48  
 public class StackKeyedObjectPool extends BaseKeyedObjectPool implements KeyedObjectPool {
 49  
     /**
 50  
      * Create a new pool using no factory.
 51  
      * Clients must first set the {@link #setFactory factory} or
 52  
      * may populate the pool using {@link #returnObject returnObject}
 53  
      * before they can be {@link #borrowObject borrowed}.
 54  
      *
 55  
      * @see #StackKeyedObjectPool(KeyedPoolableObjectFactory)
 56  
      * @see #setFactory(KeyedPoolableObjectFactory)
 57  
      */
 58  
     public StackKeyedObjectPool() {
 59  0
         this((KeyedPoolableObjectFactory)null,DEFAULT_MAX_SLEEPING,DEFAULT_INIT_SLEEPING_CAPACITY);
 60  0
     }
 61  
 
 62  
     /**
 63  
      * Create a new pool using no factory.
 64  
      * Clients must first set the {@link #setFactory factory} or
 65  
      * may populate the pool using {@link #returnObject returnObject}
 66  
      * before they can be {@link #borrowObject borrowed}.
 67  
      *
 68  
      * @param max cap on the number of "sleeping" instances in the pool
 69  
      * @see #StackKeyedObjectPool(KeyedPoolableObjectFactory, int)
 70  
      * @see #setFactory(KeyedPoolableObjectFactory)
 71  
      */
 72  
     public StackKeyedObjectPool(int max) {
 73  0
         this((KeyedPoolableObjectFactory)null,max,DEFAULT_INIT_SLEEPING_CAPACITY);
 74  0
     }
 75  
 
 76  
     /**
 77  
      * Create a new pool using no factory.
 78  
      * Clients must first set the {@link #setFactory factory} or
 79  
      * may populate the pool using {@link #returnObject returnObject}
 80  
      * before they can be {@link #borrowObject borrowed}.
 81  
      *
 82  
      * @param max cap on the number of "sleeping" instances in the pool
 83  
      * @param init initial size of the pool (this specifies the size of the container,
 84  
      *             it does not cause the pool to be pre-populated.)
 85  
      * @see #StackKeyedObjectPool(KeyedPoolableObjectFactory, int, int)
 86  
      * @see #setFactory(KeyedPoolableObjectFactory)
 87  
      */
 88  
     public StackKeyedObjectPool(int max, int init) {
 89  0
         this((KeyedPoolableObjectFactory)null,max,init);
 90  0
     }
 91  
 
 92  
     /**
 93  
      * Create a new <code>SimpleKeyedObjectPool</code> using
 94  
      * the specified <code>factory</code> to create new instances.
 95  
      *
 96  
      * @param factory the {@link KeyedPoolableObjectFactory} used to populate the pool
 97  
      */
 98  
     public StackKeyedObjectPool(KeyedPoolableObjectFactory factory) {
 99  0
         this(factory,DEFAULT_MAX_SLEEPING);
 100  0
     }
 101  
 
 102  
     /**
 103  
      * Create a new <code>SimpleKeyedObjectPool</code> using
 104  
      * the specified <code>factory</code> to create new instances.
 105  
      * capping the number of "sleeping" instances to <code>max</code>
 106  
      *
 107  
      * @param factory the {@link KeyedPoolableObjectFactory} used to populate the pool
 108  
      * @param max cap on the number of "sleeping" instances in the pool
 109  
      */
 110  
     public StackKeyedObjectPool(KeyedPoolableObjectFactory factory, int max) {
 111  0
         this(factory,max,DEFAULT_INIT_SLEEPING_CAPACITY);
 112  0
     }
 113  
 
 114  
     /**
 115  
      * Create a new <code>SimpleKeyedObjectPool</code> using
 116  
      * the specified <code>factory</code> to create new instances.
 117  
      * capping the number of "sleeping" instances to <code>max</code>,
 118  
      * and initially allocating a container capable of containing
 119  
      * at least <code>init</code> instances.
 120  
      *
 121  
      * @param factory the {@link KeyedPoolableObjectFactory} used to populate the pool
 122  
      * @param max cap on the number of "sleeping" instances in the pool
 123  
      * @param init initial size of the pool (this specifies the size of the container,
 124  
      *             it does not cause the pool to be pre-populated.)
 125  
      */
 126  0
     public StackKeyedObjectPool(KeyedPoolableObjectFactory factory, int max, int init) {
 127  0
         _factory = factory;
 128  0
         _maxSleeping = (max < 0 ? DEFAULT_MAX_SLEEPING : max);
 129  0
         _initSleepingCapacity = (init < 1 ? DEFAULT_INIT_SLEEPING_CAPACITY : init);
 130  0
         _pools = new HashMap();
 131  0
         _activeCount = new HashMap();
 132  0
     }
 133  
 
 134  
     public synchronized Object borrowObject(Object key) throws Exception {
 135  0
         assertOpen();
 136  0
         Stack stack = (Stack)(_pools.get(key));
 137  0
         if(null == stack) {
 138  0
             stack = new Stack();
 139  0
             stack.ensureCapacity( _initSleepingCapacity > _maxSleeping ? _maxSleeping : _initSleepingCapacity);
 140  0
             _pools.put(key,stack);
 141  
         }
 142  0
         Object obj = null;
 143  
         do {
 144  0
             boolean newlyMade = false;
 145  0
             if (!stack.empty()) {
 146  0
                 obj = stack.pop();
 147  0
                 _totIdle--;
 148  
             } else {
 149  0
                 if(null == _factory) {
 150  0
                     throw new NoSuchElementException("pools without a factory cannot create new objects as needed.");
 151  
                 } else {
 152  0
                     obj = _factory.makeObject(key);
 153  0
                     newlyMade = true;
 154  
                 }
 155  
             }
 156  0
             if (null != _factory && null != obj) {
 157  
                 try {
 158  0
                     _factory.activateObject(key, obj);
 159  0
                     if (!_factory.validateObject(key, obj)) {
 160  0
                         throw new Exception("ValidateObject failed");
 161  
                     }
 162  0
                 } catch (Throwable t) {
 163  
                     try {
 164  0
                         _factory.destroyObject(key,obj);
 165  0
                     } catch (Throwable t2) {
 166  
                         // swallowed
 167  
                     } finally {
 168  0
                         obj = null;
 169  0
                     }
 170  0
                     if (newlyMade) {
 171  0
                         throw new NoSuchElementException(
 172  
                             "Could not create a validated object, cause: " +
 173  
                             t.getMessage());
 174  
                     }
 175  0
                 }
 176  
             }
 177  0
         } while (obj == null);
 178  0
         incrementActiveCount(key);
 179  0
         return obj;
 180  
     }
 181  
 
 182  
     public synchronized void returnObject(Object key, Object obj) throws Exception {
 183  0
         decrementActiveCount(key);
 184  0
         if (null != _factory) {
 185  0
             if (_factory.validateObject(key, obj)) {
 186  
                 try {
 187  0
                     _factory.passivateObject(key, obj);
 188  0
                 } catch (Exception ex) {
 189  0
                     _factory.destroyObject(key, obj);
 190  0
                     return;
 191  0
                 }
 192  
             } else {
 193  0
                 return;
 194  
             }
 195  
         }
 196  
 
 197  0
         if (isClosed()) {
 198  0
             if (null != _factory) {
 199  
                 try {
 200  0
                     _factory.destroyObject(key, obj);
 201  0
                 } catch (Exception e) {
 202  
                     // swallowed
 203  0
                 }
 204  
             }
 205  0
             return;
 206  
         }
 207  
 
 208  0
         Stack stack = (Stack)_pools.get(key);
 209  0
         if(null == stack) {
 210  0
             stack = new Stack();
 211  0
             stack.ensureCapacity( _initSleepingCapacity > _maxSleeping ? _maxSleeping : _initSleepingCapacity);
 212  0
             _pools.put(key,stack);
 213  
         }
 214  0
         final int stackSize = stack.size();
 215  0
         if (stackSize >= _maxSleeping) {
 216  
             final Object staleObj;
 217  0
             if (stackSize > 0) {
 218  0
                 staleObj = stack.remove(0);
 219  0
                 _totIdle--;
 220  
             } else {
 221  0
                 staleObj = obj;
 222  
             }
 223  0
             if(null != _factory) {
 224  
                 try {
 225  0
                     _factory.destroyObject(key, staleObj);
 226  0
                 } catch (Exception e) {
 227  
                     // swallowed
 228  0
                 }
 229  
             }
 230  
         }
 231  0
         stack.push(obj);
 232  0
         _totIdle++;
 233  0
     }
 234  
 
 235  
     public synchronized void invalidateObject(Object key, Object obj) throws Exception {
 236  0
         decrementActiveCount(key);
 237  0
         if(null != _factory) {
 238  0
             _factory.destroyObject(key,obj);
 239  
         }
 240  0
         notifyAll(); // _totalActive has changed
 241  0
     }
 242  
 
 243  
     /**
 244  
      * Create an object using the {@link KeyedPoolableObjectFactory#makeObject factory},
 245  
      * passivate it, and then placed in the idle object pool.
 246  
      * <code>addObject</code> is useful for "pre-loading" a pool with idle objects.
 247  
      *
 248  
      * @param key the key a new instance should be added to
 249  
      * @throws Exception when {@link KeyedPoolableObjectFactory#makeObject} fails.
 250  
      * @throws IllegalStateException when no {@link #setFactory factory} has been set or after {@link #close} has been called on this pool.
 251  
      */
 252  
     public synchronized void addObject(Object key) throws Exception {
 253  0
         assertOpen();
 254  0
         if (_factory == null) {
 255  0
             throw new IllegalStateException("Cannot add objects without a factory.");
 256  
         }
 257  0
         Object obj = _factory.makeObject(key);
 258  
         try {
 259  0
             if (!_factory.validateObject(key, obj)) {
 260  0
                return;
 261  
             }
 262  0
         } catch (Exception e) {
 263  
             try {
 264  0
                 _factory.destroyObject(key, obj);
 265  0
             } catch (Exception e2) {
 266  
                 // swallowed
 267  0
             }
 268  0
             return;
 269  0
         }
 270  0
         _factory.passivateObject(key, obj);
 271  
 
 272  0
         Stack stack = (Stack)_pools.get(key);
 273  0
         if(null == stack) {
 274  0
             stack = new Stack();
 275  0
             stack.ensureCapacity( _initSleepingCapacity > _maxSleeping ? _maxSleeping : _initSleepingCapacity);
 276  0
             _pools.put(key,stack);
 277  
         }
 278  
 
 279  0
         final int stackSize = stack.size();
 280  0
         if (stackSize >= _maxSleeping) {
 281  
             final Object staleObj;
 282  0
             if (stackSize > 0) {
 283  0
                 staleObj = stack.remove(0);
 284  0
                 _totIdle--;
 285  
             } else {
 286  0
                 staleObj = obj;
 287  
             }
 288  
             try {
 289  0
                 _factory.destroyObject(key, staleObj);
 290  0
             } catch (Exception e) {
 291  
                 // Don't swallow destroying the newly created object.
 292  0
                 if (obj == staleObj) {
 293  0
                     throw e;
 294  
                 }
 295  0
             }
 296  0
         } else {
 297  0
             stack.push(obj);
 298  0
             _totIdle++;
 299  
         }
 300  0
     }
 301  
 
 302  
     /**
 303  
      * Returns the total number of instances currently idle in this pool.
 304  
      *
 305  
      * @return the total number of instances currently idle in this pool
 306  
      */
 307  
     public synchronized int getNumIdle() {
 308  0
         return _totIdle;
 309  
     }
 310  
 
 311  
     /**
 312  
      * Returns the total number of instances current borrowed from this pool but not yet returned.
 313  
      *
 314  
      * @return the total number of instances currently borrowed from this pool
 315  
      */
 316  
     public synchronized int getNumActive() {
 317  0
         return _totActive;
 318  
     }
 319  
 
 320  
     /**
 321  
      * Returns the number of instances currently borrowed from but not yet returned
 322  
      * to the pool corresponding to the given <code>key</code>.
 323  
      *
 324  
      * @param key the key to query
 325  
      * @return the number of instances corresponding to the given <code>key</code> currently borrowed in this pool
 326  
      */
 327  
     public synchronized int getNumActive(Object key) {
 328  0
         return getActiveCount(key);
 329  
     }
 330  
 
 331  
     /**
 332  
      * Returns the number of instances corresponding to the given <code>key</code> currently idle in this pool.
 333  
      *
 334  
      * @param key the key to query
 335  
      * @return the number of instances corresponding to the given <code>key</code> currently idle in this pool
 336  
      */
 337  
     public synchronized int getNumIdle(Object key) {
 338  
         try {
 339  0
             return((Stack)(_pools.get(key))).size();
 340  0
         } catch(Exception e) {
 341  0
             return 0;
 342  
         }
 343  
     }
 344  
 
 345  
     /**
 346  
      * Clears the pool, removing all pooled instances.
 347  
      */
 348  
     public synchronized void clear() {
 349  0
         Iterator it = _pools.keySet().iterator();
 350  0
         while(it.hasNext()) {
 351  0
             Object key = it.next();
 352  0
             Stack stack = (Stack)(_pools.get(key));
 353  0
             destroyStack(key,stack);
 354  0
         }
 355  0
         _totIdle = 0;
 356  0
         _pools.clear();
 357  0
         _activeCount.clear();
 358  0
     }
 359  
 
 360  
     /**
 361  
      * Clears the specified pool, removing all pooled instances corresponding to the given <code>key</code>.
 362  
      *
 363  
      * @param key the key to clear
 364  
      */
 365  
     public synchronized void clear(Object key) {
 366  0
         Stack stack = (Stack)(_pools.remove(key));
 367  0
         destroyStack(key,stack);
 368  0
     }
 369  
 
 370  
     private synchronized void destroyStack(Object key, Stack stack) {
 371  0
         if(null == stack) {
 372  0
             return;
 373  
         } else {
 374  0
             if(null != _factory) {
 375  0
                 Iterator it = stack.iterator();
 376  0
                 while(it.hasNext()) {
 377  
                     try {
 378  0
                         _factory.destroyObject(key,it.next());
 379  0
                     } catch(Exception e) {
 380  
                         // ignore error, keep destroying the rest
 381  0
                     }
 382  
                 }
 383  
             }
 384  0
             _totIdle -= stack.size();
 385  0
             _activeCount.remove(key);
 386  0
             stack.clear();
 387  
         }
 388  0
     }
 389  
 
 390  
     public synchronized String toString() {
 391  0
         StringBuffer buf = new StringBuffer();
 392  0
         buf.append(getClass().getName());
 393  0
         buf.append(" contains ").append(_pools.size()).append(" distinct pools: ");
 394  0
         Iterator it = _pools.keySet().iterator();
 395  0
         while(it.hasNext()) {
 396  0
             Object key = it.next();
 397  0
             buf.append(" |").append(key).append("|=");
 398  0
             Stack s = (Stack)(_pools.get(key));
 399  0
             buf.append(s.size());
 400  0
         }
 401  0
         return buf.toString();
 402  
     }
 403  
 
 404  
     /**
 405  
      * Close this pool, and free any resources associated with it.
 406  
      * <p>
 407  
      * Calling {@link #addObject addObject} or {@link #borrowObject borrowObject} after invoking
 408  
      * this method on a pool will cause them to throw an {@link IllegalStateException}.
 409  
      * </p>
 410  
      *
 411  
      * @throws Exception <strong>deprecated</strong>: implementations should silently fail if not all resources can be freed.
 412  
      */
 413  
     public void close() throws Exception {
 414  0
         super.close();
 415  0
         clear();
 416  0
     }
 417  
 
 418  
     /**
 419  
      * Sets the {@link KeyedPoolableObjectFactory factory} the pool uses
 420  
      * to create new instances.
 421  
      * Trying to change the <code>factory</code> after a pool has been used will frequently
 422  
      * throw an {@link UnsupportedOperationException}.
 423  
      *
 424  
      * @param factory the {@link KeyedPoolableObjectFactory} used to create new instances.
 425  
      * @throws IllegalStateException when the factory cannot be set at this time
 426  
      */
 427  
     public synchronized void setFactory(KeyedPoolableObjectFactory factory) throws IllegalStateException {
 428  0
         if(0 < getNumActive()) {
 429  0
             throw new IllegalStateException("Objects are already active");
 430  
         } else {
 431  0
             clear();
 432  0
             _factory = factory;
 433  
         }
 434  0
     }
 435  
 
 436  
     private int getActiveCount(Object key) {
 437  
         try {
 438  0
             return ((Integer)_activeCount.get(key)).intValue();
 439  0
         } catch(NoSuchElementException e) {
 440  0
             return 0;
 441  0
         } catch(NullPointerException e) {
 442  0
             return 0;
 443  
         }
 444  
     }
 445  
 
 446  
     private void incrementActiveCount(Object key) {
 447  0
         _totActive++;
 448  0
         Integer old = (Integer)(_activeCount.get(key));
 449  0
         if(null == old) {
 450  0
             _activeCount.put(key,new Integer(1));
 451  
         } else {
 452  0
             _activeCount.put(key,new Integer(old.intValue() + 1));
 453  
         }
 454  0
     }
 455  
 
 456  
     private void decrementActiveCount(Object key) {
 457  0
         _totActive--;
 458  0
         Integer active = (Integer)(_activeCount.get(key));
 459  0
         if(null == active) {
 460  
             // do nothing, either null or zero is OK
 461  0
         } else if(active.intValue() <= 1) {
 462  0
             _activeCount.remove(key);
 463  
         } else {
 464  0
             _activeCount.put(key, new Integer(active.intValue() - 1));
 465  
         }
 466  0
     }
 467  
 
 468  
     /** The default cap on the number of "sleeping" instances in the pool. */
 469  
     protected static final int DEFAULT_MAX_SLEEPING  = 8;
 470  
 
 471  
     /**
 472  
      * The default initial size of the pool
 473  
      * (this specifies the size of the container, it does not
 474  
      * cause the pool to be pre-populated.)
 475  
      */
 476  
     protected static final int DEFAULT_INIT_SLEEPING_CAPACITY = 4;
 477  
 
 478  
     /** My named-set of pools. */
 479  0
     protected HashMap _pools = null;
 480  
 
 481  
     /** My {@link KeyedPoolableObjectFactory}. */
 482  0
     protected KeyedPoolableObjectFactory _factory = null;
 483  
 
 484  
     /** The cap on the number of "sleeping" instances in <code>each</code> pool. */
 485  0
     protected int _maxSleeping = DEFAULT_MAX_SLEEPING;
 486  
 
 487  
     /** The initial capacity of each pool. */
 488  0
     protected int _initSleepingCapacity = DEFAULT_INIT_SLEEPING_CAPACITY;
 489  
 
 490  
     /** Total number of object borrowed and not yet retuened for all pools */
 491  0
     protected int _totActive = 0;
 492  
 
 493  
     /** Total number of objects "sleeping" for all pools */
 494  0
     protected int _totIdle = 0;
 495  
 
 496  
     /** Number of active objects borrowed and not yet returned by pool */
 497  0
     protected HashMap _activeCount = null;
 498  
 
 499  
 }