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.ArrayList;
030: import java.util.Collection;
031: import java.util.Enumeration;
032: import java.util.Iterator;
033:
034: import org.cougaar.core.blackboard.Directive;
035: import org.cougaar.core.blackboard.EnvelopeTuple;
036: import org.cougaar.core.domain.EnvelopeLogicProvider;
037: import org.cougaar.core.domain.LogicProvider;
038: import org.cougaar.core.domain.RootPlan;
039: import org.cougaar.core.mts.MessageAddress;
040: import org.cougaar.core.util.UID;
041: import org.cougaar.planning.ldm.LogPlan;
042: import org.cougaar.planning.ldm.PlanningFactory;
043: import org.cougaar.planning.ldm.asset.Asset;
044: import org.cougaar.planning.ldm.asset.ClusterPG;
045: import org.cougaar.planning.ldm.plan.Aggregation;
046: import org.cougaar.planning.ldm.plan.Allocation;
047: import org.cougaar.planning.ldm.plan.AllocationforCollections;
048: import org.cougaar.planning.ldm.plan.AssetRescind;
049: import org.cougaar.planning.ldm.plan.AssetTransfer;
050: import org.cougaar.planning.ldm.plan.AssignedAvailabilityElement;
051: import org.cougaar.planning.ldm.plan.Composition;
052: import org.cougaar.planning.ldm.plan.Disposition;
053: import org.cougaar.planning.ldm.plan.Expansion;
054: import org.cougaar.planning.ldm.plan.HasRelationships;
055: import org.cougaar.planning.ldm.plan.NewSchedule;
056: import org.cougaar.planning.ldm.plan.MPTask;
057: import org.cougaar.planning.ldm.plan.PlanElement;
058: import org.cougaar.planning.ldm.plan.Relationship;
059: import org.cougaar.planning.ldm.plan.RelationshipSchedule;
060: import org.cougaar.planning.ldm.plan.Schedule;
061: import org.cougaar.planning.ldm.plan.ScheduleElement;
062: import org.cougaar.planning.ldm.plan.Task;
063: import org.cougaar.planning.ldm.plan.TaskRescind;
064: import org.cougaar.planning.ldm.plan.Workflow;
065: import org.cougaar.planning.ldm.plan.WorkflowImpl;
066: import org.cougaar.util.Enumerator;
067: import org.cougaar.util.MutableTimeSpan;
068: import org.cougaar.util.PropertyParser;
069: import org.cougaar.util.UnaryPredicate;
070: import org.cougaar.util.log.Logger;
071: import org.cougaar.util.log.Logging;
072:
073: /** RescindLogicProvider class provides the logic to capture
074: * rescinded PlanElements (removed from collection)
075: *
076: * Attempts to do a complete LogPlan rescind walk, not depending on
077: * being re-called to do the "next" level of rescind.
078: * @property org.cougaar.planning.ldm.lps.RescindLP.checkBadTask defaults to true: When true, check for consistent Task & PEs on publishAdd/Remove
079: * @property org.cougaar.planning.ldm.lps.RescindLP.removeBadTask. When this & checkBadTask are true, will also remove bad Tasks/PEs if the above checks suggest it. Defaults to true.
080: **/
081: public class RescindLP implements LogicProvider, EnvelopeLogicProvider {
082:
083: private static final Logger logger = Logging
084: .getLogger(RescindLP.class);
085:
086: // If true, check for link consistency on Task/PE add/remove
087: private static final boolean CHECKCONSISTENCY = PropertyParser
088: .getBoolean(
089: "org.cougaar.planning.ldm.lps.RescindLP.checkBadTask",
090: true);
091:
092: // If true and find inconsistencies above, clean up
093: // where possible
094: private static final boolean DOREMOVES = PropertyParser.getBoolean(
095: "org.cougaar.planning.ldm.lps.RescindLP.removeBadTask",
096: true);
097:
098: private final RootPlan rootplan;
099: private final LogPlan logplan;
100: private final PlanningFactory ldmf;
101: private final MessageAddress self;
102:
103: //private List conflictlist = new ArrayList();
104:
105: public RescindLP(RootPlan rootplan, LogPlan logplan,
106: PlanningFactory ldmf, MessageAddress self) {
107: this .rootplan = rootplan;
108: this .logplan = logplan;
109: this .ldmf = ldmf;
110: this .self = self;
111: }
112:
113: public void init() {
114: }
115:
116: /**
117: * @param o EnvelopeTuple
118: * where Envelope.Tuple.object is an ADDED PlanElement which contains
119: * an Allocation to an agent asset.
120: * Do something if the test returned true i.e. it was a PlanElement being removed
121: **/
122: public void execute(EnvelopeTuple o, Collection changes) {
123: // drop changes
124: Object obj = o.getObject();
125: if (o.isRemove()) {
126: if (obj instanceof Task) { // task
127: taskRemoved((Task) obj);
128: } else if (obj instanceof PlanElement) { // PE
129: planElementRemoved((PlanElement) obj);
130: }
131: } else if (o.isAdd()) {
132: if (obj instanceof DeferredRescind) {
133: processDeferredRescind((DeferredRescind) obj);
134: } else if (obj instanceof PlanElement) {
135: planElementAdded((PlanElement) obj);
136: } else if (obj instanceof Task) {
137: taskAdded((Task) obj);
138: }
139: } else if (o.isChange()) {
140: if (obj instanceof Task)
141: taskChanged((Task) obj);
142: }
143: }
144:
145: private void taskChanged(Task t) {
146: // we really dont care. But use this opportunity to check for consistent blackboard objects
147: // You should not publishChange a Task that is "inconsistent" (ie no parent).
148:
149: // FIXME: Does this check things that could be broken temporarily for a task thats changing?
150: // Will the deferred rescind do the right thing?
151: if (CHECKCONSISTENCY) {
152: if (!isTaskConsistent(t, "Changed Task")) {
153: // create & publish new DeferredRescind
154: if (logger.isDebugEnabled())
155: logger
156: .debug(self
157: + ": Adding deferred rescind of inconsistent task "
158: + t);
159: rootplan.add(new DeferredRescind(t, "Changed Task"));
160: }
161: }
162: }
163:
164: private void taskAdded(Task t) {
165: // If the task has no parent, maybe it was just removed.
166: // Do a DeferredRescind(checking) and see if that's still true.
167: // If so, remove this task.
168:
169: // Also, if the task results from an Expansion or Aggregation, but that PE is not there, do similar.
170: if (CHECKCONSISTENCY) {
171: if (!isTaskConsistent(t, "Added Task")) {
172: // create & publish new DeferredRescind
173: if (logger.isDebugEnabled())
174: logger
175: .debug(self
176: + ": Adding deferred rescind of inconsistent task "
177: + t);
178: rootplan.add(new DeferredRescind(t, "Added Task"));
179: }
180: }
181: }
182:
183: // The type is a string indicating the kind of task we are checking - or more appropriately, when:
184: // Added Task, Changed Task, Added PE's Task, Removed PE's Task.
185: private boolean isTaskConsistent(Task t, String type) {
186: return ConsistencyChecker.isTaskConsistent(self, logger,
187: logplan, t, type);
188: }
189:
190: private void planElementAdded(PlanElement pe) {
191: if (!ConsistencyChecker.isPlanElementConsistent(self, logger,
192: logplan, pe, CHECKCONSISTENCY)) {
193: removePlanElement(pe, true);
194:
195: // Unless we're doing debug logging, skip out here.
196: // Note that this means an inconsistent PE
197: // will not have its Tasks consistency checked
198: if (!logger.isDebugEnabled())
199: return;
200: }
201:
202: if (!CHECKCONSISTENCY)
203: return;
204:
205: // If the task referenced by this PlanElement is inconsistent, remove it.
206: Task task = pe.getTask();
207: if (!isTaskConsistent(task, "Added PE's Task")) {
208: // create & publish new DeferredRescind
209: if (logger.isDebugEnabled())
210: logger
211: .debug(self
212: + ": Adding deferred rescind of inconsistent task "
213: + task);
214: rootplan.add(new DeferredRescind(task, "Added PE's Task"));
215: }
216: }
217:
218: private void removeTaskFromWorkflow(Task t) {
219: if (t == null)
220: return;
221: WorkflowImpl w = (WorkflowImpl) t.getWorkflow();
222: if (w == null)
223: return;
224:
225: boolean hasSub = false;
226: synchronized (w) {
227: Enumeration en = w.getTasks();
228: while (en.hasMoreElements()) {
229: Task subT = (Task) en.nextElement();
230: if (subT == t) {
231: hasSub = true;
232: break;
233: }
234: }
235: }
236:
237: if (hasSub) {
238: if (logger.isInfoEnabled())
239: logger.info(self
240: + " removing task from workflow. Task: " + t);
241: w.removeTask(t);
242: }
243: }
244:
245: private void processDeferredRescind(DeferredRescind deferredRescind) {
246: if (deferredRescind.tr != null) {
247: UID rtuid = deferredRescind.tr.getTaskUID();
248: Task t = logplan.findTask(rtuid);
249: if (t != null) {
250: if (logger.isDebugEnabled())
251: logger
252: .debug(self
253: + ": Found task for DeferredRescind. Removing "
254: + t);
255: removeTask(t);
256: rootplan.remove(deferredRescind);
257: } else {
258: if (logger.isDebugEnabled())
259: logger
260: .debug(self
261: + ": Never found task for DeferredRescind. Giving up on "
262: + rtuid);
263: rootplan.remove(deferredRescind);
264: }
265: } else if (deferredRescind.t != null) {
266: // Check consistency as above.
267: // assert CHECKCONSISTENCY == true
268: if (!isTaskConsistent(deferredRescind.t,
269: deferredRescind.type)) {
270: if (DOREMOVES) {
271: if (logger.isInfoEnabled())
272: logger
273: .warn(self
274: + ": "
275: + deferredRescind.type
276: + " inconsistent after deferral, removing: "
277: + deferredRescind.t);
278: // FIXME: remove parent task & PE too?
279: // If task is in a workflow, must first remove it from the workflow
280: removeTaskFromWorkflow(deferredRescind.t);
281: removeTask(deferredRescind.t);
282: } else {
283: if (logger.isInfoEnabled())
284: logger
285: .warn(self
286: + ": "
287: + deferredRescind.type
288: + " inconsistent after deferral, NOT REMOVING: "
289: + deferredRescind.t);
290: rootplan.remove(deferredRescind);
291: }
292: } else {
293: if (logger.isInfoEnabled())
294: logger
295: .info(self
296: + ": "
297: + deferredRescind.type
298: + " was not, now is consistent after deferral. Leaving: "
299: + deferredRescind.t);
300: rootplan.remove(deferredRescind);
301: }
302:
303: }
304: }
305:
306: /** remove PE and any cascade objects */
307: private void removePlanElement(PlanElement pe, boolean force) {
308: if (pe != null) {
309: // FIXME: Should this be lp.find(pe.getTask()) == pe??
310: if (force || logplan.findPlanElement(pe.getTask()) != null) {
311: rootplan.remove(pe);
312: // planElementRemoved(pe);
313: }
314: }
315: }
316:
317: /** rescind the cascade of any PE (does not remove the PE) */
318: private void planElementRemoved(PlanElement pe) {
319: // Is the PE on the LogPlan or the Task? - if it is, re remove it
320: Task t = pe.getTask();
321: if (CHECKCONSISTENCY && t != null) {
322: // First, check that the PEs Task is consistent - plan to remove it if not
323: if (!isTaskConsistent(t, "Removed PE's Task")) {
324: // create & publish new DeferredRescind
325: if (logger.isDebugEnabled())
326: logger
327: .debug(self
328: + ": Adding deferred rescind of inconsistent task "
329: + t);
330: rootplan
331: .add(new DeferredRescind(t, "Removed PE's Task"));
332: }
333:
334: // Now check that the various pointers to the PE agree
335: PlanElement bPE = logplan.findPlanElement(t);
336: PlanElement tPE = t.getPlanElement();
337: if (bPE == pe) {
338: // removed PE still listed as on the LogPlan under it's task
339: if (tPE == pe) {
340: // removed PE still pointed to by it's task
341: // So the PE is on the LogPlan
342: // and the task points to it - it's as though
343: // it never happened at all. Leave it?
344: if (logger.isWarnEnabled())
345: logger
346: .warn(self
347: + ": Removed PE still on LogPlan and Task points to it. PE: "
348: + pe.getUID() + ":" + pe
349: + ", Task: " + t);
350: if (DOREMOVES) {
351: removePlanElement(pe, true);
352: // Do the follow-on the next time around...
353: // FIXME: Log what I expect to happen?
354: return;
355: }
356: } else if (tPE == null) {
357: // the ASO link fixing happened by the PE
358: // is still on the LogPlan.
359: // Re-remove the PE
360: if (logger.isWarnEnabled())
361: logger
362: .warn(self
363: + ": Removed PE still on LogPlan though Task points to no PE. Re removing it. PE: "
364: + pe.getUID() + ":" + pe
365: + ", Task: " + t);
366: if (DOREMOVES) {
367: removePlanElement(pe, true);
368: // Do the follow-on the next time around...
369: return;
370: }
371: } else {
372: // the ASO link fixing happened by the PE and another
373: // PE is pointed to?
374: // is still on the LogPlan.
375: // Re-remove the PE
376: if (logger.isWarnEnabled())
377: logger
378: .warn(self
379: + ": Removed PE still on LogPlan though Task doesn't point to it. Re removing it. PE: "
380: + pe.getUID() + ":" + pe
381: + ", Task: " + t
382: + ". Task points to PE: "
383: + tPE.getUID() + ":" + tPE);
384: if (DOREMOVES) {
385: removePlanElement(pe, true);
386: // Do the follow-on the next time around...
387: return;
388: }
389: }
390: } else if (tPE != bPE) {
391: if (tPE == pe) {
392: // The PE is gone from the LogPlan, but
393: // the task still points to it. As though
394: // the ASO stuff didn't happen but the LogPlan stuff did.
395: // Note that bboard may have null or different PE
396: if (logger.isWarnEnabled())
397: logger
398: .warn(self
399: + ": Removed PE not on LogPlan but Task still points to it. Re-removing. PE: "
400: + pe.getUID()
401: + ":"
402: + pe
403: + ", Task: "
404: + t
405: + ". Logplan has "
406: + (bPE == null ? "null" : (bPE
407: .getUID()
408: + ":" + bPE)));
409: if (DOREMOVES) {
410: removePlanElement(pe, true);
411: return;
412: }
413: } else {
414: // Removed PE not on LogPlan and not pointed to.
415: // But it's task also doesn't point to the PE
416: // that is on the LogPlan under it's UID
417: // Task's PE may be null or different
418: if (logger.isInfoEnabled())
419: logger
420: .info(self
421: + " Removed PE was removed, but it's Task points to different PE than what LogPlan has under its UID. Task: "
422: + t
423: + ", LogPlan's PE: "
424: + (bPE == null ? "null" : (bPE
425: .getUID()
426: + ":" + bPE))
427: + ", Task's PE: "
428: + (tPE == null ? "null" : (tPE
429: .getUID()
430: + ":" + tPE)));
431: }
432: }
433: } // end of error check PE removal
434:
435: //logger.printDot("p");
436: if (pe instanceof Allocation) {
437: // remove planelement from the asset's roleschedule
438: //removePERS(pe);
439: allocationRemoved((Allocation) pe);
440: } else if (pe instanceof Expansion) {
441: // Do nothing
442: } else if (pe instanceof AssetTransfer) {
443: // remove planelement from the asset's roleschedule
444: //removePERS(pe);
445: assetTransferRemoved((AssetTransfer) pe);
446: } else if (pe instanceof Aggregation) {
447: // Do nothing
448: } else if (pe instanceof Disposition) {
449: // do nothing since its the end of the line
450: } else {
451: logger.error(self + ": Unknown planelement " + pe,
452: new Throwable());
453: }
454: }
455:
456: /** rescind the cascade of an allocation */
457: private void allocationRemoved(Allocation all) {
458: //logger.printDot("a");
459: Asset a = all.getAsset();
460: ClusterPG cpg = a.getClusterPG();
461: if (cpg != null) {
462: MessageAddress cid = cpg.getMessageAddress();
463: if (cid != null) {
464: UID remoteUID = ((AllocationforCollections) all)
465: .getAllocationTaskUID();
466: if (remoteUID != null) {
467: if (logger.isDebugEnabled())
468: logger
469: .debug(self
470: + ": Removed Allocation, so will propagate and rescind alloc task. Alloc: "
471: + all + ", alloc task: "
472: + remoteUID);
473: TaskRescind trm = ldmf.newTaskRescind(remoteUID,
474: cid);
475: ((AllocationforCollections) all)
476: .setAllocationTaskUID(null);
477: rootplan.sendDirective((Directive) trm);
478: }
479: }
480: }
481: }
482:
483: /** remove a task and any PE addressing it */
484: private void removeTask(Task task) {
485: if (task != null) {
486: rootplan.remove(task);
487: }
488: }
489:
490: /** remove the PE associated with a task (does not remove the task) */
491: private void taskRemoved(Task task) {
492: if (CHECKCONSISTENCY) {
493: // Is the task on the LogPlan? If it is, re remove it
494: Task bT = logplan.findTask(task.getUID());
495: if (bT == task) {
496: if (DOREMOVES) {
497: if (logger.isWarnEnabled())
498: logger
499: .warn(self
500: + ": removed Task still on LogPlan? Re-removing "
501: + task);
502: removeTask(task);
503: return; // Do the follow-on cleanup the next time around
504: } else {
505: if (logger.isWarnEnabled())
506: logger.warn(self
507: + ": removed Task still on LogPlan? "
508: + task);
509: }
510: } else if (bT != null) {
511: if (logger.isWarnEnabled())
512: logger
513: .warn(self
514: + ": removed Task UID listed as on LogPlan, but it's a different object. Removed "
515: + task + " and LogPlan has " + bT);
516: // FIXME: Remove task? bT?
517: return;
518: }
519: } // end of consistency checks
520:
521: // get the planelement with this task
522: PlanElement taskpe = task.getPlanElement();
523:
524: // FIXME: Does taskpe point to this task? Doe bpe point to this task?
525: Task taskpetask = null;
526: Task bpetask = null;
527:
528: PlanElement bpe = null;
529: if (CHECKCONSISTENCY) {
530: if (taskpe != null)
531: taskpetask = taskpe.getTask();
532: bpe = logplan.findPlanElement(task);
533: if (bpe != null)
534: bpetask = bpe.getTask();
535: if (taskpe != bpe) {
536: // Task and logplan reference different PEs for this Task
537: if (taskpe == null) {
538: // Task has no PE link (as though the PE had already been removed)
539: // But the logplan has a PE still
540: // Presumably a publishRemove(PE) just happened in another transaction,
541: // but has not finished.
542: if (logger.isInfoEnabled())
543: logger
544: .info(self
545: + ": Removed Task has no PE, but LogPlan still lists a PE under this UID. Task: "
546: + task + ", LogPlan's PE: "
547: + bpe.getUID() + ":" + bpe
548: + ". LogPlan PE's Task: "
549: + bpetask);
550: } else if (bpe == null) {
551: // Presumably a publishAdd(PE) just happened in another transaction,
552: // but has not finished
553: if (logger.isInfoEnabled())
554: logger
555: .info(self
556: + ": Removed task lists a PE, but LogPlan has no PE under this UID. Task: "
557: + task + ", Task's PE: "
558: + taskpe.getUID() + ":"
559: + taskpe
560: + ". Task's PE's Task: "
561: + taskpetask);
562: } else {
563: if (logger.isWarnEnabled()) {
564: logger
565: .warn(self
566: + ": Removed task lists a different PE than LogPlan has. Task: "
567: + task + ", Task's PE: "
568: + taskpe.getUID() + ":"
569: + taskpe + ", LogPlan's PE: "
570: + bpe.getUID() + ":" + bpe);
571: if (logger.isInfoEnabled()) {
572: logger.info(self
573: + "..... Task's PE's Task: "
574: + taskpetask
575: + ", LogPlan's PE's Task: "
576: + bpetask);
577: }
578: }
579: }
580: } else {
581: // taskpe == bpe
582: if (bpe == null) {
583: // Removed task has no PE and neither does LogPlan
584: } else if (taskpetask != task) {
585: if (logger.isInfoEnabled())
586: logger
587: .info(self
588: + ": Removed Task lists same PE as LogPlan has for it, but the PE points to a different Task. Task: "
589: + task + ", Task's PE: "
590: + taskpe.getUID() + ":"
591: + taskpe
592: + ". Task's PE's Task: "
593: + taskpetask);
594: }
595: } // end of consistency checks
596:
597: // rescind (or remove) this planelement from the logplan
598: if (DOREMOVES && bpe != null) {
599: removePlanElement(bpe, false);
600: }
601: }
602:
603: // If we didn't just remove the only PE above, remove
604: // the pe referenced by the task
605: if (taskpe != bpe && taskpe != null) {
606: // A false below would mean that if bpe == null then taskpe won't
607: // be removed. That's old behavior.
608: // Use DOREMOVES to toggle this.
609: removePlanElement(taskpe, DOREMOVES);
610: }
611: }
612:
613: /** remove the cascade associated with an AssetTransfer **/
614: private void assetTransferRemoved(AssetTransfer at) {
615: // create an AssetRescind message
616: Schedule rescindSchedule;
617:
618: //Remove info from local assets
619: Asset localAsset = logplan.findAsset(at.getAsset());
620: if (localAsset == null) {
621: logger.error(self + ": Rescinded transferred asset - "
622: + at.getAsset() + " - not found in logplan.");
623: return;
624: }
625:
626: if ((at.getAsset() instanceof HasRelationships)
627: && (at.getAssignee() instanceof HasRelationships)) {
628: rescindSchedule = ldmf.newAssignedRelationshipSchedule();
629: RelationshipSchedule transferSchedule = ((HasRelationships) at
630: .getAsset()).getRelationshipSchedule();
631:
632: for (Iterator iterator = new ArrayList(transferSchedule)
633: .iterator(); iterator.hasNext();) {
634: Relationship relationship = (Relationship) iterator
635: .next();
636: ((NewSchedule) rescindSchedule).add(ldmf
637: .newAssignedRelationshipElement(relationship));
638: }
639:
640: HasRelationships localAssignee = (HasRelationships) logplan
641: .findAsset(at.getAssignee());
642: if (localAssignee == null) {
643: logger
644: .error(self + ": Rescinded assignee - "
645: + at.getAssignee()
646: + " - not found in logplan.");
647: return;
648: }
649:
650: // Update local relationship schedules
651: RelationshipSchedule localSchedule = ((HasRelationships) localAsset)
652: .getRelationshipSchedule();
653: localSchedule.removeAll(transferSchedule);
654:
655: localSchedule = localAssignee.getRelationshipSchedule();
656: localSchedule.removeAll(transferSchedule);
657:
658: // Update asset avail
659: // Remove all current entries denoting asset avail to assignee
660: // Will add in new entry based on the current relationship schedule
661: NewSchedule assetAvailSchedule = (NewSchedule) localAsset
662: .getRoleSchedule().getAvailableSchedule();
663: final Asset assignee = at.getAssignee();
664: synchronized (assetAvailSchedule) {
665: Collection remove = assetAvailSchedule
666: .filter(new UnaryPredicate() {
667: public boolean execute(Object o) {
668: return ((o instanceof AssignedAvailabilityElement) && (((AssignedAvailabilityElement) o)
669: .getAssignee().equals(assignee)));
670: }
671: });
672: assetAvailSchedule.removeAll(remove);
673: } // end sync block
674:
675: // Get all relationships with asset
676: RelationshipSchedule relationshipSchedule = (localAssignee)
677: .getRelationshipSchedule();
678: Collection collection = relationshipSchedule
679: .getMatchingRelationships(
680: (HasRelationships) localAsset,
681: new MutableTimeSpan());
682:
683: // If any relationships, add a single avail element with the
684: // min start and max end
685: if (collection.size() > 0) {
686: Schedule schedule = ldmf.newSchedule(new Enumerator(
687: collection));
688:
689: // Add a new avail element
690: synchronized (assetAvailSchedule) {
691: assetAvailSchedule.add(ldmf
692: .newAssignedAvailabilityElement(
693: (Asset) localAssignee, schedule
694: .getStartTime(), schedule
695: .getEndTime()));
696: }
697: }
698:
699: rootplan.change(localAsset, null);
700: rootplan.change(localAssignee, null);
701: } else {
702: rescindSchedule = at.getSchedule();
703:
704: // Update asset avail - remove all current entries which match the rescind
705: // schedule
706: NewSchedule assetAvailSchedule = (NewSchedule) ((Asset) localAsset)
707: .getRoleSchedule().getAvailableSchedule();
708: final Asset assignee = at.getAssignee();
709: synchronized (assetAvailSchedule) {
710: //final Asset asset = (Asset)localAsset;
711: Collection assignedAvailSchedule = assetAvailSchedule
712: .filter(new UnaryPredicate() {
713: public boolean execute(Object o) {
714: return ((o instanceof AssignedAvailabilityElement) && (((AssignedAvailabilityElement) o)
715: .getAssignee().equals(assignee)));
716: }
717: });
718:
719: //iterate over rescind schedule and remove matching avail elements
720: for (Iterator iterator = rescindSchedule.iterator(); iterator
721: .hasNext();) {
722: ScheduleElement rescind = (ScheduleElement) iterator
723: .next();
724:
725: Iterator localIterator = assignedAvailSchedule
726: .iterator();
727:
728: //boolean found = false;
729: while (localIterator.hasNext()) {
730: ScheduleElement localAvailability = (ScheduleElement) localIterator
731: .next();
732:
733: if ((rescind.getStartTime() == localAvailability
734: .getStartTime())
735: && (rescind.getEndTime() == localAvailability
736: .getEndTime())) {
737: assignedAvailSchedule
738: .remove(localAvailability);
739: break;
740: }
741: }
742: }
743: }
744: rootplan.change(localAsset, null);
745: }
746:
747: AssetRescind arm = ldmf.newAssetRescind(at.getAsset(), at
748: .getAssignee(), rescindSchedule);
749: rootplan.sendDirective((Directive) arm);
750: }
751:
752: /** remove the plan element from the asset's roleschedule **/
753: private void removePERS(PlanElement pe) {
754: /*
755: boolean conflict = false;
756: */
757: Asset rsasset = null;
758: if (pe instanceof Allocation) {
759: Allocation alloc = (Allocation) pe;
760: rsasset = alloc.getAsset();
761: /*
762: if ( alloc.isPotentialConflict() ) {
763: conflict = true;
764: }
765: */
766: } else if (pe instanceof AssetTransfer) {
767: AssetTransfer at = (AssetTransfer) pe;
768: rsasset = at.getAsset();
769: /*
770: if ( at.isPotentialConflict() ) {
771: conflict = true;
772: }
773: */
774: }
775: if (rsasset != null) {
776: if (logger.isDebugEnabled()) {
777: logger.debug(self + " RESCIND REMOVEPERS called for: "
778: + rsasset);
779: }
780: /*
781: RoleScheduleImpl rsi = (RoleScheduleImpl) rsasset.getRoleSchedule();
782: // if the pe had a conflict re-check the roleschedule
783: if (conflict) {
784: checkConflictFlags(pe, rsi);
785: }
786: */
787: } else {
788: if (logger.isWarnEnabled())
789: logger.warn(self
790: + " Could not remove rescinded planelement");
791: }
792: }
793:
794: /*
795: // if the rescinded pe had a potential conflict re-set the conflicting pe(s)
796: private void checkConflictFlags(PlanElement pe, RoleSchedule rs) {
797: // re-set any existing items in the conflict list.
798: conflictlist.clear();
799: AllocationResult estar = pe.getEstimatedResult();
800:
801: // make sure that the start time and end time aspects are defined.
802: // if they aren't, don't check anything
803: // (this could happen with a propagating failed allocation result).
804: if ( (estar.isDefined(AspectType.START_TIME) ) && (estar.isDefined(AspectType.END_TIME) ) ) {
805: Date sdate = new Date( ((long)estar.getValue(AspectType.START_TIME)) );
806: Date edate = new Date( ((long)estar.getValue(AspectType.END_TIME)) );
807:
808: // check for encapsulating schedules of other plan elements.
809: OrderedSet encap = rs.getEncapsulatedRoleSchedule(sdate, edate);
810: Enumeration encapconflicts = encap.elements();
811: while (encapconflicts.hasMoreElements()) {
812: PlanElement conflictpe = (PlanElement) encapconflicts.nextElement();
813: // make sure its not our pe.
814: if ( !(conflictpe == pe) ) {
815: conflictlist.add(conflictpe);
816: }
817: }
818:
819: // check for ovelapping schedules of other plan elements.
820: OrderedSet overlap = rs.getOverlappingRoleSchedule(sdate, edate);
821: Enumeration overlapconflicts = overlap.elements();
822: while (overlapconflicts.hasMoreElements()) {
823: PlanElement overconflictpe = (PlanElement) overlapconflicts.nextElement();
824: // once again, make sure its not our pe.
825: if ( !(overconflictpe == pe) ) {
826: conflictlist.add(overconflictpe);
827: }
828: }
829: }
830:
831: if ( ! conflictlist.isEmpty() ) {
832: ListIterator lit = conflictlist.listIterator();
833: while ( lit.hasNext() ) {
834: RoleScheduleConflicts conpe = (RoleScheduleConflicts) lit.next();
835: // re-set this pe's conflict flag to false
836: conpe.setPotentialConflict(false);
837: // set the check flag to true so that the RoleScheduleConflictLP will
838: // run again on the publish change in case this pe had conflicts with
839: // other pe's (besides the one that was just rescinded)
840: conpe.setCheckConflicts(true);
841: rootplan.change(conpe);
842: }
843: }
844: }
845: */
846:
847: public static class DeferredRescind implements java.io.Serializable {
848: public TaskRescind tr = null;
849: public Task t = null;
850: public int tryCount = 0;
851: public String type = null;
852:
853: public DeferredRescind(TaskRescind tr) {
854: this .tr = tr;
855: }
856:
857: // Used for deferring the rescind of an inconsistent task
858: public DeferredRescind(Task t, String type) {
859: this.t = t;
860: this.type = type;
861: }
862: }
863:
864: }
|