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.Iterator;
020: import java.util.NoSuchElementException;
021: import java.util.Stack;
022:
023: import org.apache.commons.pool.BaseObjectPool;
024: import org.apache.commons.pool.ObjectPool;
025: import org.apache.commons.pool.PoolableObjectFactory;
026:
027: /**
028: * A simple, {@link java.util.Stack Stack}-based {@link ObjectPool} implementation.
029: * <p>
030: * Given a {@link PoolableObjectFactory}, this class will maintain
031: * a simple pool of instances. A finite number of "sleeping"
032: * or idle instances is enforced, but when the pool is
033: * empty, new instances are created to support the new load.
034: * Hence this class places no limit on the number of "active"
035: * instances created by the pool, but is quite useful for
036: * re-using <tt>Object</tt>s without introducing
037: * artificial limits.
038: *
039: * @author Rodney Waldhoff
040: * @author Dirk Verbeeck
041: * @version $Revision: 383290 $ $Date: 2006-03-05 02:00:15 -0500 (Sun, 05 Mar 2006) $
042: */
043: public class StackObjectPool extends BaseObjectPool implements
044: ObjectPool {
045: /**
046: * Create a new pool using
047: * no factory. Clients must first populate the pool
048: * using {@link #returnObject(java.lang.Object)}
049: * before they can be {@link #borrowObject borrowed}.
050: */
051: public StackObjectPool() {
052: this ((PoolableObjectFactory) 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)}
060: * before they can be {@link #borrowObject borrowed}.
061: *
062: * @param maxIdle cap on the number of "sleeping" instances in the pool
063: */
064: public StackObjectPool(int maxIdle) {
065: this ((PoolableObjectFactory) null, maxIdle,
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)}
073: * before they can be {@link #borrowObject borrowed}.
074: *
075: * @param maxIdle cap on the number of "sleeping" instances in the pool
076: * @param initIdleCapacity 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 StackObjectPool(int maxIdle, int initIdleCapacity) {
080: this ((PoolableObjectFactory) null, maxIdle, initIdleCapacity);
081: }
082:
083: /**
084: * Create a new <tt>StackObjectPool</tt> using
085: * the specified <i>factory</i> to create new instances.
086: *
087: * @param factory the {@link PoolableObjectFactory} used to populate the pool
088: */
089: public StackObjectPool(PoolableObjectFactory factory) {
090: this (factory, DEFAULT_MAX_SLEEPING,
091: DEFAULT_INIT_SLEEPING_CAPACITY);
092: }
093:
094: /**
095: * Create a new <tt>SimpleObjectPool</tt> using
096: * the specified <i>factory</i> to create new instances,
097: * capping the number of "sleeping" instances to <i>max</i>.
098: *
099: * @param factory the {@link PoolableObjectFactory} used to populate the pool
100: * @param maxIdle cap on the number of "sleeping" instances in the pool
101: */
102: public StackObjectPool(PoolableObjectFactory factory, int maxIdle) {
103: this (factory, maxIdle, DEFAULT_INIT_SLEEPING_CAPACITY);
104: }
105:
106: /**
107: * Create a new <tt>SimpleObjectPool</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 PoolableObjectFactory} used to populate the pool
114: * @param maxIdle cap on the number of "sleeping" instances in the pool
115: * @param initIdleCapacity 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 StackObjectPool(PoolableObjectFactory factory, int maxIdle,
119: int initIdleCapacity) {
120: _factory = factory;
121: _maxSleeping = (maxIdle < 0 ? DEFAULT_MAX_SLEEPING : maxIdle);
122: int initcapacity = (initIdleCapacity < 1 ? DEFAULT_INIT_SLEEPING_CAPACITY
123: : initIdleCapacity);
124: _pool = new Stack();
125: _pool.ensureCapacity(initcapacity > _maxSleeping ? _maxSleeping
126: : initcapacity);
127: }
128:
129: public synchronized Object borrowObject() throws Exception {
130: assertOpen();
131: Object obj = null;
132: while (null == obj) {
133: if (!_pool.empty()) {
134: obj = _pool.pop();
135: } else {
136: if (null == _factory) {
137: throw new NoSuchElementException();
138: } else {
139: obj = _factory.makeObject();
140: }
141: }
142: if (null != _factory && null != obj) {
143: _factory.activateObject(obj);
144: }
145: if (null != _factory && null != obj
146: && !_factory.validateObject(obj)) {
147: _factory.destroyObject(obj);
148: obj = null;
149: }
150: }
151: _numActive++;
152: return obj;
153: }
154:
155: public synchronized void returnObject(Object obj) throws Exception {
156: assertOpen();
157: boolean success = true;
158: if (null != _factory) {
159: if (!(_factory.validateObject(obj))) {
160: success = false;
161: } else {
162: try {
163: _factory.passivateObject(obj);
164: } catch (Exception e) {
165: success = false;
166: }
167: }
168: }
169:
170: boolean shouldDestroy = !success;
171:
172: _numActive--;
173: if (success) {
174: Object toBeDestroyed = null;
175: if (_pool.size() >= _maxSleeping) {
176: shouldDestroy = true;
177: toBeDestroyed = _pool.remove(0); // remove the stalest object
178: }
179: _pool.push(obj);
180: obj = toBeDestroyed; // swap returned obj with the stalest one so it can be destroyed
181: }
182: notifyAll(); // _numActive has changed
183:
184: if (shouldDestroy) { // by constructor, shouldDestroy is false when _factory is null
185: try {
186: _factory.destroyObject(obj);
187: } catch (Exception e) {
188: // ignored
189: }
190: }
191: }
192:
193: public synchronized void invalidateObject(Object obj)
194: throws Exception {
195: assertOpen();
196: _numActive--;
197: if (null != _factory) {
198: _factory.destroyObject(obj);
199: }
200: notifyAll(); // _numActive has changed
201: }
202:
203: public synchronized int getNumIdle() {
204: assertOpen();
205: return _pool.size();
206: }
207:
208: public synchronized int getNumActive() {
209: assertOpen();
210: return _numActive;
211: }
212:
213: public synchronized void clear() {
214: assertOpen();
215: if (null != _factory) {
216: Iterator it = _pool.iterator();
217: while (it.hasNext()) {
218: try {
219: _factory.destroyObject(it.next());
220: } catch (Exception e) {
221: // ignore error, keep destroying the rest
222: }
223: }
224: }
225: _pool.clear();
226: }
227:
228: public synchronized void close() throws Exception {
229: clear();
230: _pool = null;
231: _factory = null;
232: super .close();
233: }
234:
235: /**
236: * Create an object, and place it into the pool.
237: * addObject() is useful for "pre-loading" a pool with idle objects.
238: * @throws Exception when the {@link #_factory} has a problem creating an object.
239: */
240: public synchronized void addObject() throws Exception {
241: assertOpen();
242: Object obj = _factory.makeObject();
243: _numActive++; // A little slimy - must do this because returnObject decrements it.
244: this .returnObject(obj);
245: }
246:
247: public synchronized void setFactory(PoolableObjectFactory factory)
248: throws IllegalStateException {
249: assertOpen();
250: if (0 < getNumActive()) {
251: throw new IllegalStateException(
252: "Objects are already active");
253: } else {
254: clear();
255: _factory = factory;
256: }
257: }
258:
259: /** The default cap on the number of "sleeping" instances in the pool. */
260: protected static final int DEFAULT_MAX_SLEEPING = 8;
261:
262: /**
263: * The default initial size of the pool
264: * (this specifies the size of the container, it does not
265: * cause the pool to be pre-populated.)
266: */
267: protected static final int DEFAULT_INIT_SLEEPING_CAPACITY = 4;
268:
269: /** My pool. */
270: protected Stack _pool = null;
271:
272: /** My {@link PoolableObjectFactory}. */
273: protected PoolableObjectFactory _factory = null;
274:
275: /** The cap on the number of "sleeping" instances in the pool. */
276: protected int _maxSleeping = DEFAULT_MAX_SLEEPING;
277:
278: /** Number of object borrowed but not yet returned to the pool. */
279: protected int _numActive = 0;
280: }
|