001: package com.protomatter.pool;
002:
003: /**
004: * {{{ The Protomatter Software License, Version 1.0
005: * derived from The Apache Software License, Version 1.1
006: *
007: * Copyright (c) 1998-2002 Nate Sammons. All rights reserved.
008: *
009: * Redistribution and use in source and binary forms, with or without
010: * modification, are permitted provided that the following conditions
011: * are met:
012: *
013: * 1. Redistributions of source code must retain the above copyright
014: * notice, this list of conditions and the following disclaimer.
015: *
016: * 2. Redistributions in binary form must reproduce the above copyright
017: * notice, this list of conditions and the following disclaimer in
018: * the documentation and/or other materials provided with the
019: * distribution.
020: *
021: * 3. The end-user documentation included with the redistribution,
022: * if any, must include the following acknowledgment:
023: * "This product includes software developed for the
024: * Protomatter Software Project
025: * (http://protomatter.sourceforge.net/)."
026: * Alternately, this acknowledgment may appear in the software itself,
027: * if and wherever such third-party acknowledgments normally appear.
028: *
029: * 4. The names "Protomatter" and "Protomatter Software Project" must
030: * not be used to endorse or promote products derived from this
031: * software without prior written permission. For written
032: * permission, please contact support@protomatter.com.
033: *
034: * 5. Products derived from this software may not be called "Protomatter",
035: * nor may "Protomatter" appear in their name, without prior written
036: * permission of the Protomatter Software Project
037: * (support@protomatter.com).
038: *
039: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
040: * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
041: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
042: * DISCLAIMED. IN NO EVENT SHALL THE PROTOMATTER SOFTWARE PROJECT OR
043: * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
044: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
045: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
046: * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
047: * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
048: * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
049: * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
050: * SUCH DAMAGE. }}}
051: */
052:
053: import java.util.*;
054: import com.protomatter.syslog.Syslog;
055:
056: /**
057: * An ObjectPool implementation that has an initial size and an
058: * optional max size. The pool will grow as needed by blocks
059: * until the max size is reached.
060: *
061: * @see ObjectPool
062: * @see SimpleObjectPool
063: */
064: public abstract class GrowingObjectPool extends SimpleObjectPool {
065: private int maxPoolSize = -1;
066: private int initialPoolSize = 0;
067: private int createWaitTime = 0;
068: private int growBlock = 1;
069: private List pool = new ArrayList();
070:
071: /**
072: * Initialize the object pool. Checked out
073: * objects will be monitored.
074: */
075: public GrowingObjectPool() {
076: super ();
077: }
078:
079: /**
080: * Initialize the object pool. Checked out
081: * objects will be monitored if <TT>monitorCheckedOutObjects</TT>
082: * is true.
083: */
084: public GrowingObjectPool(boolean monitorCheckedOutObjects) {
085: super (monitorCheckedOutObjects);
086: }
087:
088: /**
089: * Get the pool.
090: */
091: protected List getPool() {
092: return this .pool;
093: }
094:
095: /**
096: * Get the number of objects in the pool that are available.
097: */
098: public int getObjectPoolSize() {
099: return this .pool.size();
100: }
101:
102: /**
103: * Get the current size of the pool. Returns (objects available
104: * + objects in use)
105: */
106: public int getCurrentPoolSize() {
107: int size = 0;
108: synchronized (sync) {
109: size = getObjectPoolSize() + getObjectsInUse();
110: }
111: return size;
112: }
113:
114: /**
115: * Gets the next object from the pool. If the pool is
116: * empty, it is grown by not more than <tt>poolGrowBlock</tt> elements
117: * up to <tt>maxPoolSize</tt> total.
118: *
119: * @exception Exception If there is a problem getting the next
120: * object from the pool -- could be caused by the
121: * createObjectPoolObject() method throwing an exception.
122: */
123: protected ObjectPoolObject getNextPoolObject() throws Exception {
124: synchronized (sync) {
125: // pool's not empty -- just get one from there
126: if (pool.size() > 0) {
127: return (ObjectPoolObject) pool.remove(0);
128: }
129: // grow the pool by "growBlock" elements.
130: else if (getCurrentPoolSize() < maxPoolSize) {
131: int currentPoolSize = getCurrentPoolSize();
132: for (int i = 1; i < growBlock
133: && (maxPoolSize + growBlock) >= currentPoolSize; i++) {
134: pool.add(createObjectPoolObject());
135: doCreateWait();
136: }
137: return createObjectPoolObject();
138: }
139: // special case -- if pool size == -1, grow forever.
140: else if (maxPoolSize == -1) {
141: for (int i = 1; i < growBlock; i++) {
142: pool.add(createObjectPoolObject());
143: doCreateWait();
144: }
145: return createObjectPoolObject();
146: }
147: }
148: // SOL -- better luck next time.
149: return null;
150: }
151:
152: /**
153: * Change the maximum size of the object pool. The pool will be
154: * shrunk unless the number of objects in use (checked out of
155: * the pool) is larger than the new desired size of the pool or
156: * the desired size is smaller than the initial size of this pool.
157: *
158: * @throws PoolException If the number of objects in use is
159: * greater than the desired size of the pool, or if the
160: * desired size is smaller than the initial size for
161: * this pool.
162: */
163: public void setMaxObjectPoolSize(int size) throws PoolException {
164: synchronized (sync) {
165: if (size < getObjectsInUse()) {
166: throw new PoolException(
167: PoolResources
168: .getResourceString(MessageConstants.CANNOT_SHRINK_POOL_1));
169: }
170: if (size < initialPoolSize) {
171: throw new PoolException(
172: PoolResources
173: .getResourceString(MessageConstants.CANNOT_SHRINK_POOL_2));
174: }
175:
176: // how many objects get evicted?
177: int evict = getCurrentPoolSize() - size;
178: if (evict > 0) // need to evict anybody?
179: {
180: for (int i = 0; i < evict; i++) {
181: ObjectPoolObject o = (ObjectPoolObject) pool
182: .remove(0);
183: o.deleteObjectPoolObject(); // should handle cleanup
184: }
185: }
186: maxPoolSize = size;
187: }
188: }
189:
190: private void doCreateWait() {
191: if (createWaitTime > 0) {
192: try {
193: Thread.sleep(createWaitTime);
194: } catch (InterruptedException x) {
195: ;
196: }
197: }
198: }
199:
200: /**
201: * Initialize the pool.
202: * Reads the following from the Map:<P>
203: * <dl>
204: *
205: * <dt><tt>pool.initialSize</tt> (Integer)</dt>
206: * <dd>The initial pool size (default is 0).</dd>
207: *
208: * <dt><tt>pool.maxSize</tt> (Integer)</dt>
209: * <dd>The max pool size (default is -1). If the max
210: * pool size is -1, the pool grows infinitely.</dd>
211: *
212: * <dt><tt>pool.growBlock</tt> (Integer)</dt>
213: * <dd>The grow size (default is 1). When a new
214: * object is needed, this many are created.</dd>
215: *
216: * <dt><tt>pool.createWaitTime</tt> (Integer)</dt>
217: * <dd>The time (in ms) to sleep between pool object creates
218: * (default is 0). This is useful for database connection
219: * pools where it's possible to overload the database by
220: * trying to make too many connections too quickly.</dd>
221: *
222: * </dl><P>
223: *
224: * @exception Exception If there is an exception initializing the pool.
225: */
226: public void init(Map ht) throws Exception {
227: Integer ips = (Integer) ht.get("pool.initialSize");
228: if (ips != null)
229: initialPoolSize = ips.intValue();
230:
231: Integer mps = (Integer) ht.get("pool.maxSize");
232: if (mps != null)
233: maxPoolSize = mps.intValue();
234:
235: Integer pgb = (Integer) ht.get("pool.growBlock");
236: if (pgb != null)
237: growBlock = pgb.intValue();
238:
239: Integer cwt = (Integer) ht.get("pool.createWaitTime");
240: if (cwt != null)
241: createWaitTime = cwt.intValue();
242:
243: // load up the pool.
244: for (int i = 0; i < initialPoolSize; i++) {
245: pool.add(createObjectPoolObject());
246: }
247: }
248:
249: /**
250: * Calls <tt>deleteObjectPoolObject()</tt> on all objects
251: * currently in the pool, and then re-creates the initial
252: * number of them.
253: *
254: * @exception Exception If there is an exception re-initializing the pool.
255: */
256: public void reInitializeObjectPool() throws Exception {
257: synchronized (sync) {
258: Iterator it = pool.iterator();
259: while (it.hasNext()) {
260: ObjectPoolObject obj = (ObjectPoolObject) it.next();
261: obj.deleteObjectPoolObject();
262: }
263: pool.clear();
264:
265: for (int i = 0; i < initialPoolSize; i++) {
266: pool.add(createObjectPoolObject());
267: doCreateWait();
268: }
269: }
270: }
271:
272: /**
273: * @see SimpleObjectPool
274: */
275: protected void checkinPoolObject(ObjectPoolObject o) {
276: pool.add(o);
277: }
278:
279: /**
280: * Get the initial size of the pool.
281: */
282: public int getInitialObjectPoolSize() {
283: return this .initialPoolSize;
284: }
285:
286: /**
287: * Get the maximum number of objects this pool will hold.
288: */
289: public int getMaxObjectPoolSize() {
290: return this .maxPoolSize;
291: }
292:
293: /**
294: * Get the number of objects the pool should grow by when
295: * it needs to grow.
296: */
297: public int getObjectPoolGrowSize() {
298: return this .growBlock;
299: }
300:
301: /**
302: * Get the number of milliseconds to sleep between
303: * creates of new objects for the pool.
304: */
305: public int getCreateWaitTime() {
306: return this.createWaitTime;
307: }
308: }
|