0001: /*
0002: * <copyright>
0003: *
0004: * Copyright 1997-2004 BBNT Solutions, LLC
0005: * under sponsorship of the Defense Advanced Research Projects
0006: * Agency (DARPA).
0007: *
0008: * You can redistribute this software and/or modify it under the
0009: * terms of the Cougaar Open Source License as published on the
0010: * Cougaar Open Source Website (www.cougaar.org).
0011: *
0012: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
0013: * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
0014: * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
0015: * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
0016: * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
0017: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
0018: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
0019: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
0020: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
0021: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
0022: * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
0023: *
0024: * </copyright>
0025: */
0026:
0027: package org.cougaar.logistics.plugin.inventory;
0028:
0029: import org.cougaar.core.agent.service.alarm.Alarm;
0030: import org.cougaar.core.blackboard.IncrementalSubscription;
0031: import org.cougaar.core.service.BlackboardService;
0032: import org.cougaar.logistics.ldm.Constants;
0033: import org.cougaar.logistics.servlet.CommStatus;
0034: import org.cougaar.planning.ldm.plan.*;
0035: import org.cougaar.util.Collectors;
0036: import org.cougaar.util.Filters;
0037: import org.cougaar.util.Thunk;
0038: import org.cougaar.util.UnaryPredicate;
0039:
0040: import java.util.*;
0041:
0042: public class ReconcileSupplyExpander extends SupplyExpander {
0043: private static final long COMMS_UP_DELAY = 120000L; // 2 minutes
0044: private TaskUtils taskUtils = getTaskUtils();
0045: ReconcileSupplyExpanderInventoryManager reconcileInventoryManager;
0046:
0047: public ReconcileSupplyExpander(
0048: InventoryManager imPlugin,
0049: ReconcileSupplyExpanderInventoryManager reconcileInventoryManager) {
0050: super (imPlugin);
0051: this .reconcileInventoryManager = reconcileInventoryManager;
0052: }
0053:
0054: public void expandAndDistributeRequisitions(Collection tasks) {
0055: LogisticsInventoryPG logInvPG;
0056: Task aTask, wdrawTask;
0057: Iterator taskIter = tasks.iterator();
0058: while (taskIter.hasNext()) {
0059: aTask = (Task) taskIter.next();
0060: if (logger.isInfoEnabled() && debugAgent())
0061: logger.info(inventoryPlugin.getSupplyType()
0062: + " - Received task " + aTask.getUID());
0063: if (commStatusExists(getCustomerName(aTask))) { // if any status objects exist
0064: if (customerCommsUp(getCustomerName(aTask))) {
0065: if (logger.isInfoEnabled() && debugAgent())
0066: logger.info(inventoryPlugin.getSupplyType()
0067: + " - Comms up on restore task "
0068: + printTask(aTask));
0069: // CUSTOMER COMM IS UP
0070: if (isPrediction(aTask)) {
0071: // we ignore committed predictions and rescind uncommitted ones
0072: // We may change this because we would have to execute out 25
0073: // days during comm loss in order for the tasks to become committed.
0074: // removeUncommittedPredictions(aTask);
0075: //TODO: do something with these.
0076: continue;
0077: }
0078: } else {
0079: // CUSTOMER COMM IS DOWN
0080: CustomerState cs = (CustomerState) customerStates
0081: .get(getCustomerName(aTask));
0082: if (isPrediction(aTask)) {
0083: if (logger.isDebugEnabled() && debugAgent()) {
0084: logger.info(inventoryPlugin.getSupplyType()
0085: + " -Comm is down "
0086: + printTheGap(aTask) + " task "
0087: + printTask(aTask));
0088: }
0089: if (beforeTheGap(aTask, cs.getLatestEndTime())) {
0090: inventoryPlugin.publishRemove(aTask);
0091: if (logger.isInfoEnabled() && debugAgent()) {
0092: logger
0093: .info(inventoryPlugin
0094: .getSupplyType()
0095: + " -Comm is down, removing prediction: "
0096: + printTheGap(aTask)
0097: + " task "
0098: + printTask(aTask));
0099: }
0100: continue;
0101: }
0102: if (afterTheGap(cs.getLatestEndTime(),
0103: cs.customerLeadTime, aTask)) {
0104: inventoryPlugin.publishRemove(aTask); // don't need to check commitment should be beyond
0105: if (logger.isInfoEnabled() && debugAgent()) {
0106: logger
0107: .info(inventoryPlugin
0108: .getSupplyType()
0109: + " - Comm is down, removing prediction after the gap "
0110: + printTheGap(aTask)
0111: + " task : "
0112: + printTask(aTask));
0113: }
0114: continue;
0115: }
0116:
0117: } else { // ignore demand tasks in or after the gap while we are waiting for the alarm to expire
0118: if (inTheGap(cs.getLatestEndTime(),
0119: cs.customerLeadTime, aTask)
0120: || afterTheGap(cs.getLatestEndTime(),
0121: cs.customerLeadTime, aTask)
0122: || isCommitted(aTask)) {
0123: if (logger.isInfoEnabled() && debugAgent()) {
0124: logger
0125: .info(inventoryPlugin
0126: .getSupplyType()
0127: + " -Comm is down, ignoring demand task committed || in || after the gap "
0128: + printTheGap(aTask)
0129: + " task: "
0130: + printTask(aTask));
0131: }
0132: continue;
0133: }
0134: }
0135: }
0136: }
0137: Date commitDate = aTask.getCommitmentDate();
0138: if (commitDate != null) {
0139: wdrawTask = expandDemandTask(aTask,
0140: createWithdrawTask(aTask));
0141: logInvPG = getLogisticsInventoryPG(wdrawTask);
0142: if (logInvPG != null) {
0143: logInvPG.addWithdrawRequisition(wdrawTask);
0144: }
0145: ((NewWorkflow) wdrawTask.getWorkflow())
0146: .setAllocationResultAggregator(supplyARA);
0147: if (logger.isInfoEnabled() && debugAgent())
0148: logger.info(inventoryPlugin.getSupplyType()
0149: + " - Epanded task :" + printTask(aTask));
0150: } else {
0151: if (isPrediction(aTask)) {
0152: logger.error(" Prediction ");
0153: }
0154: logger.error(" task has null commit date: "
0155: + commitDate);
0156: continue;
0157: }
0158: }
0159: }
0160:
0161: public void handleRemovedDispositions(Collection dispositions) {
0162: Iterator dispIter = dispositions.iterator();
0163: while (dispIter.hasNext()) {
0164: Disposition aDisp = (Disposition) dispIter.next();
0165: Task aTask = aDisp.getTask();
0166: if (aTask != null) {
0167: if (hasAuxQuery(aDisp, aTask)) {
0168: if (logger.isInfoEnabled()) {
0169: logger
0170: .info(" INSIDE remove reqs, task has aux query ");
0171: }
0172: publishRemovePrediction(aDisp, aTask);
0173: }
0174: } else {
0175: if (logger.isInfoEnabled()) {
0176: logger
0177: .info("handleRemovedRealRequisitions... Disposition's task reference is null");
0178: }
0179: }
0180: }
0181: }
0182:
0183: private static boolean isPrediction(Task aTask) {
0184: PrepositionalPhrase for_pp = aTask
0185: .getPrepositionalPhrase(Constants.Preposition.FOR);
0186: String forOrgName = (String) for_pp.getIndirectObject();
0187: String fromOrgName = aTask.getSource().toString();
0188: return !forOrgName.equals(fromOrgName);
0189: }
0190:
0191: private static String forOrg(Task aTask) {
0192: PrepositionalPhrase for_pp = aTask
0193: .getPrepositionalPhrase(Constants.Preposition.FOR);
0194: String forOrgName = (String) for_pp.getIndirectObject();
0195: return forOrgName;
0196: }
0197:
0198: private Map customerStates = new HashMap();
0199:
0200: // This method shuold be called in setup subscriptions to ensure that we have the correct
0201: // state and are rehydration safe
0202: // called when comms are down to set the state and set the customer lead time
0203: // FIXME:
0204: protected void initializeState(Collection demandTasks,
0205: Collection commStatus) {
0206: // updateCommStatus(commStatus);
0207: // for (Iterator iterator = demandTasks.iterator(); iterator.hasNext();) {
0208: // Task task = (Task) iterator.next();
0209:
0210: //}
0211: //if (logger.isWarnEnabled()) {
0212: // logger.warn("SupplyExpander rescinding redundant prediction: " + aTask);
0213: // }
0214: // } else {
0215: }
0216:
0217: public void determineCommStatus(
0218: IncrementalSubscription commStatusSub,
0219: Collection addedSupply) {
0220: Collection addedComms = commStatusSub.getAddedCollection();
0221: Collection changedComms = commStatusSub.getChangedCollection();
0222: // updateCommStatus(commStatusSub.getAddedCollection(), addedSupply);
0223: // updateCommStatus(commStatusSub.getChangedCollection(), addedSupply);
0224: updateCommStatus(addedComms, addedSupply);
0225: updateCommStatus(changedComms, addedSupply);
0226: //if there aren't any comms status subscription changes, but we are waiting on addedSupply
0227: //check things out to see its time to add the alarm
0228: if ((addedComms.isEmpty()) && (changedComms.isEmpty())
0229: && (!commStatusSub.isEmpty())
0230: && (!addedSupply.isEmpty())) {
0231: for (Iterator iter = commStatusSub.iterator(); iter
0232: .hasNext();) {
0233: CommStatus cs = (CommStatus) iter.next();
0234: String customerName = cs.getConnectedAgentName();
0235: CustomerState state = (CustomerState) customerStates
0236: .get(customerName);
0237: if ((state != null)
0238: && (state.getCommsUpAlarm() == null)
0239: && (!state.hasStateExpired())) {
0240: if ((state.isCommsUp()) && (cs.isCommUp())) {
0241: Alarm alarm = reconcileInventoryManager
0242: .addAlarm(inventoryPlugin
0243: .getCurrentTimeMillis()
0244: + COMMS_UP_DELAY);
0245: state.setCommsUpAlarm(alarm);
0246: if (logger.isInfoEnabled()) {
0247: logger
0248: .info("Have new supply tasks... setting ReconcileSupplyExpander alarm");
0249: }
0250: }
0251: }
0252: }
0253: }
0254: }
0255:
0256: public void checkCommStatusAlarms() {
0257: for (Iterator iter = customerStates.entrySet().iterator(); iter
0258: .hasNext();) {
0259: Map.Entry entry = (Map.Entry) iter.next();
0260: CustomerState state = (CustomerState) entry.getValue();
0261: Alarm this Alarm = state.getCommsUpAlarm();
0262: if (this Alarm != null) {
0263: if (this Alarm.hasExpired()) {
0264: if (logger.isInfoEnabled() && debugAgent()) {
0265: logger.info(" The expire time is "
0266: + new Date(this Alarm
0267: .getExpirationTime())
0268: + " the current time is "
0269: + new Date(inventoryPlugin
0270: .getCurrentTimeMillis()));
0271: logger.info("Alarm expired on customer "
0272: + entry.getKey());
0273: }
0274: state.setCommsUpAlarm(null);
0275: state.setStateExpired(true);
0276: reconcile((String) entry.getKey(), state);
0277: }
0278: }
0279: }
0280: }
0281:
0282: private void reconcile(String customerName, CustomerState state) {
0283: UnaryPredicate tasksGapPred = new TasksInTheGap(customerName,
0284: state.getLatestEndTime(), state.getCustomerLeadTime());
0285: UnaryPredicate predictionsGapPred = new PredictionsInTheGap(
0286: customerName, state.getLatestEndTime(), state
0287: .getCustomerLeadTime());
0288: Collection supplyTasks = tasksInTheGap(tasksGapPred);
0289: Collection predictionTasks = tasksInTheGap(predictionsGapPred);
0290: if (predictionTasks.isEmpty()) {
0291: logger
0292: .info(inventoryPlugin.getSupplyType()
0293: + ": There are no predictions in the gap, no need to reconcile."
0294: + " Number of demand tasks: "
0295: + supplyTasks.size());
0296: if (!supplyTasks.isEmpty()) {
0297: for (Iterator iterator = supplyTasks.iterator(); iterator
0298: .hasNext();) {
0299: Task task = (Task) iterator.next();
0300: if (logger.isErrorEnabled()) {
0301: logger
0302: .error(" No predictions in the gap, expanding tasks without reconciliation "
0303: + printTask(task));
0304: }
0305: Task wdrawTask = expandDemandTask(task,
0306: createWithdrawTask(task));
0307: LogisticsInventoryPG logInvPG = getLogisticsInventoryPG(wdrawTask);
0308: if (logInvPG != null) {
0309: logInvPG.addWithdrawRequisition(wdrawTask);
0310: }
0311: ((NewWorkflow) wdrawTask.getWorkflow())
0312: .setAllocationResultAggregator(supplyARA);
0313: if (logger.isInfoEnabled() && debugAgent())
0314: logger
0315: .info(inventoryPlugin.getSupplyType()
0316: + " - Epanded task :"
0317: + printTask(task));
0318: }
0319: }
0320: return; // there is nothing more to do
0321: }
0322: // predicted items dictate what we need to reconcile
0323: List sortedTasks = sortTasksByEndTime(supplyTasks);
0324: Collection uniqueSupplyItems = pruneDuplicateItems(supplyTasks);
0325: List sortedPreds = sortTasksByEndTime(predictionTasks);
0326: Collection uniquePredItems = pruneDuplicateItems(predictionTasks);
0327: for (Iterator iterator = uniquePredItems.iterator(); iterator
0328: .hasNext();) {
0329: String item = (String) iterator.next();
0330: // pass in the complete lists, and then filter as needed for the item
0331: reconcilePredictions(sortedTasks, sortedPreds, item);
0332: if (uniqueSupplyItems.contains(item))
0333: uniqueSupplyItems.remove(item);
0334: }
0335: // if we have missing predicted items, we should go ahead and expand the tasks
0336: // and complain
0337: for (Iterator iterator = uniqueSupplyItems.iterator(); iterator
0338: .hasNext();) {
0339: String item = (String) iterator.next();
0340: UnaryPredicate itemPred = new ItemPredicate(item);
0341: Collection taskItems = filterItems(itemPred, supplyTasks);
0342: for (Iterator iter = taskItems.iterator(); iter.hasNext();) {
0343: Task task = (Task) iter.next();
0344: if (logger.isErrorEnabled()) {
0345: logger
0346: .error(" No predictions in the gap, expanding tasks without reconciliation "
0347: + printTask(task));
0348: }
0349: Task wdrawTask = expandDemandTask(task,
0350: createWithdrawTask(task));
0351: LogisticsInventoryPG logInvPG = getLogisticsInventoryPG(wdrawTask);
0352: if (logInvPG != null) {
0353: logInvPG.addWithdrawRequisition(wdrawTask);
0354: }
0355: ((NewWorkflow) wdrawTask.getWorkflow())
0356: .setAllocationResultAggregator(supplyARA);
0357: if (logger.isInfoEnabled() && debugAgent())
0358: logger.info(inventoryPlugin.getSupplyType()
0359: + " - Epanded task :" + printTask(task));
0360: }
0361: }
0362: }
0363:
0364: private Collection pruneDuplicateItems(Collection preds) {
0365: Set uniqueItems = new HashSet();
0366: for (Iterator iterator = preds.iterator(); iterator.hasNext();) {
0367: Task t = (Task) iterator.next();
0368: uniqueItems.add(t.getDirectObject()
0369: .getTypeIdentificationPG().getTypeIdentification());
0370: }
0371: return uniqueItems;
0372: }
0373:
0374: private void updateCommStatus(Collection commStatus,
0375: Collection addedSupply) {
0376: boolean newSupplyTasks = (!addedSupply.isEmpty());
0377: for (Iterator iter = commStatus.iterator(); iter.hasNext();) {
0378: CommStatus cs = (CommStatus) iter.next();
0379: String customerName = cs.getConnectedAgentName();
0380: CustomerState state = (CustomerState) customerStates
0381: .get(customerName);
0382: if (state == null) {
0383: state = new CustomerState(cs);
0384: customerStates.put(customerName, state);
0385: }
0386: if (state.isCommsUp()) {
0387: if (cs.isCommUp()) {
0388: // state is still up
0389: continue;
0390: }
0391: long latestEndTime = findLastSupplyTaskTime(customerName);
0392: long customerLeadTime = latestEndTime
0393: - cs.getCommLossTime();
0394: state.setCustomerLeadTime(customerLeadTime);
0395: state.setLatestEndTime(latestEndTime);
0396: state.setCommsUp(false);
0397: if (logger.isInfoEnabled() && debugAgent()) {
0398: logger.info("Supply Type is : "
0399: + inventoryPlugin.getSupplyType()
0400: + "\n Setting customer state for "
0401: + customerName + " Comm Loss time : "
0402: + new Date(cs.getCommLossTime())
0403: + "\t latest end time found "
0404: + new Date(latestEndTime)
0405: + "\n customer lead time is "
0406: + customerLeadTime / 86400000);
0407: }
0408: } else { // customer state is down
0409: if (!cs.isCommUp()) {
0410: // state is still down
0411: continue;
0412: }
0413: if (logger.isInfoEnabled() && debugAgent()) {
0414: logger.info("Comms came up for " + customerName);
0415: }
0416: // only set the Alarm if comms are up and we have atleast some new supply tasks
0417: if (newSupplyTasks) {
0418: Alarm alarm = reconcileInventoryManager
0419: .addAlarm(inventoryPlugin
0420: .getCurrentTimeMillis()
0421: + COMMS_UP_DELAY);
0422: state.setCommsUpAlarm(alarm);
0423: if (logger.isInfoEnabled()) {
0424: logger
0425: .info("Have new supply tasks... setting ReconcileSupplyExpander alarm");
0426: }
0427: }
0428: state.setCommsUp(true);
0429: }
0430: }
0431: }
0432:
0433: private long findLastSupplyTaskTime(String customerName) {
0434: MaxEndThunk thunk = new MaxEndThunk(customerName);
0435: Collectors.apply(thunk, reconcileInventoryManager
0436: .getSupplyTasks());
0437: return thunk.getMaxEndTime();
0438: }
0439:
0440: private void reconcilePredictions(Collection demandTasks,
0441: Collection committedPreds, String item) {
0442: UnaryPredicate itemPred = new ItemPredicate(item);
0443: List sortedTasks = filterItems(itemPred, demandTasks);
0444: List sortedPreds = filterItems(itemPred, committedPreds);
0445: // if (logger.isInfoEnabled() && debugAgent() &&
0446: // inventoryPlugin.getSupplyType().equals("Consumable")) {
0447: // for (Iterator iterator = sortedTasks.iterator(); iterator.hasNext();) {
0448: // Task task = (Task) iterator.next();
0449: // logger.info(" printing tasks filtered by items " +printTask(task));
0450: //
0451: // }
0452: // }
0453: if (sortedPreds.isEmpty()) {
0454: if (!sortedTasks.isEmpty()) {
0455: for (Iterator iterator = sortedTasks.iterator(); iterator
0456: .hasNext();) {
0457: Task task = (Task) iterator.next();
0458: if (logger.isErrorEnabled()) {
0459: logger
0460: .error(" Demand task without a matching prediction, will expand"
0461: + printTask(task));
0462: }
0463: Task wdrawTask = expandDemandTask(task,
0464: createWithdrawTask(task));
0465: LogisticsInventoryPG logInvPG = getLogisticsInventoryPG(wdrawTask);
0466: if (logInvPG != null) {
0467: logInvPG.addWithdrawRequisition(wdrawTask);
0468: }
0469: ((NewWorkflow) wdrawTask.getWorkflow())
0470: .setAllocationResultAggregator(supplyARA);
0471: if (logger.isInfoEnabled() && debugAgent())
0472: logger
0473: .info(inventoryPlugin.getSupplyType()
0474: + " - Epanded task :"
0475: + printTask(task));
0476: }
0477: }
0478: return;
0479: }
0480:
0481: if (!sortedPreds.isEmpty()) {
0482: if (logger.isInfoEnabled() && debugAgent()) {
0483: logger
0484: .info(inventoryPlugin.getSupplyType()
0485: + " Item: "
0486: + taskUtils
0487: .getTaskItemName((Task) sortedPreds
0488: .get(0))
0489: + ": Number of tasks in the gap --> Predictions: "
0490: + sortedPreds.size()
0491: + " \t DemandTasks: "
0492: + sortedTasks.size());
0493: }
0494: // if there are no demand tasks, then remove the predictions cause we have nothing to reconcile against.
0495: if (sortedTasks.isEmpty()) {
0496: for (Iterator iterator = sortedPreds.iterator(); iterator
0497: .hasNext();) {
0498: Task predTask = (Task) iterator.next();
0499: if (logger.isInfoEnabled() && debugAgent()) {
0500: logger.info(inventoryPlugin.getSupplyType()
0501: + "Removing prediction for Item: "
0502: + taskUtils.getTaskItemName(predTask)
0503: + " end date "
0504: + taskUtils.getEndTime(predTask));
0505: }
0506: inventoryPlugin.publishRemove(predTask);
0507: }
0508: return;
0509: }
0510:
0511: int i = 0;
0512: int j = 0;
0513: int size = sortedPreds.size();
0514: int lastIndex = sortedTasks.size() - 1;
0515: for (i = 0; i <= lastIndex; i++) {
0516: Task task = (Task) sortedTasks.get(i);
0517: long endTime = taskUtils.getEndTime(task);
0518: double quantity = 0.0;
0519: long maxEndTime = endTime;
0520: List taskPhasedValues = new ArrayList();
0521: // let's try priming the task to except auxiliary queries
0522: setAuxiliaryQueryOnTask(task);
0523: ArrayList pUids = new ArrayList();
0524: while (j < size) {
0525: Task pred = (Task) sortedPreds.get(j);
0526: long predEndTime = taskUtils.getEndTime(pred);
0527: if (predEndTime > endTime && i < lastIndex) {
0528: break;
0529: }
0530: PlanElement pe = pred.getPlanElement();
0531: AllocationResult ar = pe.getEstimatedResult();
0532: if (!ar.isSuccess()) {
0533: // prediction failed no reconcilation needed
0534: if (logger.isInfoEnabled()) {
0535: logger
0536: .info("Found a failed prediction, no reconcilation");
0537: }
0538: j++;
0539: continue;
0540: }
0541: List phasedResults = ar
0542: .getPhasedAspectValueResults();
0543: taskPhasedValues.addAll(phasedResults);
0544: for (Iterator phaseIter = phasedResults.iterator(); phaseIter
0545: .hasNext();) {
0546: AspectValue[] aspectValues = (AspectValue[]) phaseIter
0547: .next();
0548: for (int l = 0; l < aspectValues.length; l++) {
0549: AspectValue aspectValue = aspectValues[l];
0550: switch (aspectValue.getAspectType()) {
0551: case AspectType.QUANTITY:
0552: quantity += aspectValue.getValue();
0553: break;
0554: case AspectType.END_TIME:
0555: maxEndTime = Math.max(maxEndTime,
0556: aspectValue.longValue());
0557: break;
0558: default:
0559: logger.warn("Unexpected aspect type "
0560: + aspectValue.getAspectType());
0561: }
0562: }
0563: }
0564: pUids.add(pred.getUID().toString());
0565: j++;
0566: }
0567:
0568: AspectValue[] rollup = {
0569: AspectValue.newAspectValue(AspectType.END_TIME,
0570: maxEndTime),
0571: AspectValue.newAspectValue(AspectType.QUANTITY,
0572: quantity) };
0573: AllocationResult ar = new AllocationResult(1.0, true,
0574: rollup, taskPhasedValues);
0575: // store the uid of the reconciled predictions on the actual task
0576: // so that we can remove the predictions later if the actual task gets replanned.
0577: for (int p = 0; p < pUids.size(); p++) {
0578: String s = (String) pUids.get(p);
0579: ar.addAuxiliaryQueryInfo(p, s);
0580: if (logger.isInfoEnabled() && debugAgent()) {
0581: logger.info(inventoryPlugin.getSupplyType()
0582: + " add a aux query on the AR " + j
0583: + " pred uid " + s + " task uid is "
0584: + task.getUID());
0585: }
0586: }
0587: if (logger.isInfoEnabled() && debugAgent()) {
0588: logger.info(inventoryPlugin.getSupplyType()
0589: + " - Published new disposition on task "
0590: + task.getUID() + " end Time "
0591: + new Date(endTime) + " new quantity "
0592: + quantity + "\nOriginal data "
0593: + printTask(task) + " for ITEM " + item);
0594:
0595: }
0596: if (task.getPlanElement() != null) {
0597: if (logger.isInfoEnabled() && debugAgent()) {
0598: logger.info(inventoryPlugin.getSupplyType()
0599: + " - demand task has a plan element "
0600: + printTask(task));
0601: inventoryPlugin.publishRemove(task
0602: .getPlanElement());
0603: }
0604: }
0605: Disposition disp = inventoryPlugin.getPlanningFactory()
0606: .createDisposition(task.getPlan(), task, ar);
0607: inventoryPlugin.publishAdd(disp);
0608: }
0609: }
0610: }
0611:
0612: private void setAuxiliaryQueryOnTask(Task t) {
0613: int[] types = new int[AuxiliaryQueryType.AQTYPE_COUNT];
0614: for (int i = 0; i < types.length; i++) {
0615: types[i] = i;
0616: }
0617: ((TaskImpl) t).setAuxiliaryQueryTypes(types);
0618: if (logger.isInfoEnabled()) {
0619: logger.info("Setting AuxQueryTypes: " + types
0620: + " on task: " + t.getUID());
0621: logger
0622: .info("Task says it has the following AuxQueryTypes: "
0623: + t.getAuxiliaryQueryTypes());
0624: }
0625: }
0626:
0627: //MORE EPD AUX QUERY CHANGES
0628: // private boolean hasAuxQuery(Task task) {
0629: // PlanElement pe = task.getPlanElement();
0630: // if (pe == null) {
0631: // return false;
0632: // }
0633: private boolean hasAuxQuery(Disposition pe, Task task) {
0634: AllocationResult ar = pe.getEstimatedResult();
0635: if (ar == null) {
0636: if (logger.isInfoEnabled()) {
0637: logger
0638: .info("In hasAuxQuery: Task's estimated is null");
0639: }
0640: return false;
0641: }
0642: //ar = pe.getEstimatedResult();
0643: int[] theTypes = task.getAuxiliaryQueryTypes();
0644: int checktype = theTypes[0];
0645: //return (checktype > -1);
0646: if (logger.isInfoEnabled()) {
0647: logger.info("In hasAuxQuery: checktype is " + checktype);
0648: }
0649: return (checktype > -1);
0650: }
0651:
0652: private void publishRemovePrediction(Disposition pe, Task task) {
0653: AllocationResult ar = pe.getEstimatedResult();
0654: int[] auxQueryTypes = task.getAuxiliaryQueryTypes();
0655: for (int i = 0; i < auxQueryTypes.length; i++) {
0656: String uid = ar.auxiliaryQuery(auxQueryTypes[i]);
0657: if (logger.isInfoEnabled()) {
0658: logger
0659: .info("AuxQuery from estimated result returned this uid "
0660: + uid);
0661: }
0662: if (uid != null) {
0663: BlackboardService bs = reconcileInventoryManager
0664: .getBBService();
0665: Collection predTasks = bs.query(new TaskUid(uid));
0666: if (!predTasks.isEmpty()) {
0667: inventoryPlugin.publishRemove(predTasks.iterator()
0668: .next());
0669: if (logger.isInfoEnabled()) {
0670: logger
0671: .info(inventoryPlugin.getSupplyType()
0672: + " Reconciled task was removed... Removing matching prediction "
0673: + uid);
0674: }
0675: } else if (logger.isInfoEnabled()) {
0676: logger
0677: .info("Query for matching prediction returned an empty set for uid: "
0678: + uid);
0679: }
0680: }
0681: }
0682: }
0683:
0684: private String printTask(Task t) {
0685: String info = "Item " + taskUtils.getTaskItemName(t)
0686: + " Task UID: " + t.getUID() + " for " + forOrg(t)
0687: + " Commitment Date: " + t.getCommitmentDate()
0688: + " End time " + new Date(taskUtils.getEndTime(t))
0689: + " quantity : " + taskUtils.getQuantity(t)
0690: + " is prediction --> " + isPrediction(t);
0691: return info;
0692: }
0693:
0694: private boolean beforeTheGap(Task task, long lastEndTime) {
0695: long endTime = taskUtils.getEndTime(task);
0696: boolean retVal = false;
0697: retVal = endTime < lastEndTime;
0698: if (retVal == true && logger.isInfoEnabled() && debugAgent()) {
0699: if (isPrediction(task))
0700: logger.error(" Prediction ");
0701: logger.error(inventoryPlugin.getSupplyType()
0702: + " - task has end date before the GAP: "
0703: + new Date(endTime));
0704: }
0705: return retVal;
0706: }
0707:
0708: private boolean inTheGap(long leftEdge, long leadTime, Task task) {
0709: boolean retVal = false;
0710: long rightEdge = inventoryPlugin.getCurrentTimeMillis()
0711: + leadTime;
0712: // current time + clt - lastest end time
0713: long gap = rightEdge - leftEdge;
0714: rightEdge = leftEdge + gap * 4;
0715: long endTime = taskUtils.getEndTime(task);
0716: retVal = endTime > leftEdge && endTime < rightEdge;
0717: if (retVal == true && logger.isInfoEnabled() && debugAgent()) {
0718: if (isPrediction(task))
0719: logger.info(" Prediction ");
0720: logger.info(inventoryPlugin.getSupplyType()
0721: + " - task in the GAP: end time is "
0722: + new Date(endTime) + printTheGap(task));
0723: }
0724: return retVal;
0725: }
0726:
0727: private boolean inTheOutage(long leftEdge, long rightEdge, Task task) {
0728: long commitTime = task.getCommitmentDate().getTime();
0729: if (logger.isInfoEnabled() && debugAgent()) {
0730: if (isPrediction(task))
0731: logger.info("Prediction ");
0732: logger.info(" task commitment date is: "
0733: + task.getCommitmentDate() + " in the outage? "
0734: + new Date(leftEdge) + " - " + new Date(rightEdge));
0735: }
0736: return (commitTime > leftEdge && commitTime < rightEdge);
0737: }
0738:
0739: private boolean afterTheGap(long leftEdge, long leadTime, Task task) {
0740: long rightEdge = inventoryPlugin.getCurrentTimeMillis()
0741: + leadTime;
0742: long endTime = taskUtils.getEndTime(task);
0743: boolean retVal = false;
0744: // current time + clt - lastest end time
0745: long gap = rightEdge - leftEdge;
0746: rightEdge = leftEdge + gap * 4;
0747: retVal = endTime > rightEdge;
0748: if (retVal == true && logger.isInfoEnabled() && debugAgent()) {
0749: if (isPrediction(task))
0750: logger.error(" Prediction ");
0751: logger.error(inventoryPlugin.getSupplyType()
0752: + " - task after the GAP, end time is: "
0753: + new Date(endTime));
0754: }
0755: return retVal;
0756: }
0757:
0758: private boolean commStatusExists(String name) {
0759: if (reconcileInventoryManager.getCommStatusSubscription()
0760: .isEmpty())
0761: return false;
0762: CustomerState state;
0763: state = (CustomerState) customerStates.get(name);
0764: if (state != null) {
0765: return true;
0766: }
0767: return false;
0768: }
0769:
0770: private boolean customerCommsUp(String customerName) {
0771: CustomerState state = (CustomerState) customerStates
0772: .get(customerName);
0773: return state.isCommsUp();
0774: }
0775:
0776: private String printTheGap(Task t) {
0777: String theTask = new Date(taskUtils.getEndTime(t))
0778: + "\n gap is --> ";
0779: CustomerState state = (CustomerState) customerStates
0780: .get(getCustomerName(t));
0781: long leftSide = state.getLatestEndTime();
0782: long rightSide = inventoryPlugin.getCurrentTimeMillis()
0783: + state.customerLeadTime;
0784: long gap = rightSide - leftSide;
0785: rightSide = leftSide + gap * 4;
0786: String theGap = new Date(leftSide).toString() + " -- "
0787: + new Date(rightSide).toString() + " gap interval is "
0788: + (int) (gap / 86400000);
0789: return theTask + theGap;
0790: }
0791:
0792: // Review:Is it possible that there is no supply task after the comms go down???
0793:
0794: // An instance of a Supply Expander handles one supply type, but it may have multiple customers
0795: // with differing policies therefore, customer lead time may differ.
0796: private static class CustomerState {
0797: private long customerLeadTime = 0;
0798: // previous state of comms
0799: private boolean commsUp = true;
0800: private Alarm alarm;
0801: private long latestEndTime = 0;
0802: private CommStatus cs = null;
0803: private boolean expired = false;
0804:
0805: public CustomerState(CommStatus cs) {
0806: this .cs = cs;
0807: }
0808:
0809: public void setCommsUp(boolean state) {
0810: commsUp = state;
0811: }
0812:
0813: public boolean isCommsUp() {
0814: return commsUp && alarm == null;
0815: }
0816:
0817: public void setCustomerLeadTime(long newLeadTime) {
0818: customerLeadTime = newLeadTime;
0819: }
0820:
0821: public long getCustomerLeadTime() {
0822: return customerLeadTime;
0823: }
0824:
0825: public void setCommsUpAlarm(Alarm alarm) {
0826: this .alarm = alarm;
0827: }
0828:
0829: public Alarm getCommsUpAlarm() {
0830: return this .alarm;
0831: }
0832:
0833: public void setLatestEndTime(long endTime) {
0834: latestEndTime = endTime;
0835: }
0836:
0837: public long getLatestEndTime() {
0838: return latestEndTime;
0839: }
0840:
0841: public long getCommLossTime() {
0842: return this .cs.getCommLossTime();
0843: }
0844:
0845: public long getCommRestoreTime() {
0846: return this .cs.getCommRestoreTime();
0847: }
0848:
0849: public void setStateExpired(boolean value) {
0850: this .expired = value;
0851: }
0852:
0853: public boolean hasStateExpired() {
0854: return expired;
0855: }
0856: }
0857:
0858: private class MaxEndThunk implements Thunk {
0859: long maxEnd = Long.MIN_VALUE;
0860: String customerName;
0861: Task lastTask;
0862:
0863: public MaxEndThunk(String customerName) {
0864: this .customerName = customerName;
0865: }
0866:
0867: public void apply(Object o) {
0868: if (o instanceof Task) {
0869: Task task = (Task) o;
0870: if (isPrediction(task)
0871: || !getCustomerName(task).equals(
0872: this .customerName)) {
0873: return;
0874: }
0875: long endTime = taskUtils.getEndTime(task);
0876: if (endTime > maxEnd) {
0877: maxEnd = endTime;
0878: lastTask = task;
0879: }
0880: }
0881: }
0882:
0883: public long getMaxEndTime() {
0884: if (logger.isInfoEnabled() && debugAgent())
0885: logger.info(" ReconcileExpander "
0886: + inventoryPlugin.getSupplyType()
0887: + " Last task found " + lastTask);
0888: return maxEnd;
0889: }
0890: }
0891:
0892: private class TasksInTheOutage implements UnaryPredicate {
0893: String customerName;
0894: long commLossTime;
0895: long commRestoreTime;
0896:
0897: public TasksInTheOutage(String customerName, long lossTime,
0898: long restoreTime) {
0899: this .customerName = customerName;
0900: commLossTime = lossTime;
0901: commRestoreTime = restoreTime;
0902: }
0903:
0904: public boolean execute(Object o) {
0905: if (o instanceof Task) {
0906: Task task = (Task) o;
0907: if (task.getVerb().equals(Constants.Verb.SUPPLY)) {
0908: return (getCustomerName(task).equals(customerName)
0909: && !isPrediction(task) && isCommitted(task) && inTheOutage(
0910: commLossTime, commRestoreTime, task));
0911: }
0912: }
0913: return false;
0914: }
0915: }
0916:
0917: private class TasksInTheGap implements UnaryPredicate {
0918: String customerName;
0919: long lastDemandTime;
0920: long leadTime;
0921:
0922: public TasksInTheGap(String customerName, long lastDemandTime,
0923: long leadTime) {
0924: this .customerName = customerName;
0925: this .lastDemandTime = lastDemandTime;
0926: this .leadTime = leadTime;
0927: }
0928:
0929: public boolean execute(Object o) {
0930: if (o instanceof Task) {
0931: Task task = (Task) o;
0932: if (task.getVerb().equals(Constants.Verb.SUPPLY)) {
0933: return (getCustomerName(task).equals(customerName)
0934: && !isPrediction(task) && inTheGap(
0935: lastDemandTime, leadTime, task));
0936: }
0937: }
0938: return false;
0939: }
0940: }
0941:
0942: private boolean isCommitted(Task t) {
0943: return !t.beforeCommitment(new Date(inventoryPlugin
0944: .getCurrentTimeMillis()));
0945: }
0946:
0947: private String getCustomerName(Task t) {
0948: return taskUtils.getCustomer(t).toString();
0949: }
0950:
0951: public Collection filter(UnaryPredicate predicate) {
0952: return Filters.filter(reconcileInventoryManager
0953: .getSupplyTasks(), predicate);
0954: }
0955:
0956: public Collection customerSupplyTasks(
0957: UnaryPredicate customerTaskPredicate) {
0958: return filter(customerTaskPredicate);
0959: }
0960:
0961: public Collection tasksInTheOutage(UnaryPredicate outagePredicate) {
0962: return filter(outagePredicate);
0963: }
0964:
0965: public Collection tasksInTheGap(UnaryPredicate gapPredicate) {
0966: return filter(gapPredicate);
0967: }
0968:
0969: public List filterItems(UnaryPredicate itemPred, Collection tasks) {
0970: return new ArrayList(Filters.filter(tasks, itemPred));
0971: }
0972:
0973: private class PredictionsInTheOutage implements UnaryPredicate {
0974: String customerName;
0975: long commLossTime;
0976: long commRestoreTime;
0977:
0978: public PredictionsInTheOutage(String customerName,
0979: long lossTime, long restoreTime) {
0980: this .customerName = customerName;
0981: commLossTime = lossTime;
0982: commRestoreTime = restoreTime;
0983: }
0984:
0985: public boolean execute(Object o) {
0986: if (o instanceof Task) {
0987: Task task = (Task) o;
0988: return (getCustomerName(task).equals(customerName)
0989: && isPrediction(task) && isCommitted(task) && inTheGap(
0990: commLossTime, commRestoreTime, task));
0991: }
0992: return false;
0993: }
0994: }
0995:
0996: private class TaskUid implements UnaryPredicate {
0997: String uid;
0998:
0999: public TaskUid(String uid) {
1000: this .uid = uid;
1001: }
1002:
1003: public boolean execute(Object o) {
1004: if (o instanceof Task) {
1005: Task t = (Task) o;
1006: return (t.getUID().toString().equals(uid));
1007: }
1008: return false;
1009: }
1010: }
1011:
1012: private class CustomerSupplyTask implements UnaryPredicate {
1013: String customerName;
1014:
1015: public CustomerSupplyTask(String customerName) {
1016: this .customerName = customerName;
1017: }
1018:
1019: public boolean execute(Object o) {
1020: if (o instanceof Task) {
1021: Task task = (Task) o;
1022: PrepositionalPhrase pp = task
1023: .getPrepositionalPhrase(Constants.Preposition.FOR);
1024: if (pp == null) {
1025: return false;
1026: }
1027: Object io = pp.getIndirectObject();
1028: if (io instanceof String) {
1029: String orgName = (String) io;
1030: if (orgName.equals(customerName)) {
1031: return true;
1032: }
1033: }
1034: }
1035: return false;
1036: }
1037: }
1038:
1039: private class ItemPredicate implements UnaryPredicate {
1040: String item;
1041:
1042: public ItemPredicate(String item) {
1043: this .item = item;
1044: }
1045:
1046: public boolean execute(Object o) {
1047: if (o instanceof Task) {
1048: Task task = (Task) o;
1049: String this Item = task.getDirectObject()
1050: .getTypeIdentificationPG()
1051: .getTypeIdentification();
1052: return this Item.equals(item);
1053: }
1054: return false;
1055: }
1056: }
1057:
1058: private class PredictionsInTheGap implements UnaryPredicate {
1059: String customerName;
1060: long lastDemandTime;
1061: long leadTime;
1062:
1063: public PredictionsInTheGap(String customerName,
1064: long lastDemandTime, long leadTime) {
1065: this .customerName = customerName;
1066: this .lastDemandTime = lastDemandTime;
1067: this .leadTime = leadTime;
1068: }
1069:
1070: public boolean execute(Object o) {
1071: if (o instanceof Task) {
1072: Task task = (Task) o;
1073: return (getCustomerName(task).equals(customerName)
1074: && isPrediction(task) && inTheGap(
1075: lastDemandTime, leadTime, task));
1076: }
1077: return false;
1078: }
1079: }
1080:
1081: private boolean debugAgent() {
1082: String myOrgName = inventoryPlugin.getOrgName();
1083: return (myOrgName.indexOf("123-MSB") >= 0);
1084: }
1085:
1086: private List sortTasksByEndTime(Collection tasks) {
1087: List result;
1088: if (tasks instanceof List) {
1089: result = (List) tasks;
1090: } else {
1091: result = new ArrayList(tasks);
1092: }
1093: Collections.sort(result, new Comparator() {
1094: public int compare(Object a, Object b) {
1095: Task task1 = (Task) a;
1096: Task task2 = (Task) b;
1097: long end1 = taskUtils.getEndTime(task1);
1098: long end2 = taskUtils.getEndTime(task2);
1099: if (end1 < end2)
1100: return -1;
1101: if (end1 > end2)
1102: return +1;
1103: return 0;
1104: }
1105: });
1106: return result;
1107: }
1108: }
|