001: /*
002: * <copyright>
003: *
004: * Copyright 2003-2004 BBNT Solutions, LLC
005: * under sponsorship of the Defense Advanced Research Projects
006: * Agency (DARPA).
007: *
008: * You can redistribute this software and/or modify it under the
009: * terms of the Cougaar Open Source License as published on the
010: * Cougaar Open Source Website (www.cougaar.org).
011: *
012: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
013: * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
014: * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
015: * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
016: * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
017: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
018: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
019: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
020: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
021: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
022: * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
023: *
024: * </copyright>
025: */
026:
027: package org.cougaar.util;
028:
029: import java.util.HashMap;
030:
031: /** Implement an asynchronous wait/notify map with value pass-through, selected by an opaque key.
032: **/
033: class WaitQueue {
034: private long counter = 0L;
035: private HashMap selects = new HashMap(11); // assume not too many at a time
036:
037: /** Construct a key to be used in this wait queue **/
038: Object getKey() {
039: Object key;
040: synchronized (selects) {
041: key = new Long(counter++);
042: selects.put(key, new Waiter());
043: }
044: return key;
045: }
046:
047: /** Activate any thread(s) which are waiting for a response from the key **/
048: void trigger(Object key, Object value) {
049: Waiter waiter = null;
050: synchronized (selects) {
051: waiter = (Waiter) selects.get(key);
052: if (waiter == null)
053: return; // bail if no waiter
054: }
055: waiter.trigger(value);
056: }
057:
058: /** Block the current thread until there is a triggerKey has been called
059: * on the referenced key.
060: * Returns immediately if the key is unknown or has previously been triggered.
061: * @throw InterruptedException if the wait is interrupted. In this case,
062: * the trigger is <em>not</em> cleared.
063: * @param key The key as returned by #getKey()
064: * @param timeout How long to wait or 0 (forever)
065: **/
066: Object waitFor(Object key, long timeout)
067: throws InterruptedException {
068: Waiter waiter = null;
069: synchronized (selects) {
070: waiter = (Waiter) selects.get(key);
071: if (waiter == null)
072: return null; // bail if no waiter
073: }
074:
075: // non-null waiter: pass control to it
076: Object value = waiter.waitFor(timeout);
077:
078: // when done, clear it
079: synchronized (selects) {
080: selects.remove(key);
081: }
082:
083: return value;
084: }
085:
086: /** alias for waitFor(key,0L);
087: **/
088: Object waitFor(Object key) throws InterruptedException {
089: return waitFor(key, 0L);
090: }
091:
092: /** Return true IFF waitFor(key) call would have blocked for some amount of time **/
093: boolean wouldBlock(Object key) {
094: Waiter waiter = null;
095: synchronized (selects) {
096: waiter = (Waiter) selects.get(key);
097: if (waiter == null)
098: return false;
099: }
100:
101: // non-null waiter: pass control to it
102: return waiter.wouldBlock();
103: }
104:
105: private static class Waiter {
106: private boolean trigger = false;
107: private Object value = null;
108:
109: synchronized Object waitFor(long timeout)
110: throws InterruptedException {
111: if (trigger)
112: return value;
113: this .wait(timeout);
114: return value;
115: }
116:
117: synchronized void trigger(Object value) {
118: trigger = true;
119: this .value = value;
120: this .notify();
121: }
122:
123: synchronized boolean wouldBlock() {
124: return (!trigger);
125: }
126: }
127: }
|