View Javadoc

1   /*
2    * Copyright 1999-2004 The Apache Software Foundation.
3    * 
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    * 
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    * 
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package org.apache.commons.pool.impl;
18  
19  import java.util.Iterator;
20  import java.util.NoSuchElementException;
21  import java.util.Stack;
22  
23  import org.apache.commons.pool.BaseObjectPool;
24  import org.apache.commons.pool.ObjectPool;
25  import org.apache.commons.pool.PoolableObjectFactory;
26  
27  /***
28   * A simple, {@link java.util.Stack Stack}-based {@link ObjectPool} implementation.
29   * <p>
30   * Given a {@link PoolableObjectFactory}, this class will maintain
31   * a simple pool of instances.  A finite number of "sleeping"
32   * or idle instances is enforced, but when the pool is
33   * empty, new instances are created to support the new load.
34   * Hence this class places no limit on the number of "active"
35   * instances created by the pool, but is quite useful for
36   * re-using <tt>Object</tt>s without introducing
37   * artificial limits.
38   *
39   * @author Rodney Waldhoff
40   * @author Dirk Verbeeck
41   * @version $Revision: 383290 $ $Date: 2006-03-05 02:00:15 -0500 (Sun, 05 Mar 2006) $
42   */
43  public class StackObjectPool extends BaseObjectPool implements ObjectPool {
44      /***
45       * Create a new pool using
46       * no factory. Clients must first populate the pool
47       * using {@link #returnObject(java.lang.Object)}
48       * before they can be {@link #borrowObject borrowed}.
49       */
50      public StackObjectPool() {
51          this((PoolableObjectFactory)null,DEFAULT_MAX_SLEEPING,DEFAULT_INIT_SLEEPING_CAPACITY);
52      }
53  
54      /***
55       * Create a new pool using
56       * no factory. Clients must first populate the pool
57       * using {@link #returnObject(java.lang.Object)}
58       * before they can be {@link #borrowObject borrowed}.
59       *
60       * @param maxIdle cap on the number of "sleeping" instances in the pool
61       */
62      public StackObjectPool(int maxIdle) {
63          this((PoolableObjectFactory)null,maxIdle,DEFAULT_INIT_SLEEPING_CAPACITY);
64      }
65  
66      /***
67       * Create a new pool using
68       * no factory. Clients must first populate the pool
69       * using {@link #returnObject(java.lang.Object)}
70       * before they can be {@link #borrowObject borrowed}.
71       *
72       * @param maxIdle cap on the number of "sleeping" instances in the pool
73       * @param initIdleCapacity initial size of the pool (this specifies the size of the container,
74       *             it does not cause the pool to be pre-populated.)
75       */
76      public StackObjectPool(int maxIdle, int initIdleCapacity) {
77          this((PoolableObjectFactory)null,maxIdle,initIdleCapacity);
78      }
79  
80      /***
81       * Create a new <tt>StackObjectPool</tt> using
82       * the specified <i>factory</i> to create new instances.
83       *
84       * @param factory the {@link PoolableObjectFactory} used to populate the pool
85       */
86      public StackObjectPool(PoolableObjectFactory factory) {
87          this(factory,DEFAULT_MAX_SLEEPING,DEFAULT_INIT_SLEEPING_CAPACITY);
88      }
89  
90      /***
91       * Create a new <tt>SimpleObjectPool</tt> using
92       * the specified <i>factory</i> to create new instances,
93       * capping the number of "sleeping" instances to <i>max</i>.
94       *
95       * @param factory the {@link PoolableObjectFactory} used to populate the pool
96       * @param maxIdle cap on the number of "sleeping" instances in the pool
97       */
98      public StackObjectPool(PoolableObjectFactory factory, int maxIdle) {
99          this(factory,maxIdle,DEFAULT_INIT_SLEEPING_CAPACITY);
100     }
101 
102     /***
103      * Create a new <tt>SimpleObjectPool</tt> using
104      * the specified <i>factory</i> to create new instances,
105      * capping the number of "sleeping" instances to <i>max</i>,
106      * and initially allocating a container capable of containing
107      * at least <i>init</i> instances.
108      *
109      * @param factory the {@link PoolableObjectFactory} used to populate the pool
110      * @param maxIdle cap on the number of "sleeping" instances in the pool
111      * @param initIdleCapacity initial size of the pool (this specifies the size of the container,
112      *             it does not cause the pool to be pre-populated.)
113      */
114     public StackObjectPool(PoolableObjectFactory factory, int maxIdle, int initIdleCapacity) {
115         _factory = factory;
116         _maxSleeping = (maxIdle < 0 ? DEFAULT_MAX_SLEEPING : maxIdle);
117         int initcapacity = (initIdleCapacity < 1 ? DEFAULT_INIT_SLEEPING_CAPACITY : initIdleCapacity);
118         _pool = new Stack();
119         _pool.ensureCapacity( initcapacity > _maxSleeping ? _maxSleeping : initcapacity);
120     }
121 
122     public synchronized Object borrowObject() throws Exception {
123         assertOpen();
124         Object obj = null;
125         while (null == obj) {
126             if (!_pool.empty()) {
127                 obj = _pool.pop();
128             } else {
129                 if(null == _factory) {
130                     throw new NoSuchElementException();
131                 } else {
132                     obj = _factory.makeObject();
133                 }
134             }
135             if(null != _factory && null != obj) {
136                 _factory.activateObject(obj);
137             }
138             if (null != _factory && null != obj && !_factory.validateObject(obj)) {
139                 _factory.destroyObject(obj);
140                 obj = null;
141             }
142         }
143         _numActive++;
144         return obj;
145     }
146 
147     public synchronized void returnObject(Object obj) throws Exception {
148         assertOpen();
149         boolean success = true;
150         if(null != _factory) {
151             if(!(_factory.validateObject(obj))) {
152                 success = false;
153             } else {
154                 try {
155                     _factory.passivateObject(obj);
156                 } catch(Exception e) {
157                     success = false;
158                 }
159             }
160         }
161 
162         boolean shouldDestroy = !success;
163 
164         _numActive--;
165         if (success) {
166             Object toBeDestroyed = null;
167             if(_pool.size() >= _maxSleeping) {
168                 shouldDestroy = true;
169                 toBeDestroyed = _pool.remove(0); // remove the stalest object
170             }
171             _pool.push(obj);
172             obj = toBeDestroyed; // swap returned obj with the stalest one so it can be destroyed
173         }
174         notifyAll(); // _numActive has changed
175 
176         if(shouldDestroy) { // by constructor, shouldDestroy is false when _factory is null
177             try {
178                 _factory.destroyObject(obj);
179             } catch(Exception e) {
180                 // ignored
181             }
182         }
183     }
184 
185     public synchronized void invalidateObject(Object obj) throws Exception {
186         assertOpen();
187         _numActive--;
188         if(null != _factory ) {
189             _factory.destroyObject(obj);
190         }
191         notifyAll(); // _numActive has changed
192     }
193 
194     public synchronized int getNumIdle() {
195         assertOpen();
196         return _pool.size();
197     }
198 
199     public synchronized int getNumActive() {
200         assertOpen();
201         return _numActive;
202     }
203 
204     public synchronized void clear() {
205         assertOpen();
206         if(null != _factory) {
207             Iterator it = _pool.iterator();
208             while(it.hasNext()) {
209                 try {
210                     _factory.destroyObject(it.next());
211                 } catch(Exception e) {
212                     // ignore error, keep destroying the rest
213                 }
214             }
215         }
216         _pool.clear();
217     }
218 
219     public synchronized void close() throws Exception {
220         clear();
221         _pool = null;
222         _factory = null;
223         super.close();
224     }
225 
226     /***
227      * Create an object, and place it into the pool.
228      * addObject() is useful for "pre-loading" a pool with idle objects.
229      * @throws Exception when the {@link #_factory} has a problem creating an object.
230      */
231     public synchronized void addObject() throws Exception {
232         assertOpen();
233         Object obj = _factory.makeObject();
234         _numActive++;   // A little slimy - must do this because returnObject decrements it.
235         this.returnObject(obj);
236     }
237 
238     public synchronized void setFactory(PoolableObjectFactory factory) throws IllegalStateException {
239         assertOpen();
240         if(0 < getNumActive()) {
241             throw new IllegalStateException("Objects are already active");
242         } else {
243             clear();
244             _factory = factory;
245         }
246     }
247 
248     /*** The default cap on the number of "sleeping" instances in the pool. */
249     protected static final int DEFAULT_MAX_SLEEPING  = 8;
250 
251     /***
252      * The default initial size of the pool
253      * (this specifies the size of the container, it does not
254      * cause the pool to be pre-populated.)
255      */
256     protected static final int DEFAULT_INIT_SLEEPING_CAPACITY = 4;
257 
258     /*** My pool. */
259     protected Stack _pool = null;
260 
261     /*** My {@link PoolableObjectFactory}. */
262     protected PoolableObjectFactory _factory = null;
263 
264     /*** The cap on the number of "sleeping" instances in the pool. */
265     protected int _maxSleeping = DEFAULT_MAX_SLEEPING;
266 
267     /*** Number of object borrowed but not yet returned to the pool. */
268     protected int _numActive = 0;
269 }