001: /*
002: * <copyright>
003: *
004: * Copyright 1997-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: // Later this will move elsewhere...
028: package org.cougaar.core.qos.rss;
029:
030: import org.cougaar.core.component.ServiceBroker;
031: import org.cougaar.core.mts.MessageAddress;
032: import org.cougaar.core.qos.metrics.Constants;
033: import org.cougaar.core.service.wp.AddressEntry;
034: import org.cougaar.core.service.wp.WhitePagesService;
035: import org.cougaar.qos.ResourceStatus.ResourceNode;
036: import org.cougaar.qos.qrs.AbstractContextInstantiater;
037: import org.cougaar.qos.qrs.ContextInstantiater;
038: import org.cougaar.qos.qrs.DataFormula;
039: import org.cougaar.qos.qrs.DataValue;
040: import org.cougaar.qos.qrs.RSS;
041: import org.cougaar.qos.qrs.ResourceContext;
042:
043: /**
044: * This RSS ResourceContext represents an Agent. In the RSS inheritance tree,
045: * the parent of an Agent context is a Node context (see {@link NodeDS}). Agent
046: * contexts are identified by name and support a variety of messaging and cpu
047: * related formulas, described in detail elsewhere.
048: */
049: public class AgentDS extends CougaarDS {
050:
051: static void register() {
052: ContextInstantiater cinst = new AbstractContextInstantiater() {
053: public ResourceContext instantiateContext(
054: String[] parameters, ResourceContext parent)
055: throws ParameterError {
056: return new AgentDS(parameters, parent);
057: }
058:
059: public Object identifyParameters(String[] parameters) {
060: if (parameters == null || parameters.length != 1) {
061: return null;
062: }
063: return parameters[0];
064: }
065:
066: };
067: registerContextInstantiater("Agent", cinst);
068: }
069:
070: private static final String AGENTNAME = "agentname".intern();
071: static final String TOPOLOGY = "topology";
072: static final String UNKNOWN_NODE = "FosterNode";
073:
074: public AgentDS(String[] parameters, ResourceContext parent)
075: throws ParameterError {
076: super (parameters, parent);
077: }
078:
079: protected boolean useParentPath() {
080: return false;
081: }
082:
083: String getAgentName() {
084: return (String) getSymbolValue(AGENTNAME);
085: }
086:
087: // Node DataScopes can be the first element in a path. They must
088: // find or make the corresponding HostDS and return that as the
089: // preferred parent.
090: protected ResourceContext preferredParent(RSS root) {
091: String agentname = (String) getSymbolValue(AGENTNAME);
092: String nodename = null;
093: ServiceBroker sb = (ServiceBroker) root
094: .getProperty("ServiceBroker");
095: AgentTopologyService ats = sb.getService(this ,
096: AgentTopologyService.class, null);
097: if (ats != null) {
098: nodename = ats.getAgentNode(MessageAddress
099: .getMessageAddress(agentname));
100: } else {
101: // AgentTopologyService not loaded. Try a direct WP
102: // call, even though it can give an inconsistent picture.
103: WhitePagesService svc = sb.getService(this ,
104: WhitePagesService.class, null);
105: try {
106: AddressEntry entry = svc.get(agentname, TOPOLOGY, -1);
107: if (entry == null) {
108: if (logger.isWarnEnabled()) {
109: logger.warn("Can't find node for agent "
110: + agentname);
111: }
112: } else {
113: nodename = entry.getURI().getPath().substring(1);
114: }
115: } catch (Exception ex) {
116: // log?
117: }
118:
119: }
120:
121: String[] params = { nodename == null ? UNKNOWN_NODE : nodename };
122: ResourceNode node = new ResourceNode();
123: node.kind = "Node";
124: node.parameters = params;
125: ResourceNode[] path = { node };
126: ResourceContext parent = root.getPathContext(path);
127: setParent(parent);
128: return parent;
129: }
130:
131: protected void verifyParameters(String[] parameters)
132: throws ParameterError {
133: if (parameters == null || parameters.length != 1) {
134: throw new ParameterError(
135: "AgentDS: wrong number of parameters");
136: }
137: if (!(parameters[0] != null)) {
138: throw new ParameterError("AgentDS: wrong parameter type");
139: } else {
140: // could canonicalize here
141: String agentname = parameters[0];
142: bindSymbolValue(AGENTNAME, agentname);
143: historyPrefix = "Agent" + KEY_SEPR + agentname;
144: }
145: }
146:
147: protected DataFormula instantiateFormula(String kind) {
148: if (kind.equals("LastHeard")) {
149: return new LastHeard();
150: } else if (kind.equals("LastSpoke")) {
151: return new LastSpoke();
152: } else if (kind.equals("LastSpokeError")) {
153: return new LastSpokeError();
154: } else if (kind.equals("HeardTime")) {
155: return new HeardTime();
156: } else if (kind.equals("SpokeTime")) {
157: return new SpokeTime();
158: } else if (kind.equals("SpokeErrorTime")) {
159: return new SpokeErrorTime();
160: } else if (kind.equals(Constants.PERSIST_SIZE_LAST)) {
161: return new PersistSizeLast();
162: } else if (kind.equals(Constants.CPU_LOAD_AVG)
163: || kind.equals(Constants.CPU_LOAD_MJIPS)
164: || kind.equals(Constants.MSG_IN)
165: || kind.equals(Constants.BYTES_IN)
166: || kind.equals(Constants.MSG_OUT)
167: || kind.equals(Constants.BYTES_OUT)) {
168: return new DecayingHistoryFormula(historyPrefix, kind);
169: } else {
170: return null;
171: }
172: }
173:
174: abstract static class Formula extends DataFormula {
175:
176: abstract String getKey();
177:
178: protected DataValue defaultValue() {
179: return new DataValue(0);
180: }
181:
182: protected void initialize(ResourceContext context) {
183: super .initialize(context);
184: String agentName = (String) context.getValue(AGENTNAME);
185: String key = "Agent" + KEY_SEPR + agentName + KEY_SEPR
186: + getKey();
187:
188: String[] parameters = { key };
189: ResourceNode node = new ResourceNode();
190: node.kind = "Integrater";
191: node.parameters = parameters;
192: ResourceNode formula = new ResourceNode();
193: formula.kind = "Formula";
194: formula.parameters = new String[0];
195: ResourceNode[] path = { node, formula };
196: DataFormula dependency = RSS.instance()
197: .getPathFormula(path);
198: registerDependency(dependency, "Formula");
199: }
200:
201: protected DataValue doCalculation(DataFormula.Values values) {
202: DataValue computedValue = values.get("Formula");
203: DataValue defaultValue = defaultValue();
204: return DataValue.mostCredible(computedValue, defaultValue);
205: }
206:
207: }
208:
209: abstract static class MonotonicLongFormula extends Formula {
210: int granularity = 1000;
211:
212: protected DataValue doCalculation(DataFormula.Values vals) {
213: DataValue newValue = vals.get("Formula");
214: DataValue cachedValue = getCachedValue();
215: long longNew = newValue.getLongValue();
216: long longCached = cachedValue.getLongValue();
217: if (longNew - longCached > granularity) {
218: return newValue;
219: } else {
220: return cachedValue;
221: }
222: }
223: }
224:
225: abstract static class AlarmFormula extends DataFormula {
226:
227: abstract String getKey();
228:
229: protected DataValue defaultValue() {
230: return new DataValue(0);
231: }
232:
233: protected void initialize(ResourceContext context) {
234: super .initialize(context);
235:
236: DataFormula baseFormula = context
237: .getFormula(getKey(), null);
238: registerDependency(baseFormula, "Formula");
239:
240: ResourceNode node = new ResourceNode();
241: node.kind = "Alarm";
242: node.parameters = new String[0];
243: ResourceNode formula = new ResourceNode();
244: formula.kind = "OneSecond";
245: formula.parameters = new String[0];
246: ResourceNode[] path = { node, formula };
247: DataFormula alarm = RSS.instance().getPathFormula(path);
248: registerDependency(alarm, "Alarm");
249: }
250:
251: protected DataValue doCalculation(DataFormula.Values vals) {
252: DataValue formulaDV = vals.get("Formula");
253: DataValue alarmDV = vals.get("Alarm");
254: if (formulaDV == null || alarmDV == null) {
255: // Callback before both dependencies were registered.
256: // Punt.
257: return DataValue.NO_VALUE;
258: }
259: long sendTime = formulaDV.getLongValue();
260: long alarmTime = alarmDV.getLongValue();
261: long elapsed = 0;
262:
263: if (alarmTime > sendTime) {
264: elapsed = (long) Math
265: .floor((alarmTime - sendTime) / 1000.0);
266: }
267: return new DataValue(elapsed, vals.minCredibility(),
268: "seconds", "unknown");
269: }
270:
271: }
272:
273: static class LastHeard extends AlarmFormula {
274: String getKey() {
275: return "HeardTime";
276: }
277: }
278:
279: static class LastSpoke extends AlarmFormula {
280: String getKey() {
281: return "SpokeTime";
282: }
283: }
284:
285: static class LastSpokeError extends AlarmFormula {
286: String getKey() {
287: return "SpokeErrorTime";
288: }
289: }
290:
291: // HeardTime, SpokeTime and SpokeErrorTime need to be Monotonic, and they
292: // need to be hooked into LastHeard and LastSpoke
293:
294: // The raw integrater values can not be used because there is no
295: // ordering between threads, so an old thread could publish a
296: // HeardTime that is actually before the current HeardTime
297: static class HeardTime extends MonotonicLongFormula {
298: String getKey() {
299: return "HeardTime";
300: }
301: }
302:
303: static class SpokeTime extends MonotonicLongFormula {
304: String getKey() {
305: return "SpokeTime";
306: }
307: }
308:
309: static class SpokeErrorTime extends MonotonicLongFormula {
310: String getKey() {
311: return "SpokeErrorTime";
312: }
313: }
314:
315: static class PersistSizeLast extends Formula {
316: String getKey() {
317: return Constants.PERSIST_SIZE_LAST;
318: }
319: }
320:
321: }
|