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.logistics.plugin.inventory;
028:
029: import org.cougaar.core.blackboard.IncrementalSubscription;
030: import org.cougaar.core.mts.MessageAddress;
031: import org.cougaar.glm.ldm.asset.Inventory;
032: import org.cougaar.glm.ldm.plan.AlpineAspectType;
033: import org.cougaar.logistics.ldm.Constants;
034: import org.cougaar.planning.ldm.asset.Asset;
035: import org.cougaar.planning.ldm.plan.*;
036: import org.cougaar.planning.plugin.util.AllocationResultHelper;
037: import org.cougaar.planning.plugin.util.PluginHelper;
038:
039: import java.util.*;
040:
041: public class SupplyExpander extends InventoryModule implements
042: ExpanderModule {
043:
044: /**
045: * Define an ARA that can deal with the expansion of a
046: * ProjectSupply task. Mostly, we just clone the result of the
047: * ProjectWithdraw task.
048: **/
049: protected static class ProjectionARA implements
050: AllocationResultAggregator {
051: public AllocationResult calculate(Workflow wf,
052: TaskScoreTable tst, AllocationResult currentar) {
053: if (tst.size() != 1)
054: throw new IllegalArgumentException(
055: "projectionARA: multiple subtasks");
056: AllocationResult ar = (AllocationResult) tst
057: .getAllocationResult(0);
058: if (ar == null)
059: return null;
060: if (ar.isEqual(currentar))
061: return currentar;
062: return (AllocationResult) ar.clone();
063: }
064: }
065:
066: protected static class SupplyARA implements
067: AllocationResultAggregator {
068: public AllocationResult calculate(Workflow wf,
069: TaskScoreTable tst, AllocationResult currentar) {
070: AspectValue[] merged = new AspectValue[AlpineAspectType.LAST_ALPINE_ASPECT + 1];
071: boolean success = true;
072: float rating = 0.0f;
073: int tstSize = tst.size();
074: AllocationResult withdrawAR = null; // Remember this when we see it
075: Task parentTask = wf.getParentTask();
076: AllocationResultHelper helper = new AllocationResultHelper(
077: parentTask, null);
078: AllocationResult bestAR = helper.getAllocationResult();
079: AspectValue[] curr = bestAR.getAspectValueResults();
080:
081: for (int i = 0; i < curr.length; i++) {
082: AspectValue av = curr[i];
083: int type = av.getAspectType();
084: merged[type] = av;
085: }
086: for (int i = 0; i < tstSize; i++) {
087: AllocationResult ar = tst.getAllocationResult(i);
088: if (ar == null)
089: return null; // bail if undefined
090: Task t = tst.getTask(i);
091: Verb verb = t.getVerb();
092: boolean isWithdraw = verb
093: .equals(Constants.Verb.Withdraw)
094: || verb.equals(Constants.Verb.ProjectWithdraw);
095: if (isWithdraw) {
096: if (ar == null)
097: return null;
098: withdrawAR = ar;
099: }
100: AspectValue[] avs = ar.getAspectValueResults();
101: success = success && ar.isSuccess();
102: rating += ar.getConfidenceRating();
103: for (int j = 0; j < avs.length; j++) {
104: int type = avs[j].getAspectType();
105: switch (type) {
106: case AspectType.START_TIME:
107: break;
108: case AspectType.END_TIME:
109: break;
110: case AspectType.QUANTITY:
111: if (isWithdraw)
112: merged[AspectType.QUANTITY] = avs[j];
113: break;
114: default:
115: if (!isWithdraw)
116: merged[type] = avs[j];
117: }
118: }
119: }
120: List mergedPhasedResults = new ArrayList();
121: // this seems strange why do we assume everything is phased?
122: //for now check if this is null (as all the isphased seem to be true
123: // and if it is null get the nonphased results.
124: List withdrawPhasedResults = withdrawAR
125: .getPhasedAspectValueResults();
126: if (withdrawPhasedResults != null) {
127: for (int i = 0, n = withdrawPhasedResults.size(); i < n; i++) {
128: AspectValue[] oneResult = (AspectValue[]) withdrawPhasedResults
129: .get(i);
130: mergedPhasedResults.add(merge(merged, oneResult));
131: }
132: } else {
133: AspectValue[] npresult = (AspectValue[]) withdrawAR
134: .getAspectValueResults();
135: mergedPhasedResults.add(merge(merged, npresult));
136: }
137: return new AllocationResult(rating / tstSize, success,
138: merge(merged, null), mergedPhasedResults);
139: }
140:
141: /**
142: * Merges an array of AspectValue indexed by AspectType and an
143: * unindexed array of AspectValues into an unindexed array of
144: * AspectValues.
145: **/
146: protected AspectValue[] merge(AspectValue[] rollup,
147: AspectValue[] phased) {
148: if (phased != null) {
149: rollup = (AspectValue[]) rollup.clone(); // Don't clobber the original
150: for (int i = 0; i < phased.length; i++) {
151: AspectValue av = phased[i];
152: if (av != null)
153: rollup[av.getAspectType()] = av;
154: }
155: }
156: int nAspects = 0;
157: for (int i = 0; i < rollup.length; i++) {
158: if (rollup[i] != null)
159: nAspects++;
160: }
161: AspectValue[] result = new AspectValue[nAspects];
162: int aspect = 0;
163: for (int i = 0; i < rollup.length; i++) {
164: if (rollup[i] != null)
165: result[aspect++] = rollup[i];
166: }
167: return result;
168: }
169: }
170:
171: protected static final long MSEC_PER_MIN = 60 * 1000;
172: protected static final long MSEC_PER_HOUR = MSEC_PER_MIN * 60;
173: public static final long DEFAULT_ORDER_AND_SHIPTIME = 24 * MSEC_PER_HOUR; // second day
174:
175: public static final Verb WITHDRAWVERB = Constants.Verb.Withdraw;
176: public static final Verb PROJECTWITHDRAWVERB = Constants.Verb.ProjectWithdraw;
177: public static final Verb TRANSPORTVERB = Constants.Verb.Transport;
178:
179: //private Organization myOrg;
180: protected boolean addTransport; // Add load tasks when expanding supply tasks
181: protected long ost;
182: protected static AllocationResultAggregator projectionARA = new ProjectionARA();
183: protected static AllocationResultAggregator supplyARA = new SupplyARA();
184:
185: protected MessageAddress clusterId;
186:
187: public SupplyExpander(InventoryManager imPlugin) {
188: super (imPlugin);
189: ost = DEFAULT_ORDER_AND_SHIPTIME; //In the future plugin should supply from suppliers predictor the OST - MWD
190: addTransport = false;
191: clusterId = imPlugin.getClusterId();
192: }
193:
194: public boolean expandAndDistributeProjections(Collection tasks) {
195: boolean newProjections = false;
196: LogisticsInventoryPG logInvPG;
197: Task aTask, wdrawTask;
198: Iterator taskIter = tasks.iterator();
199: while (taskIter.hasNext()) {
200: aTask = (Task) taskIter.next();
201: wdrawTask = expandDemandTask(aTask,
202: createProjectWithdrawTask(aTask));
203: logInvPG = getLogisticsInventoryPG(wdrawTask);
204: if (logInvPG != null) {
205: logInvPG.addWithdrawProjection(wdrawTask);
206: // if we have atleast one new projection - set this to true.
207: newProjections = true;
208: }
209: ((NewWorkflow) wdrawTask.getWorkflow())
210: .setAllocationResultAggregator(projectionARA);
211: }
212: return newProjections;
213: }
214:
215: public void expandAndDistributeRequisitions(Collection tasks) {
216: LogisticsInventoryPG logInvPG;
217: Task aTask, wdrawTask;
218: Iterator taskIter = tasks.iterator();
219: while (taskIter.hasNext()) {
220: aTask = (Task) taskIter.next();
221: wdrawTask = expandDemandTask(aTask,
222: createWithdrawTask(aTask));
223: logInvPG = getLogisticsInventoryPG(wdrawTask);
224: if (logInvPG != null) {
225: logInvPG.addWithdrawRequisition(wdrawTask);
226: }
227: ((NewWorkflow) wdrawTask.getWorkflow())
228: .setAllocationResultAggregator(supplyARA);
229: }
230: }
231:
232: public void handleRemovedRequisitions(Collection tasks) {
233: Iterator taskIter = tasks.iterator();
234: while (taskIter.hasNext()) {
235: Task aTask = (Task) taskIter.next();
236: if (logger.isDebugEnabled()) {
237: logger.debug("SupplyExp["
238: + inventoryPlugin.getSupplyType() + "]"
239: + "processing removal of requisition: "
240: + aTask.getUID());
241: }
242: LogisticsInventoryPG thePG = getLogisticsInventoryPG(aTask);
243: if (thePG != null) {
244: thePG.removeWithdrawRequisition(aTask);
245: }
246: }
247: }
248:
249: public void handleRemovedDispositions(Collection dispositions) {
250: // This SupplyExpander does nothing for removed dispositions
251: }
252:
253: public boolean handleRemovedProjections(Collection tasks) {
254: boolean removedProjections = false;
255: LogisticsInventoryPG thePG;
256: Task aTask;
257: Iterator taskIter = tasks.iterator();
258: while (taskIter.hasNext()) {
259: aTask = (Task) taskIter.next();
260: if (logger.isDebugEnabled()) {
261: logger.debug("SupplyExpander["
262: + inventoryPlugin.getSupplyType() + "]"
263: + "processing removal of projection: "
264: + aTask.getUID());
265: }
266: thePG = getLogisticsInventoryPG(aTask);
267: if (thePG != null) {
268: thePG.removeWithdrawProjection(aTask);
269: if (!aTask.isDeleted()) {
270: removedProjections = true;
271: }
272: // else {
273: // Inventory inventory = inventoryPlugin.findOrMakeInventory(thePG.getResource());
274: // inventoryPlugin.touchInventoryWithDeletions(inventory);
275: // }
276: }
277: }
278: return removedProjections;
279: }
280:
281: public void updateChangedRequisitions(Collection tasks) {
282: LogisticsInventoryPG thePG;
283: Expansion exp;
284: Task task, supply;
285: Iterator taskIter = tasks.iterator();
286: while (taskIter.hasNext()) {
287: supply = (Task) taskIter.next();
288: if (logger.isDebugEnabled()) {
289: logger.debug("SupplyExp["
290: + inventoryPlugin.getSupplyType() + "]"
291: + "processing changed reqs task: "
292: + supply.getUID());
293: }
294: if (supply.getPlanElement() instanceof Expansion) {
295: exp = (Expansion) supply.getPlanElement();
296: Workflow wf = exp.getWorkflow();
297: Enumeration subTasks = wf.getTasks();
298: while (subTasks.hasMoreElements()) {
299: task = (Task) subTasks.nextElement();
300: thePG = getLogisticsInventoryPG(supply);
301: if (task.getVerb().equals(Constants.Verb.WITHDRAW)) {
302: if ((getTaskUtils().getEndTime(task) < inventoryPlugin
303: .getOPlanArrivalInTheaterTime())
304: && (logger.isErrorEnabled())) {
305: logger
306: .error("At "
307: + inventoryPlugin
308: .getOrgName()
309: + "- Requisition Task:"
310: + task.getUID()
311: + " item: "
312: + getTaskUtils()
313: .getTaskItemName(
314: task)
315: + " has an endTime of "
316: + getTimeUtils()
317: .dateString(
318: getTaskUtils()
319: .getEndTime(
320: task))
321: + " which is before this orgs arrival time of "
322: + getTimeUtils()
323: .dateString(
324: inventoryPlugin
325: .getOPlanArrivalInTheaterTime()));
326: }
327: if (thePG != null) {
328: thePG.updateWithdrawRequisition(task);
329: synchronized (supply) {
330: ((NewTask) task).setPreferences(supply
331: .getPreferences());
332: }
333: inventoryPlugin.publishChange(task);
334: }
335: } else if (task.getVerb().equals(
336: Constants.Verb.TRANSPORT)) {
337: ((NewTask) task).setPrepositionalPhrases(supply
338: .getPrepositionalPhrases());
339: inventoryPlugin.publishChange(task);
340: }
341: }
342: }
343: }
344: }
345:
346: public void updateChangedProjections(Collection tasks) {
347: LogisticsInventoryPG thePG;
348: Expansion exp;
349: Task projSupply, task;
350: Iterator taskIter = tasks.iterator();
351: while (taskIter.hasNext()) {
352: projSupply = (Task) taskIter.next();
353: if (logger.isDebugEnabled()) {
354: logger.debug("SupplyExp["
355: + inventoryPlugin.getSupplyType() + "]"
356: + "processing changed projections task: "
357: + projSupply.getUID());
358: }
359: if (projSupply.getPlanElement() instanceof Expansion) {
360: exp = (Expansion) projSupply.getPlanElement();
361: Workflow wf = exp.getWorkflow();
362: Enumeration subTasks = wf.getTasks();
363: while (subTasks.hasMoreElements()) {
364: task = (Task) subTasks.nextElement();
365: if (task.getVerb().equals(
366: Constants.Verb.PROJECTWITHDRAW)) {
367: thePG = getLogisticsInventoryPG(projSupply);
368: if ((getTaskUtils().getStartTime(projSupply) < inventoryPlugin
369: .getOPlanArrivalInTheaterTime())
370: && (logger.isErrorEnabled())) {
371: logger
372: .error("At "
373: + inventoryPlugin
374: .getOrgName()
375: + "- Projection Task:"
376: + task.getUID()
377: + " item: "
378: + getTaskUtils()
379: .getTaskItemName(
380: projSupply)
381: + " has an start time of "
382: + getTimeUtils()
383: .dateString(
384: getTaskUtils()
385: .getStartTime(
386: projSupply))
387: + " which is before this orgs arrival time of "
388: + getTimeUtils()
389: .dateString(
390: inventoryPlugin
391: .getOPlanArrivalInTheaterTime()));
392: }
393: if (thePG != null) {
394: thePG.removeWithdrawProjection(task);
395: if (task.getPlanElement() != null) {
396: inventoryPlugin.publishRemove(task
397: .getPlanElement());
398: }
399: synchronized (projSupply) {
400: ((NewTask) task)
401: .setPreferences(projSupply
402: .getPreferences());
403: }
404: inventoryPlugin.publishChange(task);
405: //BD Why is this here? We never removed the task from the wf???
406: // commenting this code out
407: //((NewWorkflow)wf).addTask(task);
408: thePG.addWithdrawProjection(task);
409: //inventoryPlugin.publishChange(wf);
410: }
411: } else if (task.getVerb().equals(
412: Constants.Verb.TRANSPORT)) {
413: ((NewTask) task)
414: .setPrepositionalPhrases(projSupply
415: .getPrepositionalPhrases());
416: inventoryPlugin.publishChange(task);
417: }
418: }
419: }
420: }
421: }
422:
423: public LogisticsInventoryPG getLogisticsInventoryPG(Task wdrawTask) {
424: LogisticsInventoryPG logInvPG = null;
425: Asset asset = (Asset) wdrawTask.getDirectObject();
426: Inventory inventory = inventoryPlugin
427: .findOrMakeInventory(asset);
428: inventoryPlugin.touchInventoryForTask(wdrawTask, inventory);
429: logInvPG = (LogisticsInventoryPG) inventory
430: .searchForPropertyGroup(LogisticsInventoryPG.class);
431: return logInvPG;
432: }
433:
434: public void updateExpandedTasks(Collection changedTasks) {
435: Task aTask;
436: Iterator tasksIter = changedTasks.iterator();
437: while (tasksIter.hasNext()) {
438: aTask = (Task) tasksIter.next();
439: }
440: }
441:
442: protected Task expandDemandTask(Task parentTask, Task withdrawTask) {
443: Vector expand_tasks = new Vector();
444: expand_tasks.addElement(withdrawTask);
445: NewTask transportTask = null;
446: if (addTransport) {
447: transportTask = createTransportTask(parentTask,
448: withdrawTask);
449: expand_tasks.addElement(transportTask);
450: }
451: Expansion expansion = PluginHelper.wireExpansion(parentTask,
452: expand_tasks, inventoryPlugin.getPlanningFactory());
453: inventoryPlugin.publishAddExpansion(expansion);
454: NewWorkflow wf = (NewWorkflow) expansion.getWorkflow();
455: wf
456: .setAllocationResultAggregator(new AllocationResultAggregator.DefaultARA());
457: return withdrawTask;
458: }
459:
460: protected NewTask createWithdrawTask(Task parentTask) {
461:
462: NewTask subtask = createVanillaWithdrawTask(parentTask);
463:
464: //This method does the Supply specific stuff
465:
466: long anticipation = 0L;
467: if (addTransport)
468: anticipation += ost;
469:
470: subtask.setVerb(WITHDRAWVERB);
471: //TODO Figure out what to offset the task by for transport
472: //addEndTimePref(subtask, getTaskUtils().getEndTime(parentTask) - anticipation);
473:
474: return subtask;
475: }
476:
477: protected NewTask createProjectWithdrawTask(Task parentTask) {
478:
479: NewTask subtask = createVanillaWithdrawTask(parentTask);
480:
481: //This method does the ProjectSupply specific stuff
482:
483: long anticipation = 0L;
484: if (addTransport)
485: anticipation += ost;
486:
487: subtask.setVerb(PROJECTWITHDRAWVERB);
488: //design issue:
489: //MWD do we build in ost anticipation to end time pref
490: //like above if there is a
491: //PROJECTTRANSPORT in theatre transportation.
492:
493: return subtask;
494: }
495:
496: /** creates a Withdraw task from a Supply task **/
497: protected NewTask createVanillaWithdrawTask(Task parentTask) {
498:
499: // Create new task
500: Asset prototype = parentTask.getDirectObject();
501: NewTask subtask = inventoryPlugin.getPlanningFactory()
502: .newTask();
503: // attach withdraw task to parent and fill it in
504: subtask.setDirectObject(prototype);
505: subtask.setParentTask(parentTask);
506: subtask.setPlan(parentTask.getPlan());
507: subtask.setPrepositionalPhrases(parentTask
508: .getPrepositionalPhrases());
509: subtask.setPriority(parentTask.getPriority());
510: subtask.setSource(clusterId);
511:
512: // Copy all preferences
513: synchronized (parentTask) {
514: subtask.setPreferences(parentTask.getPreferences());
515: }
516: return subtask;
517: }
518:
519: /** creates a Transport or ProjectTransport task from a Supply and Withdraw
520: ** or ProjectSupply and ProjectWithdraw task.
521: ** Must fill in.
522: **/
523: protected NewTask createTransportTask(Task parentTask,
524: Task wdraw_task) {
525: return null;
526: }
527:
528: public void updateAllocationResult(IncrementalSubscription sub) {
529: Iterator subIt = sub.iterator();
530: while (subIt.hasNext()) {
531: PlanElement pe = (PlanElement) subIt.next();
532: if (logger.isDebugEnabled()) {
533: logger.debug("SupplyExp["
534: + inventoryPlugin.getSupplyType() + "]"
535: + "checking AR change: " + pe.getUID()
536: + " parent task is: " + pe.getTask().getUID());
537: }
538: if (PluginHelper.updatePlanElement(pe)) {
539: inventoryPlugin.publishChange(pe);
540: if (logger.isDebugEnabled()) {
541: logger
542: .debug("SupplyExp["
543: + inventoryPlugin.getSupplyType()
544: + "]"
545: + "publish Changing expansion due to AR change: "
546: + pe.getUID() + " parent task is: "
547: + pe.getTask().getUID());
548: }
549: }
550: }
551: }
552:
553: public void checkCommStatusAlarms() {
554: // This SupplyExpander doesn't check for communications loss
555: }
556:
557: public void determineCommStatus(
558: IncrementalSubscription commStatusSub, Collection tasks) {
559: //This SupplyExpander doesn't check for communications loss
560: }
561: }
|