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.lang.ref.SoftReference; 021 import java.lang.ref.ReferenceQueue; 022 import java.lang.ref.Reference; 023 import java.util.ArrayList; 024 import java.util.Iterator; 025 import java.util.List; 026 import java.util.NoSuchElementException; 027 028 import org.apache.commons.pool.BaseObjectPool; 029 import org.apache.commons.pool.ObjectPool; 030 import org.apache.commons.pool.PoolableObjectFactory; 031 import org.apache.commons.pool.PoolUtils; 032 033 /** 034 * A {@link java.lang.ref.SoftReference SoftReference} based 035 * {@link ObjectPool}. 036 * 037 * @author Rodney Waldhoff 038 * @author Sandy McArthur 039 * @version $Revision: 1206501 $ $Date: 2011-11-26 10:11:40 -0700 (Sat, 26 Nov 2011) $ 040 * @since Pool 1.0 041 */ 042 public class SoftReferenceObjectPool extends BaseObjectPool implements ObjectPool { 043 /** 044 * Create a <code>SoftReferenceObjectPool</code> without a factory. 045 * {@link #setFactory(PoolableObjectFactory) setFactory} should be called 046 * before any attempts to use the pool are made. 047 * Generally speaking you should prefer the {@link #SoftReferenceObjectPool(PoolableObjectFactory)} constructor. 048 * 049 * @see #SoftReferenceObjectPool(PoolableObjectFactory) 050 * @deprecated to be removed in pool 2.0. Use {@link #SoftReferenceObjectPool(PoolableObjectFactory)}. 051 */ 052 public SoftReferenceObjectPool() { 053 _pool = new ArrayList(); 054 _factory = null; 055 } 056 057 /** 058 * Create a <code>SoftReferenceObjectPool</code> with the specified factory. 059 * 060 * @param factory object factory to use. 061 */ 062 public SoftReferenceObjectPool(PoolableObjectFactory factory) { 063 _pool = new ArrayList(); 064 _factory = factory; 065 } 066 067 /** 068 * Create a <code>SoftReferenceObjectPool</code> with the specified factory and initial idle object count. 069 * 070 * @param factory object factory to use. 071 * @param initSize initial size to attempt to prefill the pool. 072 * @throws Exception when there is a problem prefilling the pool. 073 * @throws IllegalArgumentException when <code>factory</code> is <code>null</code>. 074 * @deprecated because this is a SoftReference pool, prefilled idle obejects may be garbage collected before they are used. 075 * To be removed in Pool 2.0. 076 */ 077 public SoftReferenceObjectPool(PoolableObjectFactory factory, int initSize) throws Exception, IllegalArgumentException { 078 if (factory == null) { 079 throw new IllegalArgumentException("factory required to prefill the pool."); 080 } 081 _pool = new ArrayList(initSize); 082 _factory = factory; 083 PoolUtils.prefill(this, initSize); 084 } 085 086 /** 087 * <p>Borrow an object from the pool. If there are no idle instances available in the pool, the configured 088 * factory's {@link PoolableObjectFactory#makeObject()} method is invoked to create a new instance.</p> 089 * 090 * <p>All instances are {@link PoolableObjectFactory#activateObject(Object) activated} and 091 * {@link PoolableObjectFactory#validateObject(Object) validated} before being returned by this 092 * method. If validation fails or an exception occurs activating or validating an idle instance, 093 * the failing instance is {@link PoolableObjectFactory#destroyObject(Object) destroyed} and another 094 * instance is retrieved from the pool, validated and activated. This process continues until either the 095 * pool is empty or an instance passes validation. If the pool is empty on activation or 096 * it does not contain any valid instances, the factory's <code>makeObject</code> method is used 097 * to create a new instance. If the created instance either raises an exception on activation or 098 * fails validation, <code>NoSuchElementException</code> is thrown. Exceptions thrown by <code>MakeObject</code> 099 * 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 assertOpen(); 109 Object obj = null; 110 boolean newlyCreated = false; 111 while(null == obj) { 112 if(_pool.isEmpty()) { 113 if(null == _factory) { 114 throw new NoSuchElementException(); 115 } else { 116 newlyCreated = true; 117 obj = _factory.makeObject(); 118 } 119 } else { 120 SoftReference ref = (SoftReference)(_pool.remove(_pool.size() - 1)); 121 obj = ref.get(); 122 ref.clear(); // prevent this ref from being enqueued with refQueue. 123 } 124 if (null != _factory && null != obj) { 125 try { 126 _factory.activateObject(obj); 127 if (!_factory.validateObject(obj)) { 128 throw new Exception("ValidateObject failed"); 129 } 130 } catch (Throwable t) { 131 PoolUtils.checkRethrow(t); 132 try { 133 _factory.destroyObject(obj); 134 } catch (Throwable t2) { 135 PoolUtils.checkRethrow(t2); 136 // Swallowed 137 } finally { 138 obj = null; 139 } 140 if (newlyCreated) { 141 throw new NoSuchElementException( 142 "Could not create a validated object, cause: " + 143 t.getMessage()); 144 } 145 } 146 } 147 } 148 _numActive++; 149 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 boolean success = !isClosed(); 168 if (_factory != null) { 169 if(!_factory.validateObject(obj)) { 170 success = false; 171 } else { 172 try { 173 _factory.passivateObject(obj); 174 } catch(Exception e) { 175 success = false; 176 } 177 } 178 } 179 180 boolean shouldDestroy = !success; 181 _numActive--; 182 if(success) { 183 _pool.add(new SoftReference(obj, refQueue)); 184 } 185 notifyAll(); // _numActive has changed 186 187 if (shouldDestroy && _factory != null) { 188 try { 189 _factory.destroyObject(obj); 190 } catch(Exception e) { 191 // ignored 192 } 193 } 194 } 195 196 /** 197 * {@inheritDoc} 198 */ 199 public synchronized void invalidateObject(Object obj) throws Exception { 200 _numActive--; 201 if (_factory != null) { 202 _factory.destroyObject(obj); 203 } 204 notifyAll(); // _numActive has changed 205 } 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 assertOpen(); 223 if (_factory == null) { 224 throw new IllegalStateException("Cannot add objects without a factory."); 225 } 226 Object obj = _factory.makeObject(); 227 228 boolean success = true; 229 if(!_factory.validateObject(obj)) { 230 success = false; 231 } else { 232 _factory.passivateObject(obj); 233 } 234 235 boolean shouldDestroy = !success; 236 if(success) { 237 _pool.add(new SoftReference(obj, refQueue)); 238 notifyAll(); // _numActive has changed 239 } 240 241 if(shouldDestroy) { 242 try { 243 _factory.destroyObject(obj); 244 } catch(Exception e) { 245 // ignored 246 } 247 } 248 } 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 pruneClearedReferences(); 257 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 return _numActive; 267 } 268 269 /** 270 * Clears any objects sitting idle in the pool. 271 */ 272 public synchronized void clear() { 273 if(null != _factory) { 274 Iterator iter = _pool.iterator(); 275 while(iter.hasNext()) { 276 try { 277 Object obj = ((SoftReference)iter.next()).get(); 278 if(null != obj) { 279 _factory.destroyObject(obj); 280 } 281 } catch(Exception e) { 282 // ignore error, keep destroying the rest 283 } 284 } 285 } 286 _pool.clear(); 287 pruneClearedReferences(); 288 } 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 super.close(); 302 clear(); 303 } 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 assertOpen(); 317 if(0 < getNumActive()) { 318 throw new IllegalStateException("Objects are already active"); 319 } else { 320 clear(); 321 _factory = factory; 322 } 323 } 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 while ((ref = refQueue.poll()) != null) { 332 try { 333 _pool.remove(ref); 334 } catch (UnsupportedOperationException uoe) { 335 // ignored 336 } 337 } 338 } 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 return _factory; 348 } 349 350 /** My pool. */ 351 private final List _pool; 352 353 /** My {@link PoolableObjectFactory}. */ 354 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 private final ReferenceQueue refQueue = new ReferenceQueue(); 362 363 /** Number of active objects. */ 364 private int _numActive = 0; //@GuardeBy("this") 365 }