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.plugin.organization;
028:
029: import java.util.Collection;
030: import java.util.Iterator;
031: import java.util.List;
032:
033: import org.cougaar.util.UnaryPredicate;
034:
035: import org.cougaar.core.mts.MessageAddress;
036:
037: import org.cougaar.core.blackboard.IncrementalSubscription;
038: import org.cougaar.core.plugin.ComponentPlugin;
039: import org.cougaar.core.service.EventService;
040: import org.cougaar.core.service.LoggingService;
041: import org.cougaar.core.service.UIDService;
042:
043: import org.cougaar.glm.ldm.asset.Organization;
044:
045: import org.cougaar.planning.ldm.asset.Asset;
046: import org.cougaar.planning.ldm.asset.ClusterPG;
047: import org.cougaar.planning.ldm.plan.PrepositionalPhrase;
048: import org.cougaar.planning.ldm.plan.Task;
049: import org.cougaar.planning.ldm.plan.Verb;
050: import org.cougaar.planning.ldm.predicate.TaskPredicate;
051:
052: /**
053: * Plugin for noticing when SUPERIOR/SUBORDINATE report relationship
054: * chain is complete for whole society.
055: * This Plugin goes in every agent in the chain, with an argument
056: * indicating the expected number of subordinates.
057: * Each agent relays to its superior when all of its subordinates
058: * have reported in with the relay. At the head of the report chain,
059: * a Cougaar Event is published when the chain is complete.
060: * This can be used to signal when it is safe to send Tasks
061: * that must reach every agent in the report chain.
062: * See, for example, GLSInitServlet.
063: **/
064: public class ReportChainDetectorPlugin extends ComponentPlugin {
065: private LoggingService logSvc = null;
066: private UIDService uidService = null;
067: private EventService evtSvc = null;
068:
069: private int numSubs = 0;
070: private ReportChainState reportChainState = null;
071:
072: private IncrementalSubscription readySub = null;
073: private IncrementalSubscription dutySub = null;
074: private IncrementalSubscription stateSub = null;
075: private IncrementalSubscription selfOrgSub = null;
076:
077: // Subscribe to relays indicating subordinates are ready
078: private class ReadyPredicate implements UnaryPredicate {
079: public ReadyPredicate() {
080: }
081:
082: public boolean execute(Object obj) {
083: return (obj instanceof ReportChainReadyRelay);
084: }
085: }
086:
087: // Get the ReportForDuty task where this Agent is reporting to its Superior
088: // -- not its SupportSuperior
089: private class DutyPredicate extends TaskPredicate {
090: public DutyPredicate() {
091: super ();
092: }
093:
094: public boolean execute(Task task) {
095: // Change this to get on Superior, not SupportSuperior
096: if (task.getVerb().equals(Verb.get("ReportForDuty"))) {
097: // Look at the roles in the AS prepositional phrase. That's
098: // what's used to construct that the AssetTransfer.
099: PrepositionalPhrase pp = task
100: .getPrepositionalPhrase(org.cougaar.planning.Constants.Preposition.AS);
101: if (pp == null)
102: return false;
103: Collection roles = (Collection) pp.getIndirectObject();
104: if (roles == null)
105: return false;
106: // This collection should contain "Subordinate"
107: return roles
108: .contains(org.cougaar.glm.ldm.Constants.Role.ADMINISTRATIVESUBORDINATE);
109: }
110: return false;
111: }
112: }
113:
114: // Subscribe the the ReportChainState objects
115: private class ReportChainStatePredicate implements UnaryPredicate {
116: public ReportChainStatePredicate() {
117: }
118:
119: public boolean execute(Object obj) {
120: return (obj instanceof ReportChainState);
121: }
122: }
123:
124: /**
125: * The predicate for the Self org subscription
126: **/
127: private static class SelfOrgAssetPredicate implements
128: UnaryPredicate {
129: public SelfOrgAssetPredicate() {
130: }
131:
132: public boolean execute(Object o) {
133:
134: if (o instanceof Organization) {
135: Organization org = (Organization) o;
136: return org.isLocal();
137: }
138: return false;
139: }
140: };
141:
142: // Get the various services
143: public void setLoggingService(LoggingService logSvc) {
144: this .logSvc = logSvc;
145: }
146:
147: public void setEventService(EventService evtSvc) {
148: this .evtSvc = evtSvc;
149: }
150:
151: public void setUIDService(UIDService uidService) {
152: this .uidService = uidService;
153: }
154:
155: private void debug(String msg) {
156: if (logSvc.isDebugEnabled()) {
157: logSvc.debug("ReportChainDetectorPlugin: " + getSelf()
158: + ": " + msg);
159: }
160: }
161:
162: public void setupSubscriptions() {
163: readySub = (IncrementalSubscription) getBlackboardService()
164: .subscribe(new ReadyPredicate());
165: dutySub = (IncrementalSubscription) getBlackboardService()
166: .subscribe(new DutyPredicate());
167: stateSub = (IncrementalSubscription) getBlackboardService()
168: .subscribe(new ReportChainStatePredicate());
169: selfOrgSub = (IncrementalSubscription) getBlackboardService()
170: .subscribe(new SelfOrgAssetPredicate());
171:
172: List params = (List) getParameters();
173: numSubs = Integer.parseInt(params.get(0).toString());
174: debug("init " + params.get(0) + " subs");
175:
176: // Initialize reportChainState
177: getState();
178: }
179:
180: public void execute() {
181:
182: // Check whether we're ready to send ReportChainReadyRelay
183: if (!getState().isChainReady()) {
184: // First handle ReadyForOplan
185: // If more people reported in, or we just reported in, now might
186: // be ready to sendReportChainReady
187: if ((dutySub.getAddedCollection().size() > 0)
188: || (readySub.getAddedCollection().size() > 0)
189: || (selfOrgSub.hasChanged())) {
190:
191: // Don't get the collections unless we logging debug level messages
192: if (logSvc.isDebugEnabled()) {
193: if (dutySub.getAddedCollection().size() > 0)
194: debug("ReportForDuty seen.");
195: if (readySub.getAddedCollection().size() > 0)
196: debug("ReportChainReadyRelay received.");
197: if (selfOrgSub.hasChanged()) {
198: debug("Self Org has changed.");
199: }
200: }
201:
202: if (isChainReady()) {
203: sendReportChainReady();
204: }
205: }
206: }
207: }
208:
209: public void log(String message) {
210: if (logSvc.isInfoEnabled())
211: logSvc.info(message);
212: }
213:
214: public void event(String type, String message) {
215: if (evtSvc != null) {
216: if (evtSvc.isEventEnabled()) {
217: evtSvc.event("[" + type + "] " + message);
218: }
219: }
220: }
221:
222: // Is this the top of the report chain?
223: public boolean isChainHead() {
224: // boolean nameSaysHead = getSelf().toString().equals("NCA") || getSelf().toString().equals("OSD.GOV");
225: // the above is the non-general solution.
226:
227: // The OrgDataPlugin creates the ReportForDuty tasks,
228: // and that happens when that plugin loads.
229: // So there is no room for timing problems if we just look
230: // for those tasks. Note of course that there are 2 kinds of RFD
231: // tasks. Superior & SupportSuperior. I want Superior - although
232: // NCA should have neither.
233:
234: // A naive solution had been to look for the Superior relationship
235: // on the selfOrg. The problem with that is that
236: // the superior relationship happens only after the OrgReportPlugin
237: // closes its first transaction (allowing an LP to run).
238: // So an agent with no subs might have this plugin run before
239: // the OrgReportPlugin, and therefore be done with its
240: // subs before it has created its superior relationships,
241: // so it might think it was the Chain Head, so it
242: // sends the event, and never reports to its superior,
243: // so the real head never reports it is done.
244:
245: // So correct logic is to return false if have no self org,
246: // false if have a ReportForDuty to a SUPERIOR,
247: // false if have a relationship with a superior, otherwise true
248: return !hasSuperior();
249: }
250:
251: // Does this agent have a superior organization?
252: // If the selfOrg is not here yet, assume that it does.
253: // If have a ReportForDuty, then it does.
254: // In other words, only return false if the selfOrg is there,
255: // and there is no ReportForDuty task and no SUPERIOR relationship
256: private boolean hasSuperior() {
257: Organization selfOrg = (Organization) selfOrgSub.first();
258:
259: if (selfOrg == null) {
260: // If we dont yet have a self org, assume were going
261: // to have a superior later, to avoid being the one with no superior
262: debug("No selfOrg");
263: return true;
264: }
265:
266: // If there is a ReportForDuty task that points to someone,
267: // that someone is a superior
268: if (getSuperior() != null) {
269: debug("getSuperior not null");
270: return true;
271: } else {
272: int rfds = dutySub.size();
273: if (rfds > 0) {
274: debug("getSuperior is null. RFD sub shows " + rfds
275: + ".");
276: return true;
277: }
278: }
279:
280: // This next is true once the LP sends the RFD task
281: Collection super iorRelationships = selfOrg
282: .getRelationshipSchedule()
283: .getMatchingRelationships(
284: org.cougaar.glm.ldm.Constants.Role.ADMINISTRATIVESUPERIOR);
285: if (super iorRelationships.size() == 0) {
286: debug("No superior relationships");
287: return false;
288: }
289:
290: return true;
291: }
292:
293: // If all our subordinates have reported they are ready, and either
294: // we have created the ReportForDuty task or we have no superior (and need none),
295: // then the report chain is ready for tasks
296: public boolean isChainReady() {
297: Organization selfOrg = (Organization) selfOrgSub.first();
298:
299: if (selfOrg == null) {
300: return false;
301: }
302:
303: Collection subordinateRelationships = selfOrg
304: .getRelationshipSchedule()
305: .getMatchingRelationships(
306: org.cougaar.glm.ldm.Constants.Role.ADMINISTRATIVESUBORDINATE);
307:
308: // Return true iff
309: // a) my RelationshipSchedule has the expected number of subordinates
310: // b) all my subs have reported (via ReportChainReadyRelay) that all their subs
311: // have reported to them
312: if ((subordinateRelationships.size() == numSubs)
313: && (readySub.size() == numSubs)
314: && ((getSuperior() != null) || isChainHead())) {
315: return true;
316: } else {
317: debug("Report Chain Not Ready: " + readySub.size()
318: + " reporting.");
319: return false;
320: }
321: }
322:
323: // Get the Current report state object from the BBoard (create if necc)
324: public ReportChainState getState() {
325: if (reportChainState == null) {
326: if (stateSub.size() == 0) {
327: ReportChainState RC = new ReportChainState(uidService
328: .nextUID());
329: getBlackboardService().publishAdd(RC);
330: reportChainState = RC;
331: } else {
332: Iterator states = stateSub.iterator();
333: reportChainState = (ReportChainState) states.next();
334: }
335: }
336:
337: return reportChainState;
338: }
339:
340: public MessageAddress getSelf() {
341: return getAgentIdentifier();
342: }
343:
344: // Get the address for our superior
345: private MessageAddress super ior = null;
346:
347: // Use the ReportForDuty task we subscribed to -- just grab the direct object
348: public MessageAddress getSuperior() {
349: if (super ior != null)
350: return super ior;
351:
352: if (dutySub.size() == 0) {
353: debug("No ReportForDuty found.");
354: return null;
355: }
356:
357: // FIXME: There are 2 kinds of superiors. I only want the SUPERIOR,
358: // not the SupportSuperior (ADMINISTRATIVE_SUPERIOR?)
359:
360: // Question: Is it possible for the RFD task to be there, but
361: // for any of these other "return null" escapes to happen, without
362: // a broken RFD task?
363: // Put another way: Is it possible for this getSuperior() task to
364: // return null for any agent that has a superior, if no error occurs?
365:
366: Iterator sups = dutySub.iterator();
367: Task dutyT = (Task) sups.next();
368: if (dutyT == null)
369: return null;
370: PrepositionalPhrase pp = dutyT
371: .getPrepositionalPhrase(org.cougaar.planning.Constants.Preposition.FOR);
372: if (pp == null)
373: return null;
374: Asset a = (Asset) pp.getIndirectObject();
375: if (a == null)
376: return null;
377: ClusterPG cpg = a.getClusterPG();
378: if (cpg == null)
379: return null;
380: return cpg.getMessageAddress();
381: }
382:
383: // Send a relay to our Superior indicating when our piece of the report
384: // chain is ready, ie we're ready for Tasks
385: public void sendReportChainReady() {
386: ReportChainState state = getState();
387: if ((getSuperior() == null) && !isChainHead()) {
388: // We should have a superior to report in to, but don't have it yet
389: return;
390: }
391:
392: // If we have not already transitioned to ReportChainReady state (ie dont do this twice)
393: if (!state.isChainReady()) {
394: state.setChainReady(true);
395: getBlackboardService().publishChange(state);
396:
397: debug("Report Chain Ready.");
398:
399: // Head of report chain (ie NCA) sends a CougaarEvent
400: // Indicating entire society has created report chain
401: if (isChainHead()) {
402: event("STATUS",
403: "ReportChainDetectorPlugin: Report Chain Ready");
404: }
405:
406: // Agent with a superior sends a relay to the superior
407: if (!isChainHead()) {
408: ReportChainReadyRelay opr = new ReportChainReadyRelay(
409: uidService.nextUID(), getSelf(), getSuperior(),
410: getSelf());
411: getBlackboardService().publishAdd(opr);
412: }
413: }
414: }
415: }
|