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: import java.util.List;
034: import java.util.ListIterator;
035:
036: import org.cougaar.core.blackboard.EnvelopeTuple;
037: import org.cougaar.core.domain.EnvelopeLogicProvider;
038: import org.cougaar.core.domain.LogicProvider;
039: import org.cougaar.core.domain.RootPlan;
040: import org.cougaar.planning.ldm.asset.Asset;
041: import org.cougaar.planning.ldm.plan.Allocation;
042: import org.cougaar.planning.ldm.plan.AllocationResult;
043: import org.cougaar.planning.ldm.plan.AspectType;
044: import org.cougaar.planning.ldm.plan.AssetTransfer;
045: import org.cougaar.planning.ldm.plan.PlanElement;
046: import org.cougaar.planning.ldm.plan.RoleSchedule;
047: import org.cougaar.planning.ldm.plan.RoleScheduleConflicts;
048: import org.cougaar.planning.ldm.plan.ScheduleElement;
049:
050: /** RoleScheduleConflictLP checks an Asset's roleschedule for potential
051: * schedule conflicts. Each time a new allocation or assettransfer is published or
052: * a change is published for an allocation or assettransfer, the allocation's/assettransfer's estimated
053: * allocation result schedule will be checked against the rest of the
054: * roleschedule. If there is a conflict, the conflicting
055: * allocation's/assettransfer's potentialconflict flags will be set.
056: * The schedule will also be checked for dates outside
057: * of the available schedule. If an available conflict occurs, the allocation's/assettransfer's
058: * assetavailabilityconflict flag will be set.
059: **/
060:
061: public class RoleScheduleConflictLP implements LogicProvider,
062: EnvelopeLogicProvider {
063:
064: private final RootPlan rootplan;
065:
066: public RoleScheduleConflictLP(RootPlan rootplan) {
067: this .rootplan = rootplan;
068: }
069:
070: public void init() {
071: }
072:
073: public void execute(EnvelopeTuple o, Collection changes) {
074: Object obj = o.getObject();
075: // We don't need to test on Envelope Contents/Action again...
076:
077: if (!((obj instanceof Allocation) || (obj instanceof AssetTransfer)))
078: return;
079:
080: if (!(o.isAdd() || (o.isChange() && ((RoleScheduleConflicts) obj)
081: .checkConflicts())))
082: return;
083:
084: PlanElement pe = (PlanElement) obj;
085: // re-set the checkconflict flag
086: ((RoleScheduleConflicts) pe).setCheckConflicts(false);
087:
088: Asset theasset = null;
089: boolean currentpc = false;
090: boolean currentaac = false;
091: if (pe instanceof Allocation) {
092: Allocation alloc = (Allocation) pe;
093: theasset = alloc.getAsset();
094: currentpc = alloc.isPotentialConflict();
095: currentaac = alloc.isAssetAvailabilityConflict();
096: } else if (pe instanceof AssetTransfer) {
097: AssetTransfer at = (AssetTransfer) pe;
098: theasset = at.getAsset();
099: currentpc = at.isPotentialConflict();
100: currentaac = at.isAssetAvailabilityConflict();
101: }
102: RoleSchedule rs = theasset.getRoleSchedule();
103:
104: boolean withinAvailSched = checkAvailableSchedule(pe, rs);
105: List conflicts = checkRoleSchedule(pe, rs);
106:
107: if (!conflicts.isEmpty()) {
108: for (ListIterator lit = conflicts.listIterator(); lit
109: .hasNext();) {
110: PlanElement tomark = (PlanElement) lit.next();
111: // make sure this pe's potentialconflict flag isn't already true before marking it
112: boolean othercurrentpc = false;
113: if (tomark instanceof Allocation) {
114: othercurrentpc = ((Allocation) tomark)
115: .isPotentialConflict();
116: } else if (tomark instanceof AssetTransfer) {
117: othercurrentpc = ((AssetTransfer) tomark)
118: .isPotentialConflict();
119: }
120: if (!othercurrentpc) {
121: ((RoleScheduleConflicts) tomark)
122: .setPotentialConflict(true);
123: rootplan.change(tomark, changes);
124: }
125: }
126: // now mark ourselves if our potentialconflict flag isn't already true
127: if (!currentpc) {
128: ((RoleScheduleConflicts) pe).setPotentialConflict(true);
129: rootplan.change(pe, changes);
130: }
131: } else {
132: // If there are no conflicts, check to see if our conflict flag was
133: // previously set to true. If it was, re-set it to false.
134: if (currentpc) {
135: ((RoleScheduleConflicts) pe)
136: .setPotentialConflict(false);
137: rootplan.change(pe, changes);
138: }
139: }
140:
141: // if its not within the available schedule and the asset availability conflict
142: // flag isn't already true, set it!
143: if ((!withinAvailSched) && (!currentaac)) {
144: // if there was a conflict here set our asset availability conflict flag
145: ((RoleScheduleConflicts) pe)
146: .setAssetAvailabilityConflict(true);
147: rootplan.change(pe, changes);
148: } else {
149: // if there was no conflict, check to see if our conflict flag was
150: // previously set to true. If it was, re-set if to false.
151: if (currentaac) {
152: ((RoleScheduleConflicts) pe)
153: .setAssetAvailabilityConflict(false);
154: rootplan.change(pe, changes);
155: }
156: }
157: }
158:
159: private boolean checkAvailableSchedule(PlanElement thepe,
160: RoleSchedule thers) {
161: // if the available schedule is null, return true
162: if (thers.getAvailableSchedule() == null) {
163: return true;
164: }
165: AllocationResult estar = thepe.getEstimatedResult();
166: // make sure that the start time and end time aspects are defined.
167: // if they aren't return true
168: //(this could happen with a propagating failed allocation result).
169: if ((estar == null)
170: || (!(estar.isDefined(AspectType.START_TIME)))
171: || (!(estar.isDefined(AspectType.END_TIME)))) {
172: return true;
173: }
174: double sdate = estar.getValue(AspectType.START_TIME);
175: double edate = estar.getValue(AspectType.END_TIME);
176: // get the available schedule, remember there may be more than one available time segment.
177: Enumeration availsched = thers.getAvailableSchedule()
178: .getAllScheduleElements();
179: while (availsched.hasMoreElements()) {
180: ScheduleElement se = (ScheduleElement) availsched
181: .nextElement();
182: long availsdate = se.getStartDate().getTime();
183: long availedate = se.getEndDate().getTime();
184: if ((sdate >= availsdate) && (edate <= availedate)) {
185: // if the dates fall into atleast one of the time segments return true.
186: return true;
187: }
188: }
189: // if we are here it didn't fall into any available schedule
190: return false;
191: }
192:
193: private List checkRoleSchedule(PlanElement thepe, RoleSchedule thers) {
194: List conflictlist = new ArrayList();
195: AllocationResult estar = thepe.getEstimatedResult();
196:
197: // make sure that the start time and end time aspects are defined.
198: // if they aren't return the empty conflictlist
199: // (this could happen with a propagating failed allocation result).
200: if ((estar != null) && (estar.isDefined(AspectType.START_TIME))
201: && (estar.isDefined(AspectType.END_TIME))) {
202:
203: long stime = ((long) estar.getValue(AspectType.START_TIME));
204: long etime = ((long) estar.getValue(AspectType.END_TIME));
205:
206: // check for encapsulating schedules of other plan elements.
207: Collection encap = thers.getEncapsulatedRoleSchedule(stime,
208: etime);
209: for (Iterator ec = encap.iterator(); ec.hasNext();) {
210: PlanElement conflictpe = (PlanElement) ec.next();
211: // make sure its not our pe.
212: if (!(conflictpe == thepe)) {
213: conflictlist.add(conflictpe);
214: }
215: }
216:
217: // check for ovelapping schedules of other plan elements.
218: Collection overlap = thers.getOverlappingRoleSchedule(
219: stime, etime);
220: for (Iterator oc = overlap.iterator(); oc.hasNext();) {
221: PlanElement overconflictpe = (PlanElement) oc.next();
222: // once again, make sure its not our pe.
223: if (!(overconflictpe == thepe)) {
224: conflictlist.add(overconflictpe);
225: }
226: }
227: }
228:
229: return conflictlist;
230: }
231: }
|