001: /*
002: * <copyright>
003: *
004: * Copyright 1997-2005 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.core.qos.frame.visualizer;
028:
029: import java.util.ArrayList;
030: import java.util.Collection;
031: import java.util.HashMap;
032: import java.util.HashSet;
033: import java.util.Iterator;
034: import java.util.Set;
035:
036: import javax.swing.event.ChangeListener;
037:
038: import org.cougaar.core.qos.frame.FrameSet;
039: import org.cougaar.core.qos.frame.RelationFrame;
040: import org.cougaar.core.qos.frame.visualizer.event.AddedFramesEvent;
041: import org.cougaar.core.qos.frame.visualizer.event.ChangeModel;
042: import org.cougaar.core.qos.frame.visualizer.event.ChangedFramesEvent;
043: import org.cougaar.core.qos.frame.visualizer.event.ContainerChildAddedEvent;
044: import org.cougaar.core.qos.frame.visualizer.event.ContainerChildRemovedEvent;
045: import org.cougaar.core.qos.frame.visualizer.event.RemovedFramesEvent;
046: import org.cougaar.core.qos.frame.visualizer.test.FramePredicate;
047: import org.cougaar.util.log.Logger;
048: import org.cougaar.util.log.Logging;
049:
050: public class FrameModel {
051: protected static int sid = 0;
052: protected int internalid = sid++;
053: protected FrameSet frameSet;
054: protected Collection allFrames;
055: protected HashSet dataFrames;
056: protected HashSet relationshipFrames;
057: // keep track of all shape graphic objects that have an associated Frame object (prototypes and grouping containers
058: // are not currently kept track of
059: private HashMap graphicsMap;
060: // relationship frames that have child == null || parent == null
061: protected HashSet pendingRelationshipFrames;
062:
063: //protected HashMap frameMap;
064: //private Object lock = new Object();
065:
066: private transient Logger log = Logging.getLogger(getClass()
067: .getName());
068:
069: //DisplayWindow displayWindow;
070: //static String TICK_EVENT_LABEL = "TICK";
071: //protected int tickNumber;
072:
073: ChangeModel addedFramesListeners;
074: ChangeModel changedFramesListeners;
075: ChangeModel removedFramesListeners;
076: //ChangeModel transitionListeners;
077: ChangeModel graphicChangeListeners;
078:
079: public FrameModel() {
080: //tickNumber = 0;
081: relationshipFrames = new HashSet();
082: pendingRelationshipFrames = new HashSet();
083: dataFrames = new HashSet();
084: allFrames = new HashSet();
085: graphicsMap = new HashMap();
086:
087: addedFramesListeners = new ChangeModel();
088: changedFramesListeners = new ChangeModel();
089: removedFramesListeners = new ChangeModel();
090: //transitionListeners = new ChangeModel();
091: graphicChangeListeners = new ChangeModel();
092:
093: // views
094: //this.displayWindow = null;
095: //this.containerView = null;
096: //this.frameTreeView = null;
097: }
098:
099: public synchronized void addAddedFramesListener(ChangeListener l) {
100: addedFramesListeners.addListener(l);
101: }
102:
103: public synchronized void removeAddedFramesListener(ChangeListener l) {
104: addedFramesListeners.removeListener(l);
105: }
106:
107: public synchronized void addChangedFramesListener(ChangeListener l) {
108: changedFramesListeners.addListener(l);
109: }
110:
111: public synchronized void removeChangedFramesListener(
112: ChangeListener l) {
113: changedFramesListeners.removeListener(l);
114: }
115:
116: public synchronized void addRemovedFramesListener(ChangeListener l) {
117: removedFramesListeners.addListener(l);
118: }
119:
120: public synchronized void removeRemovedFramesListener(
121: ChangeListener l) {
122: removedFramesListeners.addListener(l);
123: }
124:
125: /*public synchronized void addTransitionListener(ChangeListener l) {
126: transitionListeners.addListener(l);
127: }
128: public synchronized void removeTransitionListener(ChangeListener l) {
129: transitionListeners.removeListener(l);
130: }*/
131: public synchronized void addGraphicChangeListener(ChangeListener l) {
132: graphicChangeListeners.addListener(l);
133: }
134:
135: public synchronized void removeGraphicChangeListener(
136: ChangeListener l) {
137: graphicChangeListeners.removeListener(l);
138: }
139:
140: protected synchronized void notifyAddedFrames(AddedFramesEvent e) {
141: addedFramesListeners.notifyListeners(e);
142: //SwingUtilities.invokeLater(new NotifyHelper(addedFramesListeners, e));
143: }
144:
145: protected synchronized void notifyChangedFrames(ChangedFramesEvent e) {
146: changedFramesListeners.notifyListeners(e);
147: //SwingUtilities.invokeLater(new NotifyHelper(changedFramesListeners, e));
148: }
149:
150: protected synchronized void notifyRemovedFrames(RemovedFramesEvent e) {
151: removedFramesListeners.notifyListeners(e);
152: //SwingUtilities.invokeLater(new NotifyHelper(removedFramesListeners, e));
153: }
154:
155: //protected synchronized void notifyNewTransitions(TickEvent e) {
156: // transitionListeners.notifyListeners(e);
157: // //SwingUtilities.invokeLater(new NotifyHelper(transitionListeners, e));
158: //}
159:
160: public synchronized void fireContainerAddedChild(ShapeContainer c,
161: ShapeGraphic newchild) {
162: graphicChangeListeners
163: .notifyListeners(new ContainerChildAddedEvent(this , c,
164: newchild));
165: }
166:
167: public synchronized void fireContainerRemovedChild(
168: ShapeContainer c, ShapeGraphic removedchild) {
169: graphicChangeListeners
170: .notifyListeners(new ContainerChildRemovedEvent(this ,
171: c, removedchild));
172: }
173:
174: /*
175: class NotifyHelper implements Runnable {
176: ChangeModel changes;
177: ChangeEvent event;
178: public NotifyHelper(ChangeModel m, ChangeEvent e) {
179: changes = m;
180: event = e;
181: }
182: public void run() {
183: changes.notifyListeners(event);
184: }
185: }*/
186:
187: public synchronized boolean registerGraphic(
188: org.cougaar.core.qos.frame.Frame f, ShapeGraphic graphic) {
189: if (f == null || graphic == null)
190: return false;
191: ShapeGraphic sg;
192: if ((sg = (ShapeGraphic) graphicsMap.get(f)) != null) {
193: if (sg != graphic)
194: throw new IllegalArgumentException("Error: " + graphic
195: + " is already registered for frame " + f);
196: }
197: graphicsMap.put(f, graphic);
198: return true;
199: }
200:
201: public synchronized void unregisterGraphic(
202: org.cougaar.core.qos.frame.Frame f, ShapeGraphic graphic) {
203: if (f == null || graphic == null)
204: return;
205: if (graphicsMap.get(f) != null)
206: graphicsMap.remove(f);
207: }
208:
209: public ShapeGraphic getGraphic(org.cougaar.core.qos.frame.Frame f) {
210: //synchronized (lock) {
211: return (ShapeGraphic) graphicsMap.get(f);
212: //}
213: }
214:
215: public boolean hasFrameSet() {
216: return frameSet != null;
217: }
218:
219: //public synchronized void setDisplayWindow(DisplayWindow displayWindow) {
220: // this.displayWindow = displayWindow;
221: //}
222:
223: public synchronized void setFrameSet(FrameSet frameSet) {
224: this .frameSet = frameSet;
225: }
226:
227: public synchronized void framesAdded(Collection addedFrames) {
228: if (log.isDebugEnabled())
229: log.debug("addFrames(" + internalid
230: + "): initialized with " + addedFrames.size()
231: + " frames and frameset=" + frameSet.getName());
232: this .allFrames.addAll(addedFrames);
233: process(addedFrames);
234: }
235:
236: public synchronized void framesRemoved(Collection removedFrames) {
237: if (log.isDebugEnabled())
238: log.debug("removeFrames(" + internalid
239: + "): initialized with " + removedFrames.size()
240: + " frames and frameset=" + frameSet.getName());
241:
242: allFrames.removeAll(removedFrames);
243: }
244:
245: public synchronized void framesChanged(HashMap changes) {
246: processChanges(changes);
247: }
248:
249: ////////////////////////////////////////////////////////////////////////////////////////////////////////////
250: // Data exporation methods
251: ////////////////////////////////////////////////////////////////////////////////////////////////////////////
252: public String getFrameSetName() {
253: return frameSet.getName();
254: }
255:
256: public synchronized Collection getAllFrames() {
257: return new ArrayList(allFrames);
258: }
259:
260: public synchronized Collection getRelationshipFrames() {
261: return new HashSet(relationshipFrames);
262: }
263:
264: public synchronized Collection getDataFrames() {
265: return new HashSet(dataFrames);
266: }
267:
268: public org.cougaar.core.qos.frame.Frame findFrame(
269: FramePredicate predicate) {
270: return findFrame(allFrames, predicate);
271: }
272:
273: public synchronized org.cougaar.core.qos.frame.Frame findFrame(
274: Collection frames, FramePredicate predicate) {
275: //if (predicate != null)
276: // predicate.setFrameSetName((frameSet != null ? frameSet.getName() : null));
277: if (log.isDebugEnabled())
278: log
279: .debug("findFrame(:" + internalid + " frames["
280: + frames.size() + "], predicate="
281: + predicate + ")");
282: org.cougaar.core.qos.frame.Frame f;
283: for (Iterator ii = frames.iterator(); ii.hasNext();) {
284: f = (org.cougaar.core.qos.frame.Frame) ii.next();
285: if (predicate.execute(f)) {
286: //if (log.isDebugEnabled())
287: // log.debug(":"+internalid+" found frame= "+f);
288: return f;
289: }
290: }
291: return null;
292: }
293:
294: public synchronized RelationFrame findRelation(
295: org.cougaar.core.qos.frame.DataFrame parent,
296: org.cougaar.core.qos.frame.DataFrame child,
297: String relationName) {
298: return findRelation(relationshipFrames, parent, child,
299: relationName);
300: }
301:
302: public synchronized RelationFrame findRelation(
303: Collection relationFrames,
304: org.cougaar.core.qos.frame.DataFrame parent,
305: org.cougaar.core.qos.frame.DataFrame child,
306: String relationName) {
307: Collection relations = findRelations(relationFrames, parent,
308: child);
309: RelationFrame rf;
310: for (Iterator ii = relations.iterator(); ii.hasNext();) {
311: rf = (RelationFrame) ii.next();
312: if (rf.getKind().equals(relationName))
313: return rf;
314: }
315: return null;
316: }
317:
318: public synchronized Collection findRelations(
319: org.cougaar.core.qos.frame.DataFrame parent,
320: org.cougaar.core.qos.frame.DataFrame child) {
321: return findRelations(relationshipFrames, parent, child);
322: }
323:
324: public synchronized Collection findRelations(
325: Collection relationFrames,
326: org.cougaar.core.qos.frame.Frame parent,
327: org.cougaar.core.qos.frame.Frame child) {
328: ArrayList result = new ArrayList();
329: RelationFrame rf;
330: for (Iterator ii = relationFrames.iterator(); ii.hasNext();) {
331: rf = (RelationFrame) ii.next();
332: if (rf.relationshipParent() == parent
333: && rf.relationshipChild() == child)
334: result.add(rf);
335: }
336: return result;
337: }
338:
339: public synchronized Collection findFrames(FramePredicate predicate) {
340: return findFrames(allFrames, predicate);
341: }
342:
343: public synchronized Collection findFrames(Collection frames,
344: FramePredicate predicate) {
345: //if (predicate != null)
346: // predicate.setFrameSetName((frameSet != null ? frameSet.getName() : null));
347:
348: ArrayList result = new ArrayList();
349: org.cougaar.core.qos.frame.Frame f;
350: for (Iterator ii = frames.iterator(); ii.hasNext();) {
351: f = (org.cougaar.core.qos.frame.Frame) ii.next();
352: if (predicate.execute(f))
353: result.add(f);
354: }
355: //if (log.isDebugEnabled())
356: // printResult(result);
357: if (log.isDebugEnabled())
358: log.debug("findFrames(:" + internalid + " frames["
359: + frames.size() + "], predicate=" + predicate
360: + "): found " + result.size() + " frames");
361: return result;
362: }
363:
364: protected void printResult(Collection result) {
365: if (log.isDebugEnabled() && result.size() > 0) {
366: StringBuffer sb = new StringBuffer("found: \n");
367: for (Iterator jj = result.iterator(); jj.hasNext();) {
368: sb.append(jj.next().toString());
369: sb.append("\n");
370: }
371: } else if (log.isDebugEnabled() && result.size() == 0)
372: log.debug("found no matches");
373: }
374:
375: public synchronized Collection getAllChildren(
376: org.cougaar.core.qos.frame.Frame parent, String relationship) {
377: Set s = frameSet.findRelations(parent, "child", relationship);
378: if (log.isDebugEnabled())
379: log.debug("getAllChildren(:" + internalid + " parent="
380: + parent + " relationship=" + relationship
381: + "): found " + s.size() + " children");
382: return s;
383: }
384:
385: public synchronized Collection getAllChildren(
386: org.cougaar.core.qos.frame.Frame parent, Collection frames,
387: String relationship) {
388: Set s = frameSet.findRelations(parent, "child", relationship);
389: if (log.isDebugEnabled())
390: log.debug("getAllChildren(:" + internalid + " parent="
391: + parent + " relationship=" + relationship
392: + "): found " + s.size() + " children");
393: return s;
394: }
395:
396: ////////////////////////////////////////////////////////////////////////////////////////////////////////////
397: // Incoming event processing and notification
398: ////////////////////////////////////////////////////////////////////////////////////////////////////////////
399: protected boolean isValid(RelationFrame rframe) {
400: return (rframe.relationshipChild() != null && rframe
401: .relationshipParent() != null);
402: }
403:
404: protected void process(Collection frames) {
405: org.cougaar.core.qos.frame.Frame f;
406: RelationFrame rf;
407: HashSet newRelationFrames = null, newDataFrames = null;
408:
409: for (Iterator ii = frames.iterator(); ii.hasNext();) {
410: f = (org.cougaar.core.qos.frame.Frame) ii.next();
411: if (f instanceof RelationFrame) {
412: rf = (RelationFrame) f;
413: if (!isValid(rf)) {
414: pendingRelationshipFrames.add(f);
415: if (log.isDebugEnabled())
416: log.debug("process(:" + internalid
417: + " added relationFrame ("
418: + rf.getKind()
419: + ") to pendingFrames size="
420: + pendingRelationshipFrames.size());
421: } else {
422: relationshipFrames.add(f);
423: if (newRelationFrames == null)
424: newRelationFrames = new HashSet(frames.size());
425: newRelationFrames.add(f);
426: }
427: } else {
428: dataFrames.add(f);
429: if (newDataFrames == null)
430: newDataFrames = new HashSet(frames.size());
431: newDataFrames.add(f);
432: }
433: }
434:
435: HashSet moreNewRelations = checkPendingRelations();
436: if (moreNewRelations != null && moreNewRelations.size() > 0) {
437: if (newRelationFrames != null)
438: newRelationFrames.addAll(moreNewRelations);
439: else
440: newRelationFrames = moreNewRelations;
441: }
442:
443: notifyAddedFrames(new AddedFramesEvent(this , newDataFrames,
444: newRelationFrames));
445: }
446:
447: // check all relation frames and see if they are valid (parent and child are non null)
448: // if so, remove from the pending list and return in a collection
449: protected HashSet checkPendingRelations() {
450: HashSet validRelationFrames = null;
451: org.cougaar.core.qos.frame.RelationFrame f;
452:
453: for (Iterator ii = pendingRelationshipFrames.iterator(); ii
454: .hasNext();) {
455: f = (org.cougaar.core.qos.frame.RelationFrame) ii.next();
456: if (f.relationshipChild() != null
457: && f.relationshipParent() != null) {
458: //pendingRelationshipFrames.remove(f);
459: if (validRelationFrames == null)
460: validRelationFrames = new HashSet(
461: pendingRelationshipFrames.size());
462: validRelationFrames.add(f);
463: }
464: }
465: if (validRelationFrames != null) {
466: for (Iterator ii = validRelationFrames.iterator(); ii
467: .hasNext();)
468: pendingRelationshipFrames.remove(ii.next());
469: }
470: return validRelationFrames;
471: }
472:
473: protected void processChanges(HashMap changeMap) {
474: // A collection of Frame.Change instances.
475: org.cougaar.core.qos.frame.Frame frame;
476: Collection changeReports;
477:
478: HashMap changedDataFrames = null; //new HashMap();
479: HashMap changedRelationFrames = null; //new HashMap();
480: RelationFrame rf;
481:
482: // if any of the pending relations became valid since the last time we checked, process
483: // them as new frames
484: Collection validRelations = checkPendingRelations();
485: if (validRelations != null && validRelations.size() > 0)
486: process(validRelations);
487: for (Iterator ii = changeMap.keySet().iterator(); ii.hasNext();) {
488: frame = (org.cougaar.core.qos.frame.Frame) ii.next();
489: changeReports = (Collection) changeMap.get(frame);
490:
491: if (frame instanceof RelationFrame) {
492: rf = (RelationFrame) frame;
493: // if a relation frame gets changed and the relationship points to a frame that has not been added
494: // add this relation to the pending relations
495: if (!isValid(rf)) {
496: pendingRelationshipFrames.add(rf);
497: if (log.isDebugEnabled())
498: log.debug("processChanges(:" + internalid
499: + " added relationFrame ("
500: + rf.getKind()
501: + ") to pendingFrames size="
502: + pendingRelationshipFrames.size());
503: } else {
504: if (log.isDebugEnabled())
505: log.debug("processChanges: frame="
506: + frame.getKind() + " " + frame
507: + " changes.size="
508: + changeReports.size());
509: // if this is a relationship change, create transition that will animate moving a
510: // child from one parent to another
511: if (changeReports != null
512: && changeReports.size() > 0) {
513: //trans = processRelationshipChanges((RelationFrame)frame, changeReports);
514: //if (trans != null)
515: // transitions.addAll(trans);
516:
517: if (changedRelationFrames == null)
518: changedRelationFrames = new HashMap();
519: changedRelationFrames.put(frame, changeReports);
520: }
521: }
522: } else {
523: if (changeReports != null && changeReports.size() > 0) {
524: if (changedDataFrames == null)
525: changedDataFrames = new HashMap();
526: changedDataFrames.put(frame, changeReports);
527: }
528:
529: // if this is not a relationship change (we currently only animate the relationship changes)
530: // than trigger the container's slot listeners (if any)
531: //ShapeGraphic sh = getGraphic(frame);
532: //if (log.isDebugEnabled())
533: // log.debug("Observed changed "+frame+ " container="+ (sh==null?"NULL!!!":sh.toString()));
534: //SwingUtilities.invokeLater(new SetChangeHelper(frame, sh, changeReports));
535: }
536: }
537:
538: //if (transitions.size() > 0)
539: // notifyNewTransitions(new org.cougaar.core.qos.frame.visualizer.event.TickEvent(this, tickNumber++, TICK_EVENT_LABEL, transitions));
540: //displayWindow.tickEventOccured(new org.cougaar.core.qos.frame.visualizer.event.TickEvent(this, tickNumber++, TICK_EVENT_LABEL, transitions));
541:
542: if (changedDataFrames != null || changedRelationFrames != null)
543: notifyChangedFrames(new ChangedFramesEvent(this ,
544: changedDataFrames, changedRelationFrames));
545: }
546:
547: public static String getName(org.cougaar.core.qos.frame.Frame frame) {
548: return (frame != null ? (String) frame.getValue("name") : null);
549: }
550:
551: /*
552: protected Transition processRelationshipFrame(RelationFrame rframe) {
553: ShapeGraphic child, parent;
554: Frame fchild, fparent;
555:
556: fparent = rframe.relationshipParent();
557: fchild = rframe.relationshipChild();
558: if (fparent == null || fchild == null) {
559: if (log.isDebugEnabled())
560: log.debug("processRelationshipChange: invalid Relation '"+rframe.getKind()+"' parent="+getName(fparent)+" child="+getName(fchild));
561: }
562:
563: parent = getGraphic(fparent);
564: child = getGraphic(fchild);
565: if (parent == null || child == null) {
566: if (log.isDebugEnabled())
567: log.debug("--error: did not find shapes: Relation '"+rframe.getKind()+"' changed parent="+(fparent==null?"+NULL+":rframe.getParentValue())
568: +" child="+(fchild==null?"+NULL+":rframe.getChildValue())+" parentFrame="+fparent+" childFrame="+fchild);
569: return null;
570: }
571: if (child.getParent() != null && child.getParent().getId().equals(parent.getId())) {
572: if (log.isDebugEnabled())
573: log.debug("--warning: old parent = "+child.getParent()+" new parent="+parent+", ignoring...");
574: return null;
575: }
576: if (log.isDebugEnabled())
577: log.debug("Relation '"+rframe.getKind()+"' changed parent="+(fparent==null?"+NULL+":rframe.getParentValue())
578: +" child="+(fchild==null?"+NULL+":rframe.getChildValue()));//+" parentFrame="+fparent+" childFrame="+fchild);
579:
580:
581: return new Transition(child, child.getParent(), (ShapeContainer)parent);
582: }
583:
584: protected Collection processRelationshipChanges(RelationFrame rframe, Collection changeReports) {
585: ShapeGraphic child, parent;
586: Frame fchild, fparent;
587: ArrayList transitions = null; //new ArrayList();
588:
589: if (log.isDebugEnabled())
590: log.debug("processRelationshipChanges: frame="+rframe.getKind()+" changeReports.size="+changeReports.size());
591:
592: Transition t;
593: for (Iterator ii=changeReports.iterator(); ii.hasNext();) {
594: Frame.Change change = (Frame.Change) ii.next();
595: // Handle change to existing frame
596: //slotName = change.getSlotName();
597: //value = change.getValue();
598: t = processRelationshipFrame(rframe);
599: if (t!=null) {
600: if (transitions == null)
601: transitions = new ArrayList();
602: transitions.add(t);
603: }
604: }
605: return transitions;
606: }
607: */
608:
609: public String toString() {
610: return "FrameModel(" + internalid + "): frameset='"
611: + getFrameSetName() + "' has " + allFrames.size()
612: + " frames, " + dataFrames.size() + " data frames";
613: }
614: }
|