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