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 org.cougaar.util.log.Logger;
032:
033: /**
034: * A standard ResourceContext type, which listens on all known DataFeeds and
035: * selects the 'best' value by maximizing validity. The only available formula
036: * is 'Formula'.
037: */
038: public class IntegraterDS extends ResourceContext {
039:
040: static void register() {
041: ContextInstantiater cinst = new AbstractContextInstantiater() {
042: public ResourceContext instantiateContext(
043: String[] parameters, ResourceContext parent)
044: throws ResourceContext.ParameterError {
045: return new IntegraterDS(parameters, parent);
046: }
047:
048: };
049: registerContextInstantiater("Integrater", cinst);
050: }
051:
052: private static final String KEY = "key";
053:
054: private static Logger logger = Logging
055: .getLogger(IntegraterDS.class);
056:
057: protected IntegraterDS(String[] keys, ResourceContext parent)
058: throws ParameterError {
059: super (keys, parent);
060: }
061:
062: // Host Integraters can be the first element in a path. They have
063: // no parent or context other than the root.
064: protected ResourceContext preferredParent(RSS root) {
065: return root;
066: }
067:
068: protected DataFormula instantiateFormula(String kind) {
069: if (kind.equals("Formula")) {
070: return new Formula();
071: } else {
072: return null;
073: }
074: }
075:
076: /**
077: * The parameters should contain one object, a String, which will be the key
078: * used to register this context as a listener on the various DataFeeds.
079: */
080: protected void verifyParameters(String[] parameters)
081: throws ParameterError {
082: if (parameters == null || parameters.length == 0) {
083: throw new ParameterError("IntegraterDS: no parameters");
084: }
085: String key = parameters[0];
086: bindSymbolValue(KEY, key.intern());
087: }
088:
089: /**
090: * Standard formula for the IntegraterDS.
091: */
092: public static class Formula extends DataFormula implements
093: DataFeedListener {
094: private DataFeed bestFeed;
095: private String key;
096:
097: public Formula() {
098: }
099:
100: protected void initialize(ResourceContext context) {
101: super .initialize(context);
102: this .key = (String) context.getValue(KEY);
103: for (DataFeed feed : RSS.instance().feeds()) {
104: if (logger.isDebugEnabled()) {
105: logger.debug("Subscribing to " + feed);
106: }
107: feed.addListenerForKey(this , key);
108: }
109: synchronized (this ) {
110: rescanFeeds();
111: }
112: }
113:
114: // No explicit calculation is ever needed here
115: protected DataValue doCalculation(DataFormula.Values values) {
116: return getCachedValue();
117: }
118:
119: void rescanFeeds() {
120: rescanFeeds(getCachedValue());
121: }
122:
123: private void rescanFeeds(DataValue old) {
124: DataValue best = old;
125: for (DataFeed feed : RSS.instance().feeds()) {
126: DataValue current = feed.lookup(key);
127: DataValue new_best = DataValue.mostCredible(current,
128: best);
129: if (new_best != best) {
130: best = new_best;
131: bestFeed = feed;
132: }
133: }
134:
135: if (best != old) {
136: setCachedValue(best);
137: }
138: }
139:
140: /**
141: * When new data arrives from any feed, the cached 'best' value will be
142: * updated. If the new data comes from the same feed that previously
143: * supplied the 'best' value, and if the validity of the new data is
144: * greater than or equal to the validity the previous best, the new data
145: * becomes the best data. If the new data comes from the same feed that
146: * previously supplied the 'best' value, and if the validity of the new
147: * data is less than the validity the previous best, the feeds are
148: * scanned for a new best. If the new data comes from the different feed
149: * than the one that previously supplied the 'best' value, and if the
150: * validity of the new data is higher than that of the previos best, the
151: * new data becomes the best data. Otherwise the previous stays best.
152: */
153: public synchronized void newData(DataFeed store, String key,
154: DataValue data) {
155: if (logger.isDebugEnabled()) {
156: logger.debug("Integrater for " + key + " got new data "
157: + data + " from " + store.getName());
158: }
159: DataValue old = getCachedValue();
160: DataValue most = DataValue.mostCredible(old, data);
161: if (store == bestFeed) {
162: if (data == most) {
163: // Validity of "best feed" has gone up.
164: setCachedValue(data);
165: } else {
166: // Validity of "best feed" has gone down. Rescan to
167: // find a new 'best'.
168: if (data.getCredibility() == 0) {
169: // Ordinarily this would be a signal that the
170: // value has timed out and is no longer valid.
171: rescanFeeds(DataValue.NO_VALUE);
172: } else {
173: rescanFeeds(data);
174: }
175: }
176: } else {
177: if (data == most) {
178: // A different feed is now "best"
179: bestFeed = store;
180: setCachedValue(data);
181: } else {
182: // Less valid data from a feed that's not the current
183: // 'best' -- no action required.
184: }
185: }
186: }
187:
188: }
189:
190: }
|