1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.pool.impl;
18
19 import java.util.HashMap;
20 import java.util.Iterator;
21 import java.util.NoSuchElementException;
22 import java.util.Stack;
23
24 import org.apache.commons.pool.BaseKeyedObjectPool;
25 import org.apache.commons.pool.KeyedObjectPool;
26 import org.apache.commons.pool.KeyedPoolableObjectFactory;
27
28 /***
29 * A simple, {@link java.util.Stack Stack}-based {@link KeyedObjectPool} implementation.
30 * <p>
31 * Given a {@link KeyedPoolableObjectFactory}, this class will maintain
32 * a simple pool of instances. A finite number of "sleeping"
33 * or inactive 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 * @version $Revision: 328937 $ $Date: 2005-10-27 15:23:53 -0400 (Thu, 27 Oct 2005) $
42 */
43 public class StackKeyedObjectPool extends BaseKeyedObjectPool implements KeyedObjectPool {
44 /***
45 * Create a new pool using
46 * no factory. Clients must first populate the pool
47 * using {@link #returnObject(java.lang.Object,java.lang.Object)}
48 * before they can be {@link #borrowObject(java.lang.Object) borrowed}.
49 */
50 public StackKeyedObjectPool() {
51 this((KeyedPoolableObjectFactory)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,java.lang.Object)}
58 * before they can be {@link #borrowObject(java.lang.Object) borrowed}.
59 *
60 * @param max cap on the number of "sleeping" instances in the pool
61 */
62 public StackKeyedObjectPool(int max) {
63 this((KeyedPoolableObjectFactory)null,max,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,java.lang.Object)}
70 * before they can be {@link #borrowObject(java.lang.Object) borrowed}.
71 *
72 * @param max cap on the number of "sleeping" instances in the pool
73 * @param init 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 StackKeyedObjectPool(int max, int init) {
77 this((KeyedPoolableObjectFactory)null,max,init);
78 }
79
80 /***
81 * Create a new <tt>SimpleKeyedObjectPool</tt> using
82 * the specified <i>factory</i> to create new instances.
83 *
84 * @param factory the {@link KeyedPoolableObjectFactory} used to populate the pool
85 */
86 public StackKeyedObjectPool(KeyedPoolableObjectFactory factory) {
87 this(factory,DEFAULT_MAX_SLEEPING);
88 }
89
90 /***
91 * Create a new <tt>SimpleKeyedObjectPool</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 KeyedPoolableObjectFactory} used to populate the pool
96 * @param max cap on the number of "sleeping" instances in the pool
97 */
98 public StackKeyedObjectPool(KeyedPoolableObjectFactory factory, int max) {
99 this(factory,max,DEFAULT_INIT_SLEEPING_CAPACITY);
100 }
101
102 /***
103 * Create a new <tt>SimpleKeyedObjectPool</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 KeyedPoolableObjectFactory} used to populate the pool
110 * @param max cap on the number of "sleeping" instances in the pool
111 * @param init 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 StackKeyedObjectPool(KeyedPoolableObjectFactory factory, int max, int init) {
115 _factory = factory;
116 _maxSleeping = (max < 0 ? DEFAULT_MAX_SLEEPING : max);
117 _initSleepingCapacity = (init < 1 ? DEFAULT_INIT_SLEEPING_CAPACITY : init);
118 _pools = new HashMap();
119 _activeCount = new HashMap();
120 }
121
122 public synchronized Object borrowObject(Object key) throws Exception {
123 Object obj = null;
124 Stack stack = (Stack)(_pools.get(key));
125 if(null == stack) {
126 stack = new Stack();
127 stack.ensureCapacity( _initSleepingCapacity > _maxSleeping ? _maxSleeping : _initSleepingCapacity);
128 _pools.put(key,stack);
129 }
130 try {
131 obj = stack.pop();
132 _totIdle--;
133 } catch(Exception e) {
134 if(null == _factory) {
135 throw new NoSuchElementException();
136 } else {
137 obj = _factory.makeObject(key);
138 }
139 }
140 if(null != obj && null != _factory) {
141 _factory.activateObject(key,obj);
142 }
143 incrementActiveCount(key);
144 return obj;
145 }
146
147 public synchronized void returnObject(Object key, Object obj) throws Exception {
148 decrementActiveCount(key);
149 if(null == _factory || _factory.validateObject(key,obj)) {
150 Stack stack = (Stack)(_pools.get(key));
151 if(null == stack) {
152 stack = new Stack();
153 stack.ensureCapacity( _initSleepingCapacity > _maxSleeping ? _maxSleeping : _initSleepingCapacity);
154 _pools.put(key,stack);
155 }
156 if(null != _factory) {
157 try {
158 _factory.passivateObject(key,obj);
159 } catch(Exception e) {
160 _factory.destroyObject(key,obj);
161 return;
162 }
163 }
164 if(stack.size() < _maxSleeping) {
165 stack.push(obj);
166 _totIdle++;
167 } else {
168 if(null != _factory) {
169 _factory.destroyObject(key,obj);
170 }
171 }
172 } else {
173 if(null != _factory) {
174 _factory.destroyObject(key,obj);
175 }
176 }
177 }
178
179 public synchronized void invalidateObject(Object key, Object obj) throws Exception {
180 decrementActiveCount(key);
181 if(null != _factory) {
182 _factory.destroyObject(key,obj);
183 }
184 notifyAll();
185 }
186
187 public synchronized void addObject(Object key) throws Exception {
188 Object obj = _factory.makeObject(key);
189 incrementActiveCount(key);
190 returnObject(key,obj);
191 }
192
193 public int getNumIdle() {
194 return _totIdle;
195 }
196
197 public int getNumActive() {
198 return _totActive;
199 }
200
201 public synchronized int getNumActive(Object key) {
202 return getActiveCount(key);
203 }
204
205 public synchronized int getNumIdle(Object key) {
206 try {
207 return((Stack)(_pools.get(key))).size();
208 } catch(Exception e) {
209 return 0;
210 }
211 }
212
213 public synchronized void clear() {
214 Iterator it = _pools.keySet().iterator();
215 while(it.hasNext()) {
216 Object key = it.next();
217 Stack stack = (Stack)(_pools.get(key));
218 destroyStack(key,stack);
219 }
220 _totIdle = 0;
221 _pools.clear();
222 _activeCount.clear();
223 }
224
225 public synchronized void clear(Object key) {
226 Stack stack = (Stack)(_pools.remove(key));
227 destroyStack(key,stack);
228 }
229
230 private synchronized void destroyStack(Object key, Stack stack) {
231 if(null == stack) {
232 return;
233 } else {
234 if(null != _factory) {
235 Iterator it = stack.iterator();
236 while(it.hasNext()) {
237 try {
238 _factory.destroyObject(key,it.next());
239 } catch(Exception e) {
240
241 }
242 }
243 }
244 _totIdle -= stack.size();
245 _activeCount.remove(key);
246 stack.clear();
247 }
248 }
249
250 public synchronized String toString() {
251 StringBuffer buf = new StringBuffer();
252 buf.append(getClass().getName());
253 buf.append(" contains ").append(_pools.size()).append(" distinct pools: ");
254 Iterator it = _pools.keySet().iterator();
255 while(it.hasNext()) {
256 Object key = it.next();
257 buf.append(" |").append(key).append("|=");
258 Stack s = (Stack)(_pools.get(key));
259 buf.append(s.size());
260 }
261 return buf.toString();
262 }
263
264 public synchronized void close() throws Exception {
265 clear();
266 _pools = null;
267 _factory = null;
268 _activeCount = null;
269 }
270
271 public synchronized void setFactory(KeyedPoolableObjectFactory factory) throws IllegalStateException {
272 if(0 < getNumActive()) {
273 throw new IllegalStateException("Objects are already active");
274 } else {
275 clear();
276 _factory = factory;
277 }
278 }
279
280 private int getActiveCount(Object key) {
281 try {
282 return ((Integer)_activeCount.get(key)).intValue();
283 } catch(NoSuchElementException e) {
284 return 0;
285 } catch(NullPointerException e) {
286 return 0;
287 }
288 }
289
290 private void incrementActiveCount(Object key) {
291 _totActive++;
292 Integer old = (Integer)(_activeCount.get(key));
293 if(null == old) {
294 _activeCount.put(key,new Integer(1));
295 } else {
296 _activeCount.put(key,new Integer(old.intValue() + 1));
297 }
298 }
299
300 private void decrementActiveCount(Object key) {
301 _totActive--;
302 Integer active = (Integer)(_activeCount.get(key));
303 if(null == active) {
304
305 } else if(active.intValue() <= 1) {
306 _activeCount.remove(key);
307 } else {
308 _activeCount.put(key, new Integer(active.intValue() - 1));
309 }
310 }
311
312 /*** The default cap on the number of "sleeping" instances in the pool. */
313 protected static final int DEFAULT_MAX_SLEEPING = 8;
314
315 /***
316 * The default initial size of the pool
317 * (this specifies the size of the container, it does not
318 * cause the pool to be pre-populated.)
319 */
320 protected static final int DEFAULT_INIT_SLEEPING_CAPACITY = 4;
321
322 /*** My named-set of pools. */
323 protected HashMap _pools = null;
324
325 /*** My {@link KeyedPoolableObjectFactory}. */
326 protected KeyedPoolableObjectFactory _factory = null;
327
328 /*** The cap on the number of "sleeping" instances in <i>each</i> pool. */
329 protected int _maxSleeping = DEFAULT_MAX_SLEEPING;
330
331 /*** The initial capacity of each pool. */
332 protected int _initSleepingCapacity = DEFAULT_INIT_SLEEPING_CAPACITY;
333
334 /*** Total number of object borrowed and not yet retuened for all pools */
335 protected int _totActive = 0;
336
337 /*** Total number of objects "sleeping" for all pools */
338 protected int _totIdle = 0;
339
340 /*** Number of active objects borrowed and not yet returned by pool */
341 protected HashMap _activeCount = null;
342
343 }