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: package org.cougaar.lib.aggagent.query;
027:
028: import java.io.Serializable;
029: import java.util.Enumeration;
030: import java.util.Iterator;
031: import java.util.LinkedList;
032: import java.util.List;
033: import java.util.Set;
034: import java.util.Vector;
035:
036: import org.cougaar.core.util.UID;
037: import org.cougaar.core.util.UniqueObject;
038: import org.cougaar.lib.aggagent.session.UpdateDelta;
039: import org.cougaar.lib.aggagent.session.XmlTransferable;
040: import org.cougaar.lib.aggagent.util.InverseSax;
041: import org.w3c.dom.Element;
042: import org.w3c.dom.NodeList;
043:
044: /**
045: * This adapter contains a query and links to some associated structures.
046: */
047: public class QueryResultAdapter implements XmlTransferable,
048: Serializable, UniqueObject {
049: public static String QUERY_RESULT_TAG = "query_result_adapter";
050: public static String ID_ATT = "id";
051:
052: private static int uniqueIdCounter = 0;
053: private String id = null;
054: private AggregationQuery aQuery = null;
055: private AggregationResultSet rawResultSet = null;
056: private List alerts = new LinkedList();
057: private Vector addedClusters = new Vector();
058: private Vector removedClusters = new Vector();
059: private UID uid;
060:
061: private Aggregator agg;
062: private AggregationResultSet aggResultSet;
063:
064: /**
065: * Create a QueryResultAdapter to contain a particular query. At the
066: * current time, only one type of result set is supported, so it is
067: * automatically constructed and installed here.
068: */
069: public QueryResultAdapter(AggregationQuery q) {
070: this (q, (UID) null);
071: }
072:
073: public QueryResultAdapter(AggregationQuery q, UID uid) {
074: id = String.valueOf(uniqueIdCounter++);
075: setQuery(q);
076: setResultSet(new AggregationResultSet());
077: this .uid = uid;
078: }
079:
080: /**
081: * Create a QueryResultAdapter based on xml
082: */
083: public QueryResultAdapter(Element qraRoot) {
084: id = qraRoot.getAttribute(ID_ATT);
085: setQuery(new AggregationQuery((Element) qraRoot
086: .getElementsByTagName(AggregationQuery.QUERY_TAG).item(
087: 0)));
088: setResultSet(new AggregationResultSet((Element) qraRoot
089: .getElementsByTagName(
090: AggregationResultSet.RESULT_SET_TAG).item(0)));
091: NodeList alerts = qraRoot.getElementsByTagName(Alert.ALERT_TAG);
092: for (int i = 0; i < alerts.getLength(); i++) {
093: addAlert(new AlertDescriptor((Element) alerts.item(i)));
094: }
095: }
096:
097: /**
098: * Create a QueryResultAdapter with the given id.
099: */
100: public QueryResultAdapter(AggregationQuery q, String id) {
101: this (q, id, null);
102: }
103:
104: public QueryResultAdapter(AggregationQuery q, String id, UID uid) {
105: this .id = id;
106: this .uid = uid;
107: setQuery(q);
108: setResultSet(new AggregationResultSet());
109: }
110:
111: private void setQuery(AggregationQuery q) {
112: aQuery = q;
113: ScriptSpec aggSpec = aQuery.getAggSpec();
114: try {
115: if (aggSpec != null) {
116: agg = aggSpec.toAggregator();
117: setAggResultSet(new AggregationResultSet());
118: } else {
119: agg = null;
120: }
121: } catch (Exception eek) {
122: eek.printStackTrace();
123: }
124: }
125:
126: public void updateResults(UpdateDelta delta) {
127: rawResultSet.incrementalUpdate(delta);
128: aggregate();
129: }
130:
131: /**
132: * Reconcile new cluster list with current list. Updates the Agg Query and the result sets
133: */
134: public void updateClusters(Vector newClusters) {
135: Iterator iter = aQuery.getSourceClustersVector().iterator();
136: while (iter.hasNext()) {
137: String clusterId = (String) iter.next();
138: // if it's in the query, but not the new list, remove it from the query.
139: // otherwise, remove it from the list of new clusters. All the clusters remaining
140: // in that list will be added to the query at the end.
141: if (!newClusters.contains(clusterId))
142: removeCluster(clusterId);
143: else
144: newClusters.remove(clusterId);
145: }
146: iter = newClusters.iterator();
147: while (iter.hasNext()) {
148: String clusterId = (String) iter.next();
149: addCluster(clusterId);
150: }
151: }
152:
153: /**
154: * Add a cluster to the query.
155: */
156: public void addCluster(String clusterId) {
157: synchronized (addedClusters) {
158: addedClusters.add(clusterId);
159: aQuery.addSourceCluster(clusterId);
160: }
161: }
162:
163: /**
164: * Remove a cluster from the query. Will also clean the cluster out of the result sets.
165: */
166: public void removeCluster(String clusterId) {
167: synchronized (removedClusters) {
168: removedClusters.add(clusterId);
169: aQuery.removeSourceCluster(clusterId);
170: if (rawResultSet != null)
171: rawResultSet.removeClusterId(clusterId);
172: if (aggResultSet != null)
173: aggResultSet.removeClusterId(clusterId);
174: }
175: }
176:
177: /**
178: * Retrieve the Vector of clusters that have been added to this
179: * QRA after it was created. This will reset the list of added clusters
180: * when it is called
181: */
182: public Vector getAndResetAddedClusters() {
183: Vector retVec = null;
184: synchronized (addedClusters) {
185: retVec = new Vector(addedClusters);
186: addedClusters.clear();
187: }
188: return retVec;
189: }
190:
191: /**
192: * Retrieve the Vector of clusters that have been removed from this
193: * QRA after it was created. This will reset the list of removed clusters
194: * when it is called
195: */
196: public Vector getAndResetRemovedClusters() {
197: Vector retVec = null;
198: synchronized (removedClusters) {
199: retVec = new Vector(removedClusters);
200: removedClusters.clear();
201: }
202: return retVec;
203: }
204:
205: /**
206: * Use the local Aggregator (if there is one) to derive an aggregated
207: * result set from the raw data supplied by the query. If no Aggregator
208: * is present, then the call is ignored.
209: */
210: private void aggregate() {
211: if (agg != null) {
212: List atoms = new LinkedList();
213: try {
214: agg.aggregate(rawResultSet.getAllAtoms(), atoms);
215: } catch (Exception eek) {
216: eek.printStackTrace();
217: }
218: aggResultSet.replaceAggregated(atoms);
219: }
220: }
221:
222: public boolean allClustersResponded() {
223: if (rawResultSet == null)
224: return false;
225:
226: Set responded = rawResultSet.getRespondingClusters();
227:
228: Enumeration en = getQuery().getSourceClusters();
229: while (en.hasMoreElements())
230: if (!responded.contains(en.nextElement()))
231: return false;
232:
233: return true;
234: }
235:
236: /**
237: * Register an Alert as interested in events on this query.
238: */
239: public void addAlert(Alert a) {
240: synchronized (alerts) {
241: alerts.add(a);
242: }
243: a.setQueryAdapter(this );
244: }
245:
246: /**
247: * Unregister an Alert
248: *
249: * @return removed alert
250: */
251: public Alert removeAlert(String alertName) {
252: synchronized (alerts) {
253: for (Iterator i = alerts.iterator(); i.hasNext();) {
254: Alert alert = (Alert) i.next();
255: if (alert.getName().equals(alertName)) {
256: i.remove();
257: return alert;
258: }
259: }
260: }
261:
262: return null;
263: }
264:
265: public void removeAlert(Alert a) {
266: synchronized (alerts) {
267: alerts.remove(a);
268: }
269: }
270:
271: /**
272: * Notify the registered Alerts that new information has become available
273: * for this query. They will then examine the result set and respond as
274: * they see fit.
275: */
276: public Iterator getAlerts() {
277: LinkedList ll = null;
278: synchronized (alerts) {
279: ll = new LinkedList(alerts);
280: }
281: return ll.iterator();
282: }
283:
284: public AggregationQuery getQuery() {
285: return aQuery;
286: }
287:
288: private void setAggResultSet(AggregationResultSet rs) {
289: aggResultSet = rs;
290: rs.setQueryAdapter(this );
291: }
292:
293: public void setResultSet(AggregationResultSet rs) {
294: rawResultSet = rs;
295: rawResultSet.setQueryAdapter(this );
296: }
297:
298: public AggregationResultSet getResultSet() {
299: if (agg != null)
300: return aggResultSet;
301: return rawResultSet;
302: }
303:
304: public AggregationResultSet getRawResultSet() {
305: return rawResultSet;
306: }
307:
308: public boolean checkID(String id) {
309: return this .id.equals(id);
310: }
311:
312: public String getID() {
313: return id;
314: }
315:
316: public String toString() {
317: return getQuery().getName() + " (" + getID() + ")";
318: }
319:
320: /**
321: * Convert this QueryResultAdapter to an XML format. For most purposes,
322: * this means giving a summary of the resident result set. For a complete
323: * document describing the query, result set, alerts, etc., use method
324: * toWholeXml().
325: */
326: public String toXml() {
327: return getResultSet().toXml();
328: }
329:
330: public void includeXml(InverseSax doc) {
331: getResultSet().includeXml(doc);
332: }
333:
334: public String toWholeXml() {
335: InverseSax doc = new InverseSax();
336: includeWholeXml(doc);
337: return doc.toString();
338: }
339:
340: public void includeWholeXml(InverseSax doc) {
341: doc.addElement(QUERY_RESULT_TAG);
342: doc.addAttribute(ID_ATT, id);
343: aQuery.includeXml(doc);
344: getResultSet().includeXml(doc);
345: for (Iterator i = alerts.iterator(); i.hasNext();)
346: (new AlertDescriptor((Alert) i.next())).includeXml(doc);
347: doc.endElement();
348: }
349:
350: /*
351: *** UniqueObject interface
352: */
353:
354: public void setUID(UID uid) {
355: throw new RuntimeException("Attempt to change UID");
356: }
357:
358: public UID getUID() {
359: return uid;
360: }
361: }
|