001: /*
002:
003: * <copyright>
004: *
005: * Copyright 2002-2007 BBNT Solutions, LLC
006: * under sponsorship of the Defense Advanced Research Projects
007: * Agency (DARPA).
008: *
009: * You can redistribute this software and/or modify it under the
010: * terms of the Cougaar Open Source License as published on the
011: * Cougaar Open Source Website (www.cougaar.org).
012: *
013: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
014: * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
015: * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
016: * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
017: * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
018: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
019: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
020: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
021: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
022: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
023: * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
024: *
025: * </copyright>
026:
027: */
028:
029: package org.cougaar.qos.qrs;
030:
031: import java.util.Hashtable;
032: import java.util.Vector;
033:
034: /**
035: * This class is provides listener support and a simple caching scheme. Despite
036: * the name, it's not particularly 'standard', in fact it's really only suitable
037: * for feeds which want to avoid calculating values on the fly, because of the
038: * expense involved. The only uses so far seem to be Remos and Erni.
039: */
040: abstract public class StandardDataFeed extends AbstractDataFeed {
041:
042: /**
043: * Indexed by key, each entry is a Vector of listeners for that key.
044: */
045: private final Hashtable<String, Vector<DataFeedListener>> listenerMap = new Hashtable<String, Vector<DataFeedListener>>();
046:
047: /**
048: * Indexed by key, each entry is a the cached value from last poll
049: */
050: private final Hashtable<String, DataValue> valueMap = new Hashtable<String, DataValue>();
051:
052: /**
053: * Return the cached value if it exists, otherwise NO_VALUE.
054: */
055: private DataValue getValueForKey(String key) {
056: DataValue value = valueMap.get(key);
057: if (value == null) {
058: return DataValue.NO_VALUE;
059: } else {
060: return value;
061: }
062: }
063:
064: private void notifyListeners(DataValue value, String key) {
065: Vector<DataFeedListener> listeners = listenersForKey(key);
066: if (listeners != null) {
067: for (DataFeedListener listener : listeners) {
068: listener.newData(this , key, value);
069: }
070: }
071: }
072:
073: private Vector<DataFeedListener> listenersForKey(String key) {
074: return listenerMap.get(key);
075: }
076:
077: /**
078: * Subclass method should return true here iff the key is relevant to the
079: * subclass. If the key is not valid, the subclass will never be asked to
080: * compute a value for it.
081: */
082: abstract protected boolean validateKey(String key);
083:
084: /**
085: * This method does the real work of finding the current value associated
086: * with the given key. This should not usually be called as part of a query
087: * (ie from lookup, either directly or indirectly).
088: */
089: abstract protected DataValue updateValue(String key);
090:
091: /**
092: * Subclasses should call this to force an update of the cache. The second
093: * arg indicates whether or not the listeners should be notified.
094: */
095: protected void updateValueForKey(String key, boolean notify) {
096: DataValue value = updateValue(key);
097: valueMap.put(key, value);
098: if (notify) {
099: notifyListeners(value, key);
100: }
101: }
102:
103: /**
104: * Forces and caches an update of all listener keys.
105: */
106: protected void updateAll() {
107: for (String key : listenerMap.keySet()) {
108: updateValueForKey(key, true);
109: }
110: }
111:
112: /**
113: * The query interface. A real value is returned iff the key is meaningful
114: * for this feed and a value is currently cached. No computation or updating
115: * happens here.
116: */
117: public DataValue lookup(String key) {
118: if (validateKey(key)) {
119: return getValueForKey(key);
120: } else {
121: return DataValue.NO_VALUE;
122: }
123: }
124:
125: /**
126: * Add a listener for the given key. Whenever a new value for this key
127: * enters the store, all listeners will be notified. This method is part of
128: * the DataFeed interface.
129: */
130: public void addListenerForKey(DataFeedListener listener, String key) {
131: if (!validateKey(key)) {
132: return;
133: }
134:
135: Vector<DataFeedListener> listeners = listenersForKey(key);
136: if (listeners == null) {
137: listeners = new Vector<DataFeedListener>(10);
138: listenerMap.put(key, listeners);
139: }
140: listeners.addElement(listener);
141: }
142:
143: /**
144: * Remove a listener for the given key. This method is part of the DataFeed
145: * interface.
146: */
147: public void removeListenerForKey(DataFeedListener listener,
148: String key) {
149: Vector<DataFeedListener> listeners = listenersForKey(key);
150: if (listeners != null) {
151: listeners.removeElement(listener);
152: }
153: }
154:
155: }
|