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.glm.ldm.lps;
028:
029: import java.util.ArrayList;
030: import java.util.Collection;
031: import java.util.Enumeration;
032:
033: import org.cougaar.core.blackboard.Envelope;
034: import org.cougaar.core.blackboard.EnvelopeTuple;
035: import org.cougaar.core.domain.EnvelopeLogicProvider;
036: import org.cougaar.core.domain.LogicProvider;
037: import org.cougaar.core.domain.RootPlan;
038: import org.cougaar.core.util.UID;
039: import org.cougaar.glm.ldm.asset.Organization;
040: import org.cougaar.glm.ldm.oplan.OrgActivity;
041: import org.cougaar.planning.ldm.PlanningFactory;
042: import org.cougaar.planning.ldm.asset.LocalPG;
043: import org.cougaar.planning.ldm.asset.LocationSchedulePG;
044: import org.cougaar.planning.ldm.asset.LocationSchedulePGImpl;
045: import org.cougaar.planning.ldm.asset.NewLocationSchedulePG;
046: import org.cougaar.planning.ldm.plan.Schedule;
047: import org.cougaar.planning.ldm.plan.ScheduleElement;
048: import org.cougaar.util.EmptyEnumeration;
049: import org.cougaar.util.log.Logger;
050: import org.cougaar.util.log.Logging;
051: import org.cougaar.util.UnaryPredicate;
052:
053: /**
054: * OPlanWatcherLP tracks OPlan changes, reconciling other objects to the OPlan(s).
055: * In particular, it updates the local Org asset with the required LocationSchedule changes.
056: **/
057: public class OPlanWatcherLP implements LogicProvider,
058: EnvelopeLogicProvider {
059: private static final Logger logger = Logging
060: .getLogger(OPlanWatcherLP.class);
061: private final RootPlan rootplan;
062: private final PlanningFactory ldmf;
063:
064: public OPlanWatcherLP(RootPlan rootplan, PlanningFactory ldmf) {
065: this .rootplan = rootplan;
066: this .ldmf = ldmf;
067: }
068:
069: public void init() {
070: }
071:
072: /**
073: * Catch interesting Oplan and Oplan component activity.
074: */
075: public void execute(EnvelopeTuple o, Collection changes) {
076: Object obj = o.getObject();
077: if (obj instanceof OrgActivity) {
078: processOrgActivity((OrgActivity) obj, o.getAction());
079: }
080: // else do nothing
081: }
082:
083: private void processOrgActivity(OrgActivity oa, int action) {
084: // find the matching Organization
085: final String orgID = oa.getOrgID();
086:
087: if (logger.isDebugEnabled()) {
088: logger.debug("OplanWatcherLP() - OrgActivity = " + oa
089: + " action = " + action);
090: }
091:
092: Organization org = null;
093: UnaryPredicate pred = new UnaryPredicate() {
094: public boolean execute(Object o) {
095: if (o instanceof Organization) {
096: return orgID.equals(((Organization) o)
097: .getMessageAddress().toString());
098: }
099: return false;
100: }
101: };
102: Enumeration en = rootplan.searchBlackboard(pred);
103: if (en != null && en.hasMoreElements()) {
104: org = (Organization) en.nextElement();
105: } else {
106: return;
107: }
108:
109: /*
110: // something like this would work if the world was sane...
111: // right now, we'd have to do something even uglier like
112: // findAsset("UIC/"+orgID);
113: // bleah!
114: Asset a = logplan.findAsset(orgID);
115:
116:
117: if (! (a instanceof Organization)) {
118: logger.error("OPlanWatcher() found non org asset " +
119: a + " in logplan by name: "+orgID);
120: return;
121: }
122: Organization org = (Organization) a;
123: */
124:
125: // get the pg
126: LocationSchedulePG lspg = org.getLocationSchedulePG();
127: if (lspg == null) {
128: org
129: .setLocationSchedulePG(lspg = new LocationSchedulePGImpl());
130: }
131:
132: // get the schedule
133: Schedule oldls = lspg.getSchedule();
134: Schedule newls;
135: if (oldls == null) {
136: newls = ldmf.newLocationSchedule(EmptyEnumeration
137: .getEnumeration());
138: } else {
139: newls = ldmf.newLocationSchedule(oldls
140: .getAllScheduleElements());
141: }
142:
143: final UID oaUID = oa.getUID(); // the uuid of the org activity.
144:
145: // find old element(s) in ls with matching oaUIDs
146: Collection found = newls.filter(new UnaryPredicate() {
147: public boolean execute(Object o) {
148: if (o instanceof OrgActivity.OAScheduleElement) {
149: return oaUID
150: .equals(((OrgActivity.OAScheduleElement) o)
151: .getOrgActivityUID());
152: } else {
153: return false;
154: }
155: }
156: });
157:
158: switch (action) {
159: case Envelope.ADD: {
160: if (found.size() > 0) {
161: logger
162: .warn("OPlanWatcher() saw redundant OrgActivity add for "
163: + oa);
164: }
165: ScheduleElement se = oa.getNormalizedScheduleElement();
166: if (se != null) {
167: newls.add(se);
168: }
169: }
170: break;
171: case Envelope.CHANGE: {
172: newls.removeAll(found);
173: ScheduleElement se = oa.getNormalizedScheduleElement();
174: if (se != null) {
175: newls.add(se);
176: }
177: }
178: break;
179: case Envelope.REMOVE:
180: newls.removeAll(found);
181: break;
182: default:
183: logger
184: .warn("OPlanWatcher() somehow caught random envelope type "
185: + action);
186: return;
187: }
188:
189: // MIK - deactive change marking. Various other LPs misunderstand changed
190: // orgs as relationship changes, leading to oplan repropagation, leading to
191: // reactivation of this LP leading to a spiraling recursion of death.
192: // The *right* thing to do is to publish with details, and change all the
193: // other LPs to pay attention to what changed, only reacting when/as
194: // appropriate. Yet another pre-demo hack.
195:
196: // RAY - Turned this back on since some plugins need to see
197: // updated location schedules. The offending plugin
198: // (PropagationPlugin) checks explicitly for
199: // RelationshipSchedule.RelationshipScheduleChangeReport
200: // ChangeReports and re-propagates IFF the changes include such a
201: // ChangeReport
202:
203: // mark the object as having changed...maybe we should forward the changes?
204:
205: // Mark the org as only having changed local things
206: // AssetReportPlugin - which is responsible for forwarding the changes to the org
207: // to other agents - will look for this change report, and avoid propogating
208: // the change if it was only such LocalPG changes
209: Collection changes = new ArrayList();
210: changes.add(new LocalPG.LocalPGChangeReport());
211: ((NewLocationSchedulePG) lspg).setSchedule(newls);
212: rootplan.change(org, changes);
213: }
214: }
|