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.util.*;
055: import com.protomatter.syslog.Syslog;
056:
057: /**
058: * A minimal implementation of an ObjectPool.
059: * This class provides a non-growing pool that
060: * sleeps the threads that are trying to check
061: * something out of the pool, and wakes them
062: * up in-order when something is checked back in.
063: *
064: * @see ObjectPool
065: */
066: public abstract class SimpleObjectPool implements ObjectPool {
067: /**
068: * An object used for synchronization.
069: */
070: protected Object sync = new Object();
071:
072: private List waiters = new ArrayList();
073: private List checkedOutObjects = new ArrayList();
074: private boolean monitorCheckedOutObjects = true;
075:
076: /**
077: * Initialize the object pool. Checked out
078: * objects will be monitored.
079: */
080: public SimpleObjectPool() {
081: this (true);
082: }
083:
084: /**
085: * Initialize the object pool. Checked out
086: * objects will be monitored if <TT>monitorCheckedOutObjects</TT>
087: * is true.
088: */
089: public SimpleObjectPool(boolean monitorCheckedOutObjects) {
090: super ();
091: this .monitorCheckedOutObjects = monitorCheckedOutObjects;
092: }
093:
094: /**
095: * Get a reference to the object being used
096: * as a synchronization lock. Subclasses that
097: * need to lock the operation of the pool while
098: * they perform maintenance should synchronize
099: * on this object and then manipulate the pool.
100: */
101: protected Object getSyncObject() {
102: return this .sync;
103: }
104:
105: /**
106: * Get the number of threads waiting for an object to become available.
107: */
108: public int getNumWaiters() {
109: return this .waiters.size();
110: }
111:
112: /**
113: * Get the number of objects that are currently checked out.
114: */
115: public int getObjectsInUse() {
116: return this .checkedOutObjects.size();
117: }
118:
119: /**
120: * Add a thread to the queue of threads waiting for the shared object.
121: * If, for some reason, the thread is already in the queue, then this
122: * call will be ignored --- the thread can only be in the queue once
123: * via this method.
124: */
125: private final void addToWaiters(Thread t) {
126: synchronized (waiters) {
127: if (!waiters.contains(t)) {
128: waiters.add(t);
129: //Syslog.debug(this, "Adding waiter " + t);
130: }
131: }
132: }
133:
134: /**
135: * Remove the given thread from the list of waiters. This
136: * method should only be called if you know what you're
137: * doing.
138: */
139: public final void removeWaiter(Thread t) {
140: synchronized (waiters) {
141: waiters.remove(t);
142: }
143: }
144:
145: /**
146: * Get the next thread in line and remove it from the waiters.
147: */
148: private final Thread getNextWaiter() {
149: synchronized (waiters) {
150: if (waiters.size() != 0)
151: return (Thread) waiters.remove(0);
152: return null;
153: }
154: }
155:
156: /**
157: * Implements a first in, first out reservation scheme. If no
158: * threads are waiting for the object, then the caller never blocks.
159: * If there are waiters, then the caller "get's in line," and waits
160: * for their turn with the object.
161: *
162: * @exception Exception If there is a problem checking an object out of the pool.
163: */
164: public ObjectPoolObject checkout() throws Exception {
165: Thread thread = Thread.currentThread();
166:
167: ObjectPoolObject obj = null;
168: while (true) // mmmm.... infinity
169: {
170: synchronized (sync) {
171: boolean done = false;
172:
173: while (!done) {
174: obj = getNextPoolObject(); // can throw exception
175:
176: if (obj != null) {
177: obj.beforeObjectPoolObjectCheckout();
178: // make sure the checked out object is still valid.
179: if (obj.isObjectPoolObjectValid()) {
180: if (monitorCheckedOutObjects)
181: checkedOutObjects.add(obj);
182: return obj;
183: } else {
184: obj.deleteObjectPoolObject();
185: }
186: } else {
187: done = true;
188: }
189: }
190: }
191:
192: // if we got here it's because we didn't get
193: // anything from the pool. We'll just wait
194: // till someone wakes us up and give it another
195: // try.
196: synchronized (thread) {
197: addToWaiters(thread);
198: thread.wait();
199: }
200: }
201: }
202:
203: /**
204: * Check an object back into the pool. If there are
205: * threads in the wait queue, the thread that has been waiting
206: * longest will get the shared object next. The waiter may not receive
207: * the shared object immediately, however.
208: *
209: * @exception Exception If there was a problem checking in the object.
210: */
211: public void checkin(ObjectPoolObject opo) throws Exception {
212: opo.afterObjectPoolObjectCheckin();
213: synchronized (sync) {
214: try {
215: if (opo.isObjectPoolObjectValid())
216: checkinPoolObject(opo); // can throw Exception
217: else
218: opo.deleteObjectPoolObject();
219: } finally {
220: // make sure to remove it from the list of
221: // checked out objects.
222: if (monitorCheckedOutObjects)
223: this .checkedOutObjects.remove(opo);
224:
225: // wake up the next guy in line.
226: Thread waiter = getNextWaiter();
227: if (waiter != null) {
228: synchronized (waiter) {
229: waiter.notify();
230: }
231: }
232: }
233: }
234: }
235:
236: /**
237: * Get the list of objects that are currently checked out of the pool.
238: */
239: protected List getCheckedOutObjects() {
240: return this .checkedOutObjects;
241: }
242:
243: /**
244: * This method needs to be implemented by sub-classes.
245: * It should return the next element in the pool, or
246: * null if the pool is empty. Growable implementations
247: * should use this method to add more elements to the
248: * pool.
249: *
250: * @exception Exception If there is a problem getting the
251: * next object for the pool -- this is implementation specific.
252: */
253: protected abstract ObjectPoolObject getNextPoolObject()
254: throws Exception;
255:
256: /**
257: * This method needs to be implemented by sub-classes.
258: * It should add the given ObjectPoolObject to the pool.
259: *
260: * @exception Exception If there is a problem checking in the
261: * object -- this is implementation specific.
262: */
263: protected abstract void checkinPoolObject(ObjectPoolObject o)
264: throws Exception;
265:
266: /**
267: * To be implemented by sub-classes. This is a factory
268: * method for creating objects that go in this pool.
269: *
270: * @exception Exception If there is a problem creating the next
271: * object for the pool -- this is implementation specific.
272: */
273: protected abstract ObjectPoolObject createObjectPoolObject()
274: throws Exception;
275: }
|