001 /*
002 * Copyright 1999-2004 The Apache Software Foundation.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017 package org.apache.commons.pool.impl;
018
019 import java.util.Enumeration;
020 import java.util.HashMap;
021 import java.util.Iterator;
022 import java.util.NoSuchElementException;
023 import java.util.Stack;
024
025 import org.apache.commons.pool.BaseKeyedObjectPool;
026 import org.apache.commons.pool.KeyedObjectPool;
027 import org.apache.commons.pool.KeyedPoolableObjectFactory;
028
029 /**
030 * A simple, {@link java.util.Stack Stack}-based {@link KeyedObjectPool} implementation.
031 * <p>
032 * Given a {@link KeyedPoolableObjectFactory}, this class will maintain
033 * a simple pool of instances. A finite number of "sleeping"
034 * or inactive instances is enforced, but when the pool is
035 * empty, new instances are created to support the new load.
036 * Hence this class places no limit on the number of "active"
037 * instances created by the pool, but is quite useful for
038 * re-using <tt>Object</tt>s without introducing
039 * artificial limits.
040 *
041 * @author Rodney Waldhoff
042 * @version $Revision: 1.14 $ $Date: 2004/02/28 12:16:21 $
043 */
044 public class StackKeyedObjectPool extends BaseKeyedObjectPool implements KeyedObjectPool {
045 /**
046 * Create a new pool using
047 * no factory. Clients must first populate the pool
048 * using {@link #returnObject(java.lang.Object,java.lang.Object)}
049 * before they can be {@link #borrowObject(java.lang.Object) borrowed}.
050 */
051 public StackKeyedObjectPool() {
052 this((KeyedPoolableObjectFactory)null,DEFAULT_MAX_SLEEPING,DEFAULT_INIT_SLEEPING_CAPACITY);
053 }
054
055 /**
056 * Create a new pool using
057 * no factory. Clients must first populate the pool
058 * using {@link #returnObject(java.lang.Object,java.lang.Object)}
059 * before they can be {@link #borrowObject(java.lang.Object) borrowed}.
060 *
061 * @param max cap on the number of "sleeping" instances in the pool
062 */
063 public StackKeyedObjectPool(int max) {
064 this((KeyedPoolableObjectFactory)null,max,DEFAULT_INIT_SLEEPING_CAPACITY);
065 }
066
067 /**
068 * Create a new pool using
069 * no factory. Clients must first populate the pool
070 * using {@link #returnObject(java.lang.Object,java.lang.Object)}
071 * before they can be {@link #borrowObject(java.lang.Object) borrowed}.
072 *
073 * @param max cap on the number of "sleeping" instances in the pool
074 * @param init initial size of the pool (this specifies the size of the container,
075 * it does not cause the pool to be pre-populated.)
076 */
077 public StackKeyedObjectPool(int max, int init) {
078 this((KeyedPoolableObjectFactory)null,max,init);
079 }
080
081 /**
082 * Create a new <tt>SimpleKeyedObjectPool</tt> using
083 * the specified <i>factory</i> to create new instances.
084 *
085 * @param factory the {@link KeyedPoolableObjectFactory} used to populate the pool
086 */
087 public StackKeyedObjectPool(KeyedPoolableObjectFactory factory) {
088 this(factory,DEFAULT_MAX_SLEEPING);
089 }
090
091 /**
092 * Create a new <tt>SimpleKeyedObjectPool</tt> using
093 * the specified <i>factory</i> to create new instances.
094 * capping the number of "sleeping" instances to <i>max</i>
095 *
096 * @param factory the {@link KeyedPoolableObjectFactory} used to populate the pool
097 * @param max cap on the number of "sleeping" instances in the pool
098 */
099 public StackKeyedObjectPool(KeyedPoolableObjectFactory factory, int max) {
100 this(factory,max,DEFAULT_INIT_SLEEPING_CAPACITY);
101 }
102
103 /**
104 * Create a new <tt>SimpleKeyedObjectPool</tt> using
105 * the specified <i>factory</i> to create new instances.
106 * capping the number of "sleeping" instances to <i>max</i>,
107 * and initially allocating a container capable of containing
108 * at least <i>init</i> instances.
109 *
110 * @param factory the {@link KeyedPoolableObjectFactory} used to populate the pool
111 * @param max cap on the number of "sleeping" instances in the pool
112 * @param init initial size of the pool (this specifies the size of the container,
113 * it does not cause the pool to be pre-populated.)
114 */
115 public StackKeyedObjectPool(KeyedPoolableObjectFactory factory, int max, int init) {
116 _factory = factory;
117 _maxSleeping = (max < 0 ? DEFAULT_MAX_SLEEPING : max);
118 _initSleepingCapacity = (init < 1 ? DEFAULT_INIT_SLEEPING_CAPACITY : init);
119 _pools = new HashMap();
120 _activeCount = new HashMap();
121 }
122
123 public synchronized Object borrowObject(Object key) throws Exception {
124 Object obj = null;
125 Stack stack = (Stack)(_pools.get(key));
126 if(null == stack) {
127 stack = new Stack();
128 stack.ensureCapacity( _initSleepingCapacity > _maxSleeping ? _maxSleeping : _initSleepingCapacity);
129 _pools.put(key,stack);
130 }
131 try {
132 obj = stack.pop();
133 _totIdle--;
134 } catch(Exception e) {
135 if(null == _factory) {
136 throw new NoSuchElementException();
137 } else {
138 obj = _factory.makeObject(key);
139 }
140 }
141 if(null != obj && null != _factory) {
142 _factory.activateObject(key,obj);
143 }
144 incrementActiveCount(key);
145 return obj;
146 }
147
148 public synchronized void returnObject(Object key, Object obj) throws Exception {
149 decrementActiveCount(key);
150 if(null == _factory || _factory.validateObject(key,obj)) {
151 Stack stack = (Stack)(_pools.get(key));
152 if(null == stack) {
153 stack = new Stack();
154 stack.ensureCapacity( _initSleepingCapacity > _maxSleeping ? _maxSleeping : _initSleepingCapacity);
155 _pools.put(key,stack);
156 }
157 if(null != _factory) {
158 try {
159 _factory.passivateObject(key,obj);
160 } catch(Exception e) {
161 _factory.destroyObject(key,obj);
162 return;
163 }
164 }
165 if(stack.size() < _maxSleeping) {
166 stack.push(obj);
167 _totIdle++;
168 } else {
169 if(null != _factory) {
170 _factory.destroyObject(key,obj);
171 }
172 }
173 } else {
174 if(null != _factory) {
175 _factory.destroyObject(key,obj);
176 }
177 }
178 }
179
180 public synchronized void invalidateObject(Object key, Object obj) throws Exception {
181 decrementActiveCount(key);
182 if(null != _factory) {
183 _factory.destroyObject(key,obj);
184 }
185 notifyAll(); // _totalActive has changed
186 }
187
188 public void addObject(Object key) throws Exception {
189 Object obj = _factory.makeObject(key);
190 synchronized(this) {
191 incrementActiveCount(key); // returnObject will decrement this
192 returnObject(key,obj);
193 }
194 }
195
196 public int getNumIdle() {
197 return _totIdle;
198 }
199
200 public int getNumActive() {
201 return _totActive;
202 }
203
204 public int getNumActive(Object key) {
205 return getActiveCount(key);
206 }
207
208 public synchronized int getNumIdle(Object key) {
209 try {
210 return((Stack)(_pools.get(key))).size();
211 } catch(Exception e) {
212 return 0;
213 }
214 }
215
216 public synchronized void clear() {
217 Iterator it = _pools.keySet().iterator();
218 while(it.hasNext()) {
219 Object key = it.next();
220 Stack stack = (Stack)(_pools.get(key));
221 destroyStack(key,stack);
222 }
223 _totIdle = 0;
224 _pools.clear();
225 _activeCount.clear();
226 }
227
228 public synchronized void clear(Object key) {
229 Stack stack = (Stack)(_pools.remove(key));
230 destroyStack(key,stack);
231 }
232
233 private synchronized void destroyStack(Object key, Stack stack) {
234 if(null == stack) {
235 return;
236 } else {
237 if(null != _factory) {
238 Enumeration enum = stack.elements();
239 while(enum.hasMoreElements()) {
240 try {
241 _factory.destroyObject(key,enum.nextElement());
242 } catch(Exception e) {
243 // ignore error, keep destroying the rest
244 }
245 }
246 }
247 _totIdle -= stack.size();
248 _activeCount.remove(key);
249 stack.clear();
250 }
251 }
252
253 public synchronized String toString() {
254 StringBuffer buf = new StringBuffer();
255 buf.append(getClass().getName());
256 buf.append(" contains ").append(_pools.size()).append(" distinct pools: ");
257 Iterator it = _pools.keySet().iterator();
258 while(it.hasNext()) {
259 Object key = it.next();
260 buf.append(" |").append(key).append("|=");
261 Stack s = (Stack)(_pools.get(key));
262 buf.append(s.size());
263 }
264 return buf.toString();
265 }
266
267 public synchronized void close() throws Exception {
268 clear();
269 _pools = null;
270 _factory = null;
271 _activeCount = null;
272 }
273
274 public synchronized void setFactory(KeyedPoolableObjectFactory factory) throws IllegalStateException {
275 if(0 < getNumActive()) {
276 throw new IllegalStateException("Objects are already active");
277 } else {
278 clear();
279 _factory = factory;
280 }
281 }
282
283 private int getActiveCount(Object key) {
284 try {
285 return ((Integer)_activeCount.get(key)).intValue();
286 } catch(NoSuchElementException e) {
287 return 0;
288 } catch(NullPointerException e) {
289 return 0;
290 }
291 }
292
293 private void incrementActiveCount(Object key) {
294 _totActive++;
295 Integer old = (Integer)(_activeCount.get(key));
296 if(null == old) {
297 _activeCount.put(key,new Integer(1));
298 } else {
299 _activeCount.put(key,new Integer(old.intValue() + 1));
300 }
301 }
302
303 private void decrementActiveCount(Object key) {
304 _totActive--;
305 Integer active = (Integer)(_activeCount.get(key));
306 if(null == active) {
307 // do nothing, either null or zero is OK
308 } else if(active.intValue() <= 1) {
309 _activeCount.remove(key);
310 } else {
311 _activeCount.put(key, new Integer(active.intValue() - 1));
312 }
313 }
314
315 /** The default cap on the number of "sleeping" instances in the pool. */
316 protected static final int DEFAULT_MAX_SLEEPING = 8;
317
318 /**
319 * The default initial size of the pool
320 * (this specifies the size of the container, it does not
321 * cause the pool to be pre-populated.)
322 */
323 protected static final int DEFAULT_INIT_SLEEPING_CAPACITY = 4;
324
325 /** My named-set of pools. */
326 protected HashMap _pools = null;
327
328 /** My {@link KeyedPoolableObjectFactory}. */
329 protected KeyedPoolableObjectFactory _factory = null;
330
331 /** The cap on the number of "sleeping" instances in <i>each</i> pool. */
332 protected int _maxSleeping = DEFAULT_MAX_SLEEPING;
333
334 /** The initial capacity of each pool. */
335 protected int _initSleepingCapacity = DEFAULT_INIT_SLEEPING_CAPACITY;
336
337 /** Total number of object borrowed and not yet retuened for all pools */
338 protected int _totActive = 0;
339
340 /** Total number of objects "sleeping" for all pools */
341 protected int _totIdle = 0;
342
343 /** Number of active objects borrowed and not yet returned by pool */
344 protected HashMap _activeCount = null;
345
346 }
|