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.Iterator; 021 import java.util.NoSuchElementException; 022 import java.util.Stack; 023 024 import org.apache.commons.pool.BaseObjectPool; 025 import org.apache.commons.pool.ObjectPool; 026 import org.apache.commons.pool.PoolableObjectFactory; 027 028 /** 029 * A simple, {@link java.util.Stack Stack}-based {@link ObjectPool} implementation. 030 * <p> 031 * Given a {@link PoolableObjectFactory}, this class will maintain 032 * a simple pool of instances. A finite number of "sleeping" 033 * or idle instances is enforced, but when the pool is 034 * empty, new instances are created to support the new load. 035 * Hence this class places no limit on the number of "active" 036 * instances created by the pool, but is quite useful for 037 * re-using <tt>Object</tt>s without introducing 038 * artificial limits. 039 * 040 * @author Rodney Waldhoff 041 * @author Dirk Verbeeck 042 * @author Sandy McArthur 043 * @version $Revision: 777748 $ $Date: 2009-05-22 20:00:44 -0400 (Fri, 22 May 2009) $ 044 * @since Pool 1.0 045 */ 046 public class StackObjectPool extends BaseObjectPool implements ObjectPool { 047 /** 048 * Create a new pool using 049 * no factory. 050 * Clients must first {@link #setFactory(PoolableObjectFactory) set the factory} 051 * else this pool will not behave correctly. 052 * Clients may first populate the pool 053 * using {@link #returnObject(java.lang.Object)} 054 * before they can be {@link #borrowObject borrowed} but this useage is <strong>discouraged</strong>. 055 * 056 * @see #StackObjectPool(PoolableObjectFactory) 057 */ 058 public StackObjectPool() { 059 this((PoolableObjectFactory)null,DEFAULT_MAX_SLEEPING,DEFAULT_INIT_SLEEPING_CAPACITY); 060 } 061 062 /** 063 * Create a new pool using 064 * no factory. 065 * Clients must first {@link #setFactory(PoolableObjectFactory) set the factory} 066 * else this pool will not behave correctly. 067 * Clients may first populate the pool 068 * using {@link #returnObject(java.lang.Object)} 069 * before they can be {@link #borrowObject borrowed} but this useage is <strong>discouraged</strong>. 070 * 071 * @param maxIdle cap on the number of "sleeping" instances in the pool 072 * @see #StackObjectPool(PoolableObjectFactory, int) 073 */ 074 public StackObjectPool(int maxIdle) { 075 this((PoolableObjectFactory)null,maxIdle,DEFAULT_INIT_SLEEPING_CAPACITY); 076 } 077 078 /** 079 * Create a new pool using 080 * no factory. 081 * Clients must first {@link #setFactory(PoolableObjectFactory) set the factory} 082 * else this pool will not behave correctly. 083 * Clients may first populate the pool 084 * using {@link #returnObject(java.lang.Object)} 085 * before they can be {@link #borrowObject borrowed} but this useage is <strong>discouraged</strong>. 086 * 087 * @param maxIdle cap on the number of "sleeping" instances in the pool 088 * @param initIdleCapacity 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 #StackObjectPool(PoolableObjectFactory, int, int) 091 */ 092 public StackObjectPool(int maxIdle, int initIdleCapacity) { 093 this((PoolableObjectFactory)null,maxIdle,initIdleCapacity); 094 } 095 096 /** 097 * Create a new <tt>StackObjectPool</tt> using 098 * the specified <i>factory</i> to create new instances. 099 * 100 * @param factory the {@link PoolableObjectFactory} used to populate the pool 101 */ 102 public StackObjectPool(PoolableObjectFactory factory) { 103 this(factory,DEFAULT_MAX_SLEEPING,DEFAULT_INIT_SLEEPING_CAPACITY); 104 } 105 106 /** 107 * Create a new <tt>SimpleObjectPool</tt> using 108 * the specified <i>factory</i> to create new instances, 109 * capping the number of "sleeping" instances to <i>max</i>. 110 * 111 * @param factory the {@link PoolableObjectFactory} used to populate the pool 112 * @param maxIdle cap on the number of "sleeping" instances in the pool 113 */ 114 public StackObjectPool(PoolableObjectFactory factory, int maxIdle) { 115 this(factory,maxIdle,DEFAULT_INIT_SLEEPING_CAPACITY); 116 } 117 118 /** 119 * Create a new <tt>SimpleObjectPool</tt> using 120 * the specified <i>factory</i> to create new instances, 121 * capping the number of "sleeping" instances to <i>max</i>, 122 * and initially allocating a container capable of containing 123 * at least <i>init</i> instances. 124 * 125 * @param factory the {@link PoolableObjectFactory} used to populate the pool 126 * @param maxIdle cap on the number of "sleeping" instances in the pool 127 * @param initIdleCapacity initial size of the pool (this specifies the size of the container, 128 * it does not cause the pool to be pre-populated.) 129 */ 130 public StackObjectPool(PoolableObjectFactory factory, int maxIdle, int initIdleCapacity) { 131 _factory = factory; 132 _maxSleeping = (maxIdle < 0 ? DEFAULT_MAX_SLEEPING : maxIdle); 133 int initcapacity = (initIdleCapacity < 1 ? DEFAULT_INIT_SLEEPING_CAPACITY : initIdleCapacity); 134 _pool = new Stack(); 135 _pool.ensureCapacity( initcapacity > _maxSleeping ? _maxSleeping : initcapacity); 136 } 137 138 public synchronized Object borrowObject() throws Exception { 139 assertOpen(); 140 Object obj = null; 141 boolean newlyCreated = false; 142 while (null == obj) { 143 if (!_pool.empty()) { 144 obj = _pool.pop(); 145 } else { 146 if(null == _factory) { 147 throw new NoSuchElementException(); 148 } else { 149 obj = _factory.makeObject(); 150 newlyCreated = true; 151 if (obj == null) { 152 throw new NoSuchElementException("PoolableObjectFactory.makeObject() returned null."); 153 } 154 } 155 } 156 if (null != _factory && null != obj) { 157 try { 158 _factory.activateObject(obj); 159 if (!_factory.validateObject(obj)) { 160 throw new Exception("ValidateObject failed"); 161 } 162 } catch (Throwable t) { 163 try { 164 _factory.destroyObject(obj); 165 } catch (Throwable t2) { 166 // swallowed 167 } finally { 168 obj = null; 169 } 170 if (newlyCreated) { 171 throw new NoSuchElementException( 172 "Could not create a validated object, cause: " + 173 t.getMessage()); 174 } 175 } 176 } 177 } 178 _numActive++; 179 return obj; 180 } 181 182 public synchronized void returnObject(Object obj) throws Exception { 183 boolean success = !isClosed(); 184 if(null != _factory) { 185 if(!_factory.validateObject(obj)) { 186 success = false; 187 } else { 188 try { 189 _factory.passivateObject(obj); 190 } catch(Exception e) { 191 success = false; 192 } 193 } 194 } 195 196 boolean shouldDestroy = !success; 197 198 _numActive--; 199 if (success) { 200 Object toBeDestroyed = null; 201 if(_pool.size() >= _maxSleeping) { 202 shouldDestroy = true; 203 toBeDestroyed = _pool.remove(0); // remove the stalest object 204 } 205 _pool.push(obj); 206 obj = toBeDestroyed; // swap returned obj with the stalest one so it can be destroyed 207 } 208 notifyAll(); // _numActive has changed 209 210 if(shouldDestroy) { // by constructor, shouldDestroy is false when _factory is null 211 try { 212 _factory.destroyObject(obj); 213 } catch(Exception e) { 214 // ignored 215 } 216 } 217 } 218 219 public synchronized void invalidateObject(Object obj) throws Exception { 220 _numActive--; 221 if (null != _factory) { 222 _factory.destroyObject(obj); 223 } 224 notifyAll(); // _numActive has changed 225 } 226 227 /** 228 * Return the number of instances 229 * currently idle in this pool. 230 * 231 * @return the number of instances currently idle in this pool 232 */ 233 public synchronized int getNumIdle() { 234 return _pool.size(); 235 } 236 237 /** 238 * Return the number of instances currently borrowed from this pool. 239 * 240 * @return the number of instances currently borrowed from this pool 241 */ 242 public synchronized int getNumActive() { 243 return _numActive; 244 } 245 246 /** 247 * Clears any objects sitting idle in the pool. 248 */ 249 public synchronized void clear() { 250 if(null != _factory) { 251 Iterator it = _pool.iterator(); 252 while(it.hasNext()) { 253 try { 254 _factory.destroyObject(it.next()); 255 } catch(Exception e) { 256 // ignore error, keep destroying the rest 257 } 258 } 259 } 260 _pool.clear(); 261 } 262 263 /** 264 * Close this pool, and free any resources associated with it. 265 * <p> 266 * Calling {@link #addObject} or {@link #borrowObject} after invoking 267 * this method on a pool will cause them to throw an 268 * {@link IllegalStateException}. 269 * </p> 270 * 271 * @throws Exception <strong>deprecated</strong>: implementations should silently fail if not all resources can be freed. 272 */ 273 public void close() throws Exception { 274 super.close(); 275 clear(); 276 } 277 278 /** 279 * Create an object, and place it into the pool. 280 * addObject() is useful for "pre-loading" a pool with idle objects. 281 * @throws Exception when the {@link #_factory} has a problem creating an object. 282 */ 283 public synchronized void addObject() throws Exception { 284 assertOpen(); 285 if (_factory == null) { 286 throw new IllegalStateException("Cannot add objects without a factory."); 287 } 288 Object obj = _factory.makeObject(); 289 290 boolean success = true; 291 if(!_factory.validateObject(obj)) { 292 success = false; 293 } else { 294 _factory.passivateObject(obj); 295 } 296 297 boolean shouldDestroy = !success; 298 299 if (success) { 300 Object toBeDestroyed = null; 301 if(_pool.size() >= _maxSleeping) { 302 shouldDestroy = true; 303 toBeDestroyed = _pool.remove(0); // remove the stalest object 304 } 305 _pool.push(obj); 306 obj = toBeDestroyed; // swap returned obj with the stalest one so it can be destroyed 307 } 308 notifyAll(); // _numIdle has changed 309 310 if(shouldDestroy) { // by constructor, shouldDestroy is false when _factory is null 311 try { 312 _factory.destroyObject(obj); 313 } catch(Exception e) { 314 // ignored 315 } 316 } 317 } 318 319 /** 320 * Sets the {@link PoolableObjectFactory factory} this pool uses 321 * to create new instances. Trying to change 322 * the <code>factory</code> while there are borrowed objects will 323 * throw an {@link IllegalStateException}. 324 * 325 * @param factory the {@link PoolableObjectFactory} used to create new instances. 326 * @throws IllegalStateException when the factory cannot be set at this time 327 */ 328 public synchronized void setFactory(PoolableObjectFactory factory) throws IllegalStateException { 329 assertOpen(); 330 if(0 < getNumActive()) { 331 throw new IllegalStateException("Objects are already active"); 332 } else { 333 clear(); 334 _factory = factory; 335 } 336 } 337 338 /** The default cap on the number of "sleeping" instances in the pool. */ 339 protected static final int DEFAULT_MAX_SLEEPING = 8; 340 341 /** 342 * The default initial size of the pool 343 * (this specifies the size of the container, it does not 344 * cause the pool to be pre-populated.) 345 */ 346 protected static final int DEFAULT_INIT_SLEEPING_CAPACITY = 4; 347 348 /** My pool. */ 349 protected Stack _pool = null; 350 351 /** My {@link PoolableObjectFactory}. */ 352 protected PoolableObjectFactory _factory = null; 353 354 /** The cap on the number of "sleeping" instances in the pool. */ 355 protected int _maxSleeping = DEFAULT_MAX_SLEEPING; 356 357 /** Number of object borrowed but not yet returned to the pool. */ 358 protected int _numActive = 0; 359 }