1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.commons.pool.impl;
19
20 import java.util.Iterator;
21 import java.util.NoSuchElementException;
22 import java.util.Stack;
23
24 import org.apache.commons.pool.BaseObjectPool;
25 import org.apache.commons.pool.ObjectPool;
26 import org.apache.commons.pool.PoolableObjectFactory;
27
28 /***
29 * A simple, {@link java.util.Stack Stack}-based {@link ObjectPool} implementation.
30 * <p>
31 * Given a {@link PoolableObjectFactory}, this class will maintain
32 * a simple pool of instances. A finite number of "sleeping"
33 * or idle instances is enforced, but when the pool is
34 * empty, new instances are created to support the new load.
35 * Hence this class places no limit on the number of "active"
36 * instances created by the pool, but is quite useful for
37 * re-using <tt>Object</tt>s without introducing
38 * artificial limits.
39 *
40 * @author Rodney Waldhoff
41 * @author Dirk Verbeeck
42 * @author Sandy McArthur
43 * @version $Revision: 607137 $ $Date: 2007-12-27 16:06:49 -0700 (Thu, 27 Dec 2007) $
44 * @since Pool 1.0
45 */
46 public class StackObjectPool extends BaseObjectPool implements ObjectPool {
47 /***
48 * Create a new pool using
49 * no factory.
50 * Clients must first {@link #setFactory(PoolableObjectFactory) set the factory}
51 * else this pool will not behave correctly.
52 * Clients may first populate the pool
53 * using {@link #returnObject(java.lang.Object)}
54 * before they can be {@link #borrowObject borrowed} but this useage is <strong>discouraged</strong>.
55 *
56 * @see #StackObjectPool(PoolableObjectFactory)
57 */
58 public StackObjectPool() {
59 this((PoolableObjectFactory)null,DEFAULT_MAX_SLEEPING,DEFAULT_INIT_SLEEPING_CAPACITY);
60 }
61
62 /***
63 * Create a new pool using
64 * no factory.
65 * Clients must first {@link #setFactory(PoolableObjectFactory) set the factory}
66 * else this pool will not behave correctly.
67 * Clients may first populate the pool
68 * using {@link #returnObject(java.lang.Object)}
69 * before they can be {@link #borrowObject borrowed} but this useage is <strong>discouraged</strong>.
70 *
71 * @param maxIdle cap on the number of "sleeping" instances in the pool
72 * @see #StackObjectPool(PoolableObjectFactory, int)
73 */
74 public StackObjectPool(int maxIdle) {
75 this((PoolableObjectFactory)null,maxIdle,DEFAULT_INIT_SLEEPING_CAPACITY);
76 }
77
78 /***
79 * Create a new pool using
80 * no factory.
81 * Clients must first {@link #setFactory(PoolableObjectFactory) set the factory}
82 * else this pool will not behave correctly.
83 * Clients may first populate the pool
84 * using {@link #returnObject(java.lang.Object)}
85 * before they can be {@link #borrowObject borrowed} but this useage is <strong>discouraged</strong>.
86 *
87 * @param maxIdle cap on the number of "sleeping" instances in the pool
88 * @param initIdleCapacity initial size of the pool (this specifies the size of the container,
89 * it does not cause the pool to be pre-populated.)
90 * @see #StackObjectPool(PoolableObjectFactory, int, int)
91 */
92 public StackObjectPool(int maxIdle, int initIdleCapacity) {
93 this((PoolableObjectFactory)null,maxIdle,initIdleCapacity);
94 }
95
96 /***
97 * Create a new <tt>StackObjectPool</tt> using
98 * the specified <i>factory</i> to create new instances.
99 *
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
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);
204 }
205 _pool.push(obj);
206 obj = toBeDestroyed;
207 }
208 notifyAll();
209
210 if(shouldDestroy) {
211 try {
212 _factory.destroyObject(obj);
213 } catch(Exception e) {
214
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();
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
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);
304 }
305 _pool.push(obj);
306 obj = toBeDestroyed;
307 }
308 notifyAll();
309
310 if(shouldDestroy) {
311 try {
312 _factory.destroyObject(obj);
313 } catch(Exception e) {
314
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 }