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