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: package org.cougaar.mlm.debug.ui;
028:
029: import java.util.Enumeration;
030: import java.util.Hashtable;
031: import java.util.Vector;
032:
033: import org.cougaar.core.blackboard.IncrementalSubscription;
034: import org.cougaar.core.mts.MessageAddress;
035: import org.cougaar.glm.ldm.asset.Organization;
036: import org.cougaar.glm.ldm.asset.PhysicalAsset;
037: import org.cougaar.planning.ldm.ClusterServesPlugin;
038: import org.cougaar.planning.ldm.asset.AggregateAsset;
039: import org.cougaar.planning.ldm.asset.Asset;
040: import org.cougaar.planning.ldm.asset.ItemIdentificationPG;
041: import org.cougaar.planning.ldm.plan.ClusterObjectFactory;
042: import org.cougaar.planning.ldm.plan.Plan;
043: import org.cougaar.planning.plugin.legacy.SimplePlugin;
044: import org.cougaar.util.UnaryPredicate;
045:
046: /** This is an example of a User Interface Plugin.
047: It allows the user to specify the cluster from which
048: to obtain information, and the type of information to display:
049: log plan, expandable tasks, allocatable workflows,
050: assets (assigned to the cluster), and asset schedules (schedules
051: for assets allocated by the cluster).
052: The plan, tasks, and workflows are displayed as trees, and the
053: assets and scheduled assets are displayed as bar graphs.
054: The information displayed is monitored (if from a local cluster) for
055: additions, changes, and deletions, and the displays are updated.
056: This currently assumes there is only one plan ("Reality").
057: Future: When multiple plans are supported, the plans in each
058: cluster should be displayed, and the user should
059: select a plan for which to obtain information.
060:
061: This extends GenericPluginAdapter which provides the plugin
062: state transition methods. It implements the
063: UserInterfacePluginServesComponent interface which has one method,
064: serveUserInterfaceComponent which gets a reference to the component,
065: used later to obtain cluster object factories and cluster collections.
066: */
067: public class UIPlugin extends SimplePlugin implements UISubscriber {
068:
069: private ClusterServesPlugin uiComponent = null;
070: private Object componentLock = new Object();
071: private ClusterObjectFactory clusterObjectFactory = null;
072: private MessageAddress clusterIdentifier; // this cluster
073: private Plan plan;
074: private Hashtable subscribers = new Hashtable();
075: private Vector clusters = new Vector(10); // clusters we know about
076: private Vector assets = new Vector(10); // assets we know about
077:
078: protected void setupSubscriptions() {
079: getSubscriber().setShouldBePersisted(false);
080: clusterObjectFactory = getFactory();
081: plan = clusterObjectFactory.getRealityPlan();
082: synchronized (componentLock) {
083: this .uiComponent = getCluster();
084: componentLock.notifyAll();
085: }
086: rawSubscribe(this , assetPredicate());
087:
088: UIDisplay uiDisplay = new UIDisplay(this , getDelegate());
089: Thread gui = new Thread(uiDisplay);
090: gui.setName("uiPlugin:uiDisplay:" + gui.getName());
091: gui.start();
092: }
093:
094: /** Get the plan.
095: */
096:
097: Plan getPlan() {
098: waitUntilReady();
099: return plan;
100: }
101:
102: /** Get named plan. Return the only plan for now.
103: */
104:
105: Plan getPlan(String planName) {
106: waitUntilReady();
107: return plan;
108: }
109:
110: /** Subscribe to assets so we can get cluster ids for
111: tasks that the user creates and assets for displaying single
112: asset schedules.
113: */
114:
115: /** Get this cluster's cluster assets. */
116:
117: private static UnaryPredicate assetPredicate() {
118: return new UnaryPredicate() {
119: public boolean execute(Object o) {
120: //System.out.println("Predicate called with: " + o.toString());
121: return (o instanceof Asset);
122: }
123: };
124: }
125:
126: /** UISubscriber interface.
127: Notified when an asset is added, removed, or changed
128: and update our lists of all assets and cluster assets.
129: */
130:
131: public synchronized void subscriptionChanged(
132: IncrementalSubscription container) {
133: //System.out.println("Container changed");
134: Enumeration added = container.getAddedList();
135: Enumeration removed = container.getRemovedList();
136: while (added.hasMoreElements()) {
137: Object o = added.nextElement();
138: assets.addElement(o);
139: if (o instanceof Organization)
140: clusters.addElement(o);
141: }
142: while (removed.hasMoreElements()) {
143: Object o = removed.nextElement();
144: assets.removeElement(o);
145: if (o instanceof Organization)
146: clusters.removeElement(o);
147: }
148: }
149:
150: public Vector getClusterNames() {
151: Vector clusterNames = new Vector(clusters.size());
152: for (int i = 0; i < clusters.size(); i++) {
153: Organization cluster = (Organization) clusters.elementAt(i);
154: ItemIdentificationPG itemIdProp = cluster
155: .getItemIdentificationPG();
156: if (itemIdProp != null)
157: clusterNames.addElement(cluster.getMessageAddress());
158: }
159: return clusterNames;
160: }
161:
162: public Vector getPhysicalAssetNames() {
163: Vector assetNames = new Vector(assets.size());
164: String s = "";
165: for (int i = 0; i < assets.size(); i++) {
166: Asset a = (Asset) assets.elementAt(i);
167: if (a instanceof PhysicalAsset)
168: s = UIAsset.getName(a);
169: else if (a instanceof AggregateAsset) {
170: AggregateAsset aa = (AggregateAsset) a;
171: if (aa.getAsset() != null)
172: s = UIAsset.getName(aa.getAsset());
173: else
174: continue;
175: } else
176: continue;
177: if ((s == null) || s.equals(""))
178: continue;
179: assetNames.addElement(s);
180: }
181: return assetNames;
182: }
183:
184: public MessageAddress getClusterIdFromName(String clusterName) {
185: String s = "";
186: for (int i = 0; i < clusters.size(); i++) {
187: Organization cluster = (Organization) clusters.elementAt(i);
188: MessageAddress cid = cluster.getMessageAddress();
189: if (cid != null && cid.getAddress().equals(clusterName))
190: return cid;
191: }
192: return null;
193: }
194:
195: /** Wait until component this is plugged into identifies itself.
196: */
197:
198: private void waitUntilReady() {
199: synchronized (componentLock) {
200: while (uiComponent == null) {
201: try {
202: componentLock.wait();
203: } catch (InterruptedException e) {
204: }
205: }
206: }
207: }
208:
209: /** Called to subscribe to a cluster collection specified by the predicate.
210: When the cluster collection has changed, the uiPlugin will notify the
211: subscriber. Thus, all uiPlugin threads call this method to subscribe
212: to collections of their choice, and the uiPlugin notifies each when
213: its subscription has changed.
214: Synchronized to prevent execute from running before subscribe
215: "records" the subscriber and their subscription.
216: Carefully opens a transaction and then calls the lowlevel routine
217: rawSubscribe.
218: */
219: void subscribe(UISubscriber uiSubscriber, UnaryPredicate predicate) {
220: openTransaction();
221: rawSubscribe(uiSubscriber, predicate);
222: closeTransactionDontReset();
223: }
224:
225: /** do the work of subscribe() above. It is up to the caller to
226: * be careful of transaction issues.
227: **/
228: void rawSubscribe(UISubscriber uiSubscriber,
229: UnaryPredicate predicate) {
230: IncrementalSubscription container = (IncrementalSubscription) subscribe(predicate);
231: // record the container and the interested subscriber
232: synchronized (subscribers) {
233: subscribers.put(container, uiSubscriber);
234: }
235: }
236:
237: /** Called when any cluster collection has changed. Check which
238: cluster collections have changed and notify the subscriber.
239: Synchronized to prevent execute from running before subscribe
240: "records" the subscriber and their subscription.
241: */
242: public void execute() {
243: //System.out.println("Execute called");
244: synchronized (subscribers) {
245: Enumeration containers = subscribers.keys();
246: while (containers.hasMoreElements()) {
247: IncrementalSubscription container = (IncrementalSubscription) containers
248: .nextElement();
249: if (container.hasChanged()) {
250: UISubscriber uiSubscriber = (UISubscriber) subscribers
251: .get(container);
252: // if the user closed the display, there's no object associated
253: // with the container, so we remove it
254: if (uiSubscriber == null) {
255: // System.out.println("Removing container");
256: subscribers.remove(container);
257: } else
258: uiSubscriber.subscriptionChanged(container);
259: }
260: }
261: }
262: }
263: }
|