Coverage Report - org.apache.commons.pool.impl.SoftReferenceObjectPool
 
Classes in this File Line Coverage Branch Coverage Complexity
SoftReferenceObjectPool
0%
0/115
0%
0/52
3.571
 
 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 java.lang.ref.SoftReference;
 21  
 import java.lang.ref.ReferenceQueue;
 22  
 import java.lang.ref.Reference;
 23  
 import java.util.ArrayList;
 24  
 import java.util.Iterator;
 25  
 import java.util.List;
 26  
 import java.util.NoSuchElementException;
 27  
 
 28  
 import org.apache.commons.pool.BaseObjectPool;
 29  
 import org.apache.commons.pool.ObjectPool;
 30  
 import org.apache.commons.pool.PoolableObjectFactory;
 31  
 import org.apache.commons.pool.PoolUtils;
 32  
 
 33  
 /**
 34  
  * A {@link java.lang.ref.SoftReference SoftReference} based
 35  
  * {@link ObjectPool}.
 36  
  *
 37  
  * @author Rodney Waldhoff
 38  
  * @author Sandy McArthur
 39  
  * @version $Revision: 1206501 $ $Date: 2011-11-26 10:11:40 -0700 (Sat, 26 Nov 2011) $
 40  
  * @since Pool 1.0
 41  
  */
 42  
 public class SoftReferenceObjectPool extends BaseObjectPool implements ObjectPool {
 43  
     /**
 44  
      * Create a <code>SoftReferenceObjectPool</code> without a factory.
 45  
      * {@link #setFactory(PoolableObjectFactory) setFactory} should be called
 46  
      * before any attempts to use the pool are made.
 47  
      * Generally speaking you should prefer the {@link #SoftReferenceObjectPool(PoolableObjectFactory)} constructor.
 48  
      *
 49  
      * @see #SoftReferenceObjectPool(PoolableObjectFactory)
 50  
      * @deprecated to be removed in pool 2.0.  Use {@link #SoftReferenceObjectPool(PoolableObjectFactory)}.
 51  
      */
 52  0
     public SoftReferenceObjectPool() {
 53  0
         _pool = new ArrayList();
 54  0
         _factory = null;
 55  0
     }
 56  
 
 57  
     /**
 58  
      * Create a <code>SoftReferenceObjectPool</code> with the specified factory.
 59  
      *
 60  
      * @param factory object factory to use.
 61  
      */
 62  0
     public SoftReferenceObjectPool(PoolableObjectFactory factory) {
 63  0
         _pool = new ArrayList();
 64  0
         _factory = factory;
 65  0
     }
 66  
 
 67  
     /**
 68  
      * Create a <code>SoftReferenceObjectPool</code> with the specified factory and initial idle object count.
 69  
      *
 70  
      * @param factory object factory to use.
 71  
      * @param initSize initial size to attempt to prefill the pool.
 72  
      * @throws Exception when there is a problem prefilling the pool.
 73  
      * @throws IllegalArgumentException when <code>factory</code> is <code>null</code>.
 74  
      * @deprecated because this is a SoftReference pool, prefilled idle obejects may be garbage collected before they are used.
 75  
      *      To be removed in Pool 2.0.
 76  
      */
 77  0
     public SoftReferenceObjectPool(PoolableObjectFactory factory, int initSize) throws Exception, IllegalArgumentException {
 78  0
         if (factory == null) {
 79  0
             throw new IllegalArgumentException("factory required to prefill the pool.");
 80  
         }
 81  0
         _pool = new ArrayList(initSize);
 82  0
         _factory = factory;
 83  0
         PoolUtils.prefill(this, initSize);
 84  0
     }
 85  
 
 86  
     /**
 87  
      * <p>Borrow an object from the pool.  If there are no idle instances available in the pool, the configured
 88  
      * factory's {@link PoolableObjectFactory#makeObject()} method is invoked to create a new instance.</p>
 89  
      * 
 90  
      * <p>All instances are {@link PoolableObjectFactory#activateObject(Object) activated} and
 91  
      * {@link PoolableObjectFactory#validateObject(Object) validated} before being returned by this
 92  
      * method.  If validation fails or an exception occurs activating or validating an idle instance,
 93  
      * the failing instance is {@link PoolableObjectFactory#destroyObject(Object) destroyed} and another
 94  
      * instance is retrieved from the pool, validated and activated.  This process continues until either the
 95  
      * pool is empty or an instance passes validation.  If the pool is empty on activation or
 96  
      * it does not contain any valid instances, the factory's <code>makeObject</code> method is used
 97  
      * to create a new instance.  If the created instance either raises an exception on activation or
 98  
      * fails validation, <code>NoSuchElementException</code> is thrown. Exceptions thrown by <code>MakeObject</code>
 99  
      * are propagated to the caller; but other than <code>ThreadDeath</code> or <code>VirtualMachineError</code>,
 100  
      * exceptions generated by activation, validation or destroy methods are swallowed silently.</p>
 101  
      * 
 102  
      * @throws NoSuchElementException if a valid object cannot be provided
 103  
      * @throws IllegalStateException if invoked on a {@link #close() closed} pool
 104  
      * @throws Exception if an exception occurs creating a new instance
 105  
      * @return a valid, activated object instance
 106  
      */
 107  
     public synchronized Object borrowObject() throws Exception {
 108  0
         assertOpen();
 109  0
         Object obj = null;
 110  0
         boolean newlyCreated = false;
 111  0
         while(null == obj) {
 112  0
             if(_pool.isEmpty()) {
 113  0
                 if(null == _factory) {
 114  0
                     throw new NoSuchElementException();
 115  
                 } else {
 116  0
                     newlyCreated = true;
 117  0
                     obj = _factory.makeObject();
 118  
                 }
 119  
             } else {
 120  0
                 SoftReference ref = (SoftReference)(_pool.remove(_pool.size() - 1));
 121  0
                 obj = ref.get();
 122  0
                 ref.clear(); // prevent this ref from being enqueued with refQueue.
 123  
             }
 124  0
             if (null != _factory && null != obj) {
 125  
                 try {
 126  0
                     _factory.activateObject(obj);
 127  0
                     if (!_factory.validateObject(obj)) {
 128  0
                         throw new Exception("ValidateObject failed");
 129  
                     }
 130  0
                 } catch (Throwable t) {
 131  0
                     PoolUtils.checkRethrow(t);
 132  
                     try {
 133  0
                         _factory.destroyObject(obj);
 134  0
                     } catch (Throwable t2) {
 135  0
                         PoolUtils.checkRethrow(t2);
 136  
                         // Swallowed
 137  
                     } finally {
 138  0
                         obj = null;
 139  0
                     }
 140  0
                     if (newlyCreated) {
 141  0
                         throw new NoSuchElementException(
 142  
                             "Could not create a validated object, cause: " +
 143  
                             t.getMessage());
 144  
                     }
 145  0
                 }
 146  
             }
 147  
         }
 148  0
         _numActive++;
 149  0
         return obj;
 150  
     }
 151  
 
 152  
     /**
 153  
      * <p>Returns an instance to the pool after successful validation and passivation. The returning instance
 154  
      * is destroyed if any of the following are true:<ul>
 155  
      *   <li>the pool is closed</li>
 156  
      *   <li>{@link PoolableObjectFactory#validateObject(Object) validation} fails</li>
 157  
      *   <li>{@link PoolableObjectFactory#passivateObject(Object) passivation} throws an exception</li>
 158  
      * </ul>
 159  
      *</p>
 160  
      * 
 161  
      * <p>Exceptions passivating or destroying instances are silently swallowed.  Exceptions validating
 162  
      * instances are propagated to the client.</p>
 163  
      * 
 164  
      * @param obj instance to return to the pool
 165  
      */
 166  
     public synchronized void returnObject(Object obj) throws Exception {
 167  0
         boolean success = !isClosed();
 168  0
         if (_factory != null) {
 169  0
             if(!_factory.validateObject(obj)) {
 170  0
                 success = false;
 171  
             } else {
 172  
                 try {
 173  0
                     _factory.passivateObject(obj);
 174  0
                 } catch(Exception e) {
 175  0
                     success = false;
 176  0
                 }
 177  
             }
 178  
         }
 179  
 
 180  0
         boolean shouldDestroy = !success;
 181  0
         _numActive--;
 182  0
         if(success) {
 183  0
             _pool.add(new SoftReference(obj, refQueue));
 184  
         }
 185  0
         notifyAll(); // _numActive has changed
 186  
 
 187  0
         if (shouldDestroy && _factory != null) {
 188  
             try {
 189  0
                 _factory.destroyObject(obj);
 190  0
             } catch(Exception e) {
 191  
                 // ignored
 192  0
             }
 193  
         }
 194  0
     }
 195  
 
 196  
     /**
 197  
      * {@inheritDoc}
 198  
      */
 199  
     public synchronized void invalidateObject(Object obj) throws Exception {
 200  0
         _numActive--;
 201  0
         if (_factory != null) {
 202  0
             _factory.destroyObject(obj);
 203  
         }
 204  0
         notifyAll(); // _numActive has changed
 205  0
     }
 206  
 
 207  
     /**
 208  
      * <p>Create an object, and place it into the pool.
 209  
      * addObject() is useful for "pre-loading" a pool with idle objects.</p>
 210  
      * 
 211  
      * <p>Before being added to the pool, the newly created instance is
 212  
      * {@link PoolableObjectFactory#validateObject(Object) validated} and 
 213  
      * {@link PoolableObjectFactory#passivateObject(Object) passivated}.  If validation
 214  
      * fails, the new instance is {@link PoolableObjectFactory#destroyObject(Object) destroyed}.
 215  
      * Exceptions generated by the factory <code>makeObject</code> or <code>passivate</code> are
 216  
      * propagated to the caller. Exceptions destroying instances are silently swallowed.</p>
 217  
      * 
 218  
      * @throws IllegalStateException if invoked on a {@link #close() closed} pool
 219  
      * @throws Exception when the {@link #getFactory() factory} has a problem creating or passivating an object.
 220  
      */
 221  
     public synchronized void addObject() throws Exception {
 222  0
         assertOpen();
 223  0
         if (_factory == null) {
 224  0
             throw new IllegalStateException("Cannot add objects without a factory.");
 225  
         }
 226  0
         Object obj = _factory.makeObject();
 227  
 
 228  0
         boolean success = true;
 229  0
         if(!_factory.validateObject(obj)) {
 230  0
             success = false;
 231  
         } else {
 232  0
             _factory.passivateObject(obj);
 233  
         }
 234  
 
 235  0
         boolean shouldDestroy = !success;
 236  0
         if(success) {
 237  0
             _pool.add(new SoftReference(obj, refQueue));
 238  0
             notifyAll(); // _numActive has changed
 239  
         }
 240  
 
 241  0
         if(shouldDestroy) {
 242  
             try {
 243  0
                 _factory.destroyObject(obj);
 244  0
             } catch(Exception e) {
 245  
                 // ignored
 246  0
             }
 247  
         }
 248  0
     }
 249  
 
 250  
     /**
 251  
      * Returns an approximation not less than the of the number of idle instances in the pool.
 252  
      * 
 253  
      * @return estimated number of idle instances in the pool
 254  
      */
 255  
     public synchronized int getNumIdle() {
 256  0
         pruneClearedReferences();
 257  0
         return _pool.size();
 258  
     }
 259  
 
 260  
     /**
 261  
      * Return the number of instances currently borrowed from this pool.
 262  
      *
 263  
      * @return the number of instances currently borrowed from this pool
 264  
      */
 265  
     public synchronized int getNumActive() {
 266  0
         return _numActive;
 267  
     }
 268  
 
 269  
     /**
 270  
      * Clears any objects sitting idle in the pool.
 271  
      */
 272  
     public synchronized void clear() {
 273  0
         if(null != _factory) {
 274  0
             Iterator iter = _pool.iterator();
 275  0
             while(iter.hasNext()) {
 276  
                 try {
 277  0
                     Object obj = ((SoftReference)iter.next()).get();
 278  0
                     if(null != obj) {
 279  0
                         _factory.destroyObject(obj);
 280  
                     }
 281  0
                 } catch(Exception e) {
 282  
                     // ignore error, keep destroying the rest
 283  0
                 }
 284  
             }
 285  
         }
 286  0
         _pool.clear();
 287  0
         pruneClearedReferences();
 288  0
     }
 289  
 
 290  
     /**
 291  
      * <p>Close this pool, and free any resources associated with it. Invokes
 292  
      * {@link #clear()} to destroy and remove instances in the pool.</p>
 293  
      * 
 294  
      * <p>Calling {@link #addObject} or {@link #borrowObject} after invoking
 295  
      * this method on a pool will cause them to throw an
 296  
      * {@link IllegalStateException}.</p>
 297  
      *
 298  
      * @throws Exception never - exceptions clearing the pool are swallowed
 299  
      */
 300  
     public void close() throws Exception {
 301  0
         super.close();
 302  0
         clear();
 303  0
     }
 304  
 
 305  
     /**
 306  
      * Sets the {@link PoolableObjectFactory factory} this pool uses
 307  
      * to create new instances. Trying to change
 308  
      * the <code>factory</code> while there are borrowed objects will
 309  
      * throw an {@link IllegalStateException}.
 310  
      *
 311  
      * @param factory the {@link PoolableObjectFactory} used to create new instances.
 312  
      * @throws IllegalStateException when the factory cannot be set at this time
 313  
      * @deprecated to be removed in pool 2.0
 314  
      */
 315  
     public synchronized void setFactory(PoolableObjectFactory factory) throws IllegalStateException {
 316  0
         assertOpen();
 317  0
         if(0 < getNumActive()) {
 318  0
             throw new IllegalStateException("Objects are already active");
 319  
         } else {
 320  0
             clear();
 321  0
             _factory = factory;
 322  
         }
 323  0
     }
 324  
 
 325  
     /**
 326  
      * If any idle objects were garbage collected, remove their
 327  
      * {@link Reference} wrappers from the idle object pool.
 328  
      */
 329  
     private void pruneClearedReferences() {
 330  
         Reference ref;
 331  0
         while ((ref = refQueue.poll()) != null) {
 332  
             try {
 333  0
                 _pool.remove(ref);
 334  0
             } catch (UnsupportedOperationException uoe) {
 335  
                 // ignored
 336  0
             }
 337  
         }
 338  0
     }
 339  
     
 340  
     /**
 341  
      * Returns the {@link PoolableObjectFactory} used by this pool to create and manage object instances.
 342  
      * 
 343  
      * @return the factory
 344  
      * @since 1.5.5
 345  
      */
 346  
     public synchronized PoolableObjectFactory getFactory() { 
 347  0
         return _factory;
 348  
     }
 349  
 
 350  
     /** My pool. */
 351  
     private final List _pool;
 352  
 
 353  
     /** My {@link PoolableObjectFactory}. */
 354  0
     private PoolableObjectFactory _factory = null;
 355  
 
 356  
     /**
 357  
      * Queue of broken references that might be able to be removed from <code>_pool</code>.
 358  
      * This is used to help {@link #getNumIdle()} be more accurate with minimial
 359  
      * performance overhead.
 360  
      */
 361  0
     private final ReferenceQueue refQueue = new ReferenceQueue();
 362  
 
 363  
     /** Number of active objects. */
 364  0
     private int _numActive = 0; //@GuardeBy("this")
 365  
 }