View Javadoc

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.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.PoolUtils;
27  import org.apache.commons.pool.PoolableObjectFactory;
28  
29  /**
30   * A simple, {@link java.util.Stack Stack}-based {@link ObjectPool} implementation.
31   * <p>
32   * Given a {@link PoolableObjectFactory}, this class will maintain
33   * a simple pool of instances.  A finite number of "sleeping"
34   * or idle 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 <tt>Object</tt>s without introducing
39   * artificial limits.
40   *
41   * @param <T> the type of objects held in this pool
42   * 
43   * @author Rodney Waldhoff
44   * @author Dirk Verbeeck
45   * @author Sandy McArthur
46   * @version $Revision: 1222396 $ $Date: 2011-12-22 14:02:25 -0500 (Thu, 22 Dec 2011) $
47   * @since Pool 1.0
48   */
49  public class StackObjectPool<T> extends BaseObjectPool<T> implements ObjectPool<T> {
50      /**
51       * Create a new pool using no factory. Clients must first 
52       * {@link #setFactory(PoolableObjectFactory) set the factory} or
53       * else this pool will not behave correctly. Clients may first populate the pool
54       * using {@link #returnObject(java.lang.Object)} before they can be {@link #borrowObject borrowed}
55       * but this usage is <strong>discouraged</strong>.
56       *
57       * @see #StackObjectPool(PoolableObjectFactory)
58       * @deprecated to be removed in pool 2.0 - use {@link #StackObjectPool(PoolableObjectFactory)}
59       */
60      @Deprecated
61      public StackObjectPool() {
62          this(null,DEFAULT_MAX_SLEEPING,DEFAULT_INIT_SLEEPING_CAPACITY);
63      }
64  
65      /**
66       * Create a new pool using no factory.
67       * Clients must first {@link #setFactory(PoolableObjectFactory) set the factory} or
68       * else this pool will not behave correctly. Clients may first populate the pool
69       * using {@link #returnObject(java.lang.Object)} before they can be {@link #borrowObject borrowed}
70       * but this usage is <strong>discouraged</strong>.
71       *
72       * @param maxIdle cap on the number of "sleeping" instances in the pool
73       * @see #StackObjectPool(PoolableObjectFactory, int)
74       * @deprecated to be removed in pool 2.0 - use {@link #StackObjectPool(PoolableObjectFactory, int)}
75       */
76      @Deprecated
77      public StackObjectPool(int maxIdle) {
78          this(null,maxIdle,DEFAULT_INIT_SLEEPING_CAPACITY);
79      }
80  
81      /**
82       * Create a new pool using no factory.
83       * Clients must first {@link #setFactory(PoolableObjectFactory) set the factory} or
84       * else this pool will not behave correctly. Clients may first populate the pool
85       * using {@link #returnObject(java.lang.Object)} before they can be {@link #borrowObject borrowed}
86       * but this usage is <strong>discouraged</strong>.
87       *
88       * @param maxIdle cap on the number of "sleeping" instances in the pool
89       * @param initIdleCapacity initial size of the pool (this specifies the size of the container,
90       *             it does not cause the pool to be pre-populated.)
91       * @see #StackObjectPool(PoolableObjectFactory, int, int)
92       * @deprecated to be removed in pool 2.0 - use {@link #StackObjectPool(PoolableObjectFactory, int, int)}
93       */
94      @Deprecated
95      public StackObjectPool(int maxIdle, int initIdleCapacity) {
96          this(null,maxIdle,initIdleCapacity);
97      }
98  
99      /**
100      * Create a new <tt>StackObjectPool</tt> using the specified <i>factory</i> to create new instances.
101      *
102      * @param factory the {@link PoolableObjectFactory} used to populate the pool
103      */
104     public StackObjectPool(PoolableObjectFactory<T> factory) {
105         this(factory,DEFAULT_MAX_SLEEPING,DEFAULT_INIT_SLEEPING_CAPACITY);
106     }
107 
108     /**
109      * Create a new <tt>SimpleObjectPool</tt> using the specified <i>factory</i> to create new instances,
110      * capping the number of "sleeping" instances to <i>maxIdle</i>.
111      *
112      * @param factory the {@link PoolableObjectFactory} used to populate the pool
113      * @param maxIdle cap on the number of "sleeping" instances in the pool
114      */
115     public StackObjectPool(PoolableObjectFactory<T> factory, int maxIdle) {
116         this(factory,maxIdle,DEFAULT_INIT_SLEEPING_CAPACITY);
117     }
118 
119     /**
120      * <p>Create a new <tt>StackObjectPool</tt> using the specified <code>factory</code> to create new instances,
121      * capping the number of "sleeping" instances to <code>maxIdle</code>, and initially allocating a container
122      * capable of containing at least <code>initIdleCapacity</code> instances.  The pool is not pre-populated.
123      * The <code>initIdleCapacity</code> parameter just determines the initial size of the underlying
124      * container, which can increase beyond this value if <code>maxIdle &gt; initIdleCapacity.</code></p>
125      * 
126      * <p>Negative values of <code>maxIdle</code> are ignored (i.e., the pool is created using
127      * {@link #DEFAULT_MAX_SLEEPING}) as are non-positive values for <code>initIdleCapacity.</code>
128      *
129      * @param factory the {@link PoolableObjectFactory} used to populate the pool
130      * @param maxIdle cap on the number of "sleeping" instances in the pool
131      * @param initIdleCapacity initial size of the pool (this specifies the size of the container,
132      *             it does not cause the pool to be pre-populated.)
133      */
134     public StackObjectPool(PoolableObjectFactory<T> factory, int maxIdle, int initIdleCapacity) {
135         _factory = factory;
136         _maxSleeping = (maxIdle < 0 ? DEFAULT_MAX_SLEEPING : maxIdle);
137         int initcapacity = (initIdleCapacity < 1 ? DEFAULT_INIT_SLEEPING_CAPACITY : initIdleCapacity);
138         _pool = new Stack<T>();
139         _pool.ensureCapacity( initcapacity > _maxSleeping ? _maxSleeping : initcapacity);
140     }
141 
142     /**
143      * <p>Borrows an object from the pool.  If there are idle instances available on the stack,
144      * the top element of the stack is popped to activate, validate and return to the client.  If there
145      * are no idle instances available, the {@link PoolableObjectFactory#makeObject() makeObject} 
146      * method of the pool's {@link PoolableObjectFactory} is invoked to create a new instance.</p>
147      * 
148      * <p>All instances are {@link PoolableObjectFactory#activateObject(Object) activated} and
149      * {@link PoolableObjectFactory#validateObject(Object) validated} before being returned to the
150      * client.  If validation fails or an exception occurs activating or validating an instance 
151      * popped from the idle instance stack, the failing instance is 
152      * {@link PoolableObjectFactory#destroyObject(Object) destroyed} and the next instance on
153      * the stack is popped, validated and activated.  This process continues until either the
154      * stack is empty or an instance passes validation.  If the stack is empty on activation or
155      * it does not contain any valid instances, the factory's <code>makeObject</code> method is used
156      * to create a new instance.  If a null instance is returned by the factory or the created
157      * instance either raises an exception on activation or fails validation, <code>NoSuchElementException</code>
158      * is thrown. Exceptions thrown by <code>MakeObject</code> are propagated to the caller; but 
159      * other than <code>ThreadDeath</code> or <code>VirtualMachineError</code>, exceptions generated by
160      * activation, validation or destroy methods are swallowed silently.</p>
161      * 
162      * @return an instance from the pool
163      */
164     @Override
165     public synchronized T borrowObject() throws Exception {
166         assertOpen();
167         T obj = null;
168         boolean newlyCreated = false;
169         while (null == obj) {
170             if (!_pool.empty()) {
171                 obj = _pool.pop();
172             } else {
173                 if(null == _factory) {
174                     throw new NoSuchElementException();
175                 } else {
176                     obj = _factory.makeObject();
177                     newlyCreated = true;
178                   if (obj == null) {
179                     throw new NoSuchElementException("PoolableObjectFactory.makeObject() returned null.");
180                   }
181                 }
182             }
183             if (null != _factory && null != obj) {
184                 try {
185                     _factory.activateObject(obj);
186                     if (!_factory.validateObject(obj)) {
187                         throw new Exception("ValidateObject failed");
188                     }
189                 } catch (Throwable t) {
190                     PoolUtils.checkRethrow(t);
191                     try {
192                         _factory.destroyObject(obj);
193                     } catch (Throwable t2) {
194                         PoolUtils.checkRethrow(t2);
195                         // swallowed
196                     } finally {
197                         obj = null;
198                     }
199                     if (newlyCreated) {
200                         throw new NoSuchElementException(
201                             "Could not create a validated object, cause: " +
202                             t.getMessage());
203                     }
204                 }
205             }
206         }
207         _numActive++;
208         return obj;
209     }
210 
211     /**
212      * <p>Returns an instance to the pool, pushing it on top of the idle instance stack after successful
213      * validation and passivation. The returning instance is destroyed if any of the following are true:<ul>
214      *   <li>the pool is closed</li>
215      *   <li>{@link PoolableObjectFactory#validateObject(Object) validation} fails</li>
216      *   <li>{@link PoolableObjectFactory#passivateObject(Object) passivation} throws an exception</li>
217      * </ul>
218      * If adding a validated, passivated returning instance to the stack would cause
219      * {@link #getMaxSleeping() maxSleeping} to be exceeded, the oldest (bottom) instance on the stack
220      * is destroyed to make room for the returning instance, which is pushed on top of the stack.</p>
221      * 
222      * <p>Exceptions passivating or destroying instances are silently swallowed.  Exceptions validating
223      * instances are propagated to the client.</p>
224      * 
225      * @param obj instance to return to the pool
226      */
227     @Override
228     public synchronized void returnObject(T obj) throws Exception {
229         boolean success = !isClosed();
230         if(null != _factory) {
231             if(!_factory.validateObject(obj)) {
232                 success = false;
233             } else {
234                 try {
235                     _factory.passivateObject(obj);
236                 } catch(Exception e) {
237                     success = false;
238                 }
239             }
240         }
241 
242         boolean shouldDestroy = !success;
243 
244         _numActive--;
245         if (success) {
246             T toBeDestroyed = null;
247             if(_pool.size() >= _maxSleeping) {
248                 shouldDestroy = true;
249                 toBeDestroyed = _pool.remove(0); // remove the stalest object
250             }
251             _pool.push(obj);
252             obj = toBeDestroyed; // swap returned obj with the stalest one so it can be destroyed
253         }
254         notifyAll(); // _numActive has changed
255 
256         if(shouldDestroy) { // by constructor, shouldDestroy is false when _factory is null
257             try {
258                 _factory.destroyObject(obj);
259             } catch(Exception e) {
260                 // ignored
261             }
262         }
263     }
264 
265     /**
266      * {@inheritDoc}
267      */
268     @Override
269     public synchronized void invalidateObject(T obj) throws Exception {
270         _numActive--;
271         if (null != _factory) {
272             _factory.destroyObject(obj);
273         }
274         notifyAll(); // _numActive has changed
275     }
276 
277     /**
278      * Return the number of instances
279      * currently idle in this pool.
280      *
281      * @return the number of instances currently idle in this pool
282      */
283     @Override
284     public synchronized int getNumIdle() {
285         return _pool.size();
286     }
287 
288     /**
289      * Return the number of instances currently borrowed from this pool.
290      *
291      * @return the number of instances currently borrowed from this pool
292      */
293     @Override
294     public synchronized int getNumActive() {
295         return _numActive;
296     }
297 
298     /**
299      * Clears any objects sitting idle in the pool. Silently swallows any
300      * exceptions thrown by {@link PoolableObjectFactory#destroyObject(Object)}.
301      */
302     @Override
303     public synchronized void clear() {
304         if(null != _factory) {
305             Iterator<T> it = _pool.iterator();
306             while(it.hasNext()) {
307                 try {
308                     _factory.destroyObject(it.next());
309                 } catch(Exception e) {
310                     // ignore error, keep destroying the rest
311                 }
312             }
313         }
314         _pool.clear();
315     }
316 
317     /**
318      * <p>Close this pool, and free any resources associated with it. Invokes
319      * {@link #clear()} to destroy and remove instances in the pool.</p>
320      * 
321      * <p>Calling {@link #addObject} or {@link #borrowObject} after invoking
322      * this method on a pool will cause them to throw an
323      * {@link IllegalStateException}.</p>
324      *
325      * @throws Exception never - exceptions clearing the pool are swallowed
326      */
327     @Override
328     public void close() throws Exception {
329         super.close();
330         clear();
331     }
332 
333     /**
334      * <p>Create an object, and place it on top of the stack.
335      * This method is useful for "pre-loading" a pool with idle objects.</p>
336      * 
337      * <p>Before being added to the pool, the newly created instance is
338      * {@link PoolableObjectFactory#validateObject(Object) validated} and 
339      * {@link PoolableObjectFactory#passivateObject(Object) passivated}.  If validation
340      * fails, the new instance is {@link PoolableObjectFactory#destroyObject(Object) destroyed}.
341      * Exceptions generated by the factory <code>makeObject</code> or <code>passivate</code> are
342      * propagated to the caller. Exceptions destroying instances are silently swallowed.</p>
343      * 
344      * <p>If a new instance is created and successfully validated and passivated and adding this
345      * instance to the pool causes {@link #getMaxSleeping() maxSleeping} to be exceeded, the oldest
346      * (bottom) instance in the pool is destroyed to make room for the newly created instance, which
347      * is pushed on top of the stack.
348      * 
349      * @throws Exception when the {@link #getFactory() factory} has a problem creating or passivating an object.
350      */
351     @Override
352     public synchronized void addObject() throws Exception {
353         assertOpen();
354         if (_factory == null) {
355             throw new IllegalStateException("Cannot add objects without a factory.");
356         }
357         T obj = _factory.makeObject();
358 
359         boolean success = true;
360         if(!_factory.validateObject(obj)) {
361             success = false;
362         } else {
363             _factory.passivateObject(obj);
364         }
365 
366         boolean shouldDestroy = !success;
367 
368         if (success) {
369             T toBeDestroyed = null;
370             if(_pool.size() >= _maxSleeping) {
371                 shouldDestroy = true;
372                 toBeDestroyed = _pool.remove(0); // remove the stalest object
373             }
374             _pool.push(obj);
375             obj = toBeDestroyed; // swap returned obj with the stalest one so it can be destroyed
376         }
377         notifyAll(); // _numIdle has changed
378 
379         if(shouldDestroy) { // by constructor, shouldDestroy is false when _factory is null
380             try {
381                 _factory.destroyObject(obj);
382             } catch(Exception e) {
383                 // ignored
384             }
385         }
386     }
387 
388     /**
389      * Sets the {@link PoolableObjectFactory factory} this pool uses
390      * to create new instances. Trying to change
391      * the <code>factory</code> while there are borrowed objects will
392      * throw an {@link IllegalStateException}.
393      *
394      * @param factory the {@link PoolableObjectFactory} used to create new instances.
395      * @throws IllegalStateException when the factory cannot be set at this time
396      * @deprecated to be removed in pool 2.0
397      */
398     @Deprecated
399     @Override
400     public synchronized void setFactory(PoolableObjectFactory<T> factory) throws IllegalStateException {
401         assertOpen();
402         if(0 < getNumActive()) {
403             throw new IllegalStateException("Objects are already active");
404         } else {
405             clear();
406             _factory = factory;
407         }
408     }
409 
410     /**
411      * The cap on the number of "sleeping" instances in the pool.
412      */
413     protected static final int DEFAULT_MAX_SLEEPING  = 8;
414 
415     /**
416      * The default initial size of the pool
417      * (this specifies the size of the container, it does not
418      * cause the pool to be pre-populated.)
419      */
420     protected static final int DEFAULT_INIT_SLEEPING_CAPACITY = 4;
421 
422     /** 
423      * My pool.
424      * @deprecated to be made private in pool 2.0 
425      */
426     @Deprecated
427     protected Stack<T> _pool = null;
428 
429     /** 
430      * My {@link PoolableObjectFactory}.
431      * @deprecated to be made private in pool 2.0 - use {@link #getFactory()}
432      */
433     @Deprecated
434     protected PoolableObjectFactory<T> _factory = null;
435 
436     /** 
437      * The cap on the number of "sleeping" instances in the pool. 
438      * @deprecated to be made private in pool 2.0 - use {@link #getMaxSleeping()}
439      */
440     @Deprecated
441     protected int _maxSleeping = DEFAULT_MAX_SLEEPING;
442     
443     /**
444      * Number of objects borrowed but not yet returned to the pool.
445      * @deprecated to be made private in pool 2.0 - use {@link #getNumActive()}
446      */
447     @Deprecated
448     protected int _numActive = 0;
449 
450     /**
451      * Returns the {@link PoolableObjectFactory} used by this pool to create and manage object instances.
452      * 
453      * @return the factory
454      * @since 1.5.5
455      */
456     public synchronized PoolableObjectFactory<T> getFactory() {
457         return _factory;
458     }
459 
460     /**
461      * Returns the maximum number of idle instances in the pool.
462      * 
463      * @return maxSleeping
464      * @since 1.5.5
465      */
466     public int getMaxSleeping() {
467         return _maxSleeping;
468     }
469 
470    
471 }