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.planning.ldm.lps;
028:
029: import java.util.Collection;
030:
031: import org.cougaar.core.blackboard.Directive;
032: import org.cougaar.core.domain.LogicProvider;
033: import org.cougaar.core.domain.MessageLogicProvider;
034: import org.cougaar.core.domain.RootPlan;
035: import org.cougaar.core.mts.MessageAddress;
036: import org.cougaar.core.util.UID;
037: import org.cougaar.planning.ldm.LogPlan;
038: import org.cougaar.planning.ldm.PlanningFactory;
039: import org.cougaar.planning.ldm.plan.AllocationforCollections;
040: import org.cougaar.planning.ldm.plan.Deletion;
041: import org.cougaar.planning.ldm.plan.PlanElement;
042: import org.cougaar.planning.ldm.plan.TaskRescind;
043: import org.cougaar.util.log.Logger;
044: import org.cougaar.util.log.Logging;
045:
046: /**
047: * take an incoming Deletion Directive and
048: * perform Modification to the LOGPLAN
049: **/
050: public class ReceiveDeletionLP implements LogicProvider,
051: MessageLogicProvider {
052: private final RootPlan rootplan;
053: private final LogPlan logplan;
054: private final PlanningFactory ldmf;
055: private final MessageAddress self;
056:
057: private static final Logger logger = Logging
058: .getLogger(ReceiveDeletionLP.class);
059:
060: public ReceiveDeletionLP(RootPlan rootplan, LogPlan logplan,
061: PlanningFactory ldmf, MessageAddress self) {
062: this .rootplan = rootplan;
063: this .logplan = logplan;
064: this .ldmf = ldmf;
065: this .self = self;
066: }
067:
068: public void init() {
069: }
070:
071: /**
072: * perform updates -- per Deletion ALGORITHM --
073: *
074: **/
075: public void execute(Directive dir, Collection changes) {
076: if (dir instanceof Deletion) {
077: processDeletion((Deletion) dir);
078: }
079: }
080:
081: /**
082: * The deletion prototol between agents.
083: * DeletionPlugin in agent B decides it can delete a task received
084: * from agent A. The task is marked as deleted and then removed.
085: * DeletionLP in agent B reacts to the remove, notes the removed
086: * task is deleted, and sends a Deletion directive to agent A.
087: * ReceiveDeletionLP (here) in agent A receives the Deletion
088: * directive, marks its copy of the remoteTask as deleted.
089: * Eventually our (agent A) DeletionPlugin will delete the parent
090: * task of the deleted remote task. When that happens the task
091: * will be "rescinded", but the rescind will be marked as the
092: * rescind of a deleted task.
093: * Agent B handles the rescind and the task is gone.
094: *
095: * Anomalies:
096: * 1) Agent A resends the task before receiving the Deletion. Agent
097: * B finds a deleted matching task and resends the Deletion
098: * directive (just in case, see below).
099: * 2a) Agent A restarts after receiving the Deletion, but before
100: * persisting or rescinding the deleted task. The task is
101: * rehydrated as not deleted. Normal resynchronization causes the
102: * task to be resent and a new Deletion is returned as in case 1
103: * above.
104: * 2b) Agent A restarts after receiving the Deletion, but before
105: * rescinding the deleted task. Normal resynchronization does not
106: * cause the task to be resent because the task is marked
107: * deleted.
108: * 3) Agent A restarts after sending the rescind and the task
109: * returns. This case is problematic because there is no record
110: * anywhere of its having been deleted. We resolve this by not
111: * sending tasks that end in the past. This means that tasks that
112: * are initially published having end times in the past will not
113: * be propagated. Such tasks are anomalous to begin with.
114: * 4) Agent B restarts after sending the Deletion, but before the
115: * task is rescinded and the deleted task is restored to its
116: * undeleted state. The notification from B to A signals that the
117: * task exists and is not deleted. This is at odds with A's
118: * state. Since the task has not yet been rescinded, the deleted
119: * status is removed.
120: * 5) Same as 4 except A _has_ rescinded the task. It's too late to
121: * stop the outgoing TaskRescind. B ignores it because it is
122: * marked as the rescind of a deleted task and the task is not
123: * deleted. B's notification to A causes the usual TaskRescind
124: * that is also ignored by B for the same reason.
125: **/
126: private void processDeletion(Deletion del) {
127: UID tuid = del.getTaskUID();
128: PlanElement pe = logplan.findPlanElement(tuid);
129: if (pe == null) {
130: // Must have been rescinded, fabricate a TaskRescind to ack the
131: // deletion
132: TaskRescind ntr = ldmf.newTaskRescind(
133: del.getChildTaskUID(), del.getSource(), true);
134: rootplan.sendDirective(ntr);
135: if (logger.isDebugEnabled())
136: logger.debug(self
137: + ": ignoring Deletion for deleted task");
138: } else {
139: ((AllocationforCollections) pe)
140: .setAllocationTaskDeleted(true);
141: if (logger.isDebugEnabled())
142: logger.debug(self + ": acking Deletion for " + tuid);
143: // Now the deleted remoteTask will simply hang around until the
144: // deletion plugin gets around to deleting its parent structure.
145: }
146: }
147: }
|