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.mlm.plugin.assessor;
028:
029: import java.util.ArrayList;
030: import java.util.Collection;
031: import java.util.Date;
032: import java.util.Enumeration;
033: import java.util.HashMap;
034: import java.util.Iterator;
035: import java.util.List;
036: import java.util.Vector;
037:
038: import org.cougaar.core.blackboard.IncrementalSubscription;
039: import org.cougaar.core.plugin.ComponentPlugin;
040: import org.cougaar.glm.ldm.Constants;
041: import org.cougaar.glm.ldm.asset.Organization;
042: import org.cougaar.glm.ldm.plan.AlpineAspectType;
043: import org.cougaar.glm.plugins.MaintainedItem;
044: import org.cougaar.planning.ldm.PlanningFactory;
045: import org.cougaar.planning.ldm.asset.Asset;
046: import org.cougaar.planning.ldm.plan.Allocation;
047: import org.cougaar.planning.ldm.plan.AllocationResult;
048: import org.cougaar.planning.ldm.plan.AllocationResultAggregator;
049: import org.cougaar.planning.ldm.plan.AspectType;
050: import org.cougaar.planning.ldm.plan.AspectValue;
051: import org.cougaar.planning.ldm.plan.Expansion;
052: import org.cougaar.planning.ldm.plan.NewPrepositionalPhrase;
053: import org.cougaar.planning.ldm.plan.NewTask;
054: import org.cougaar.planning.ldm.plan.NewWorkflow;
055: import org.cougaar.planning.ldm.plan.PlanElement;
056: import org.cougaar.planning.ldm.plan.Relationship;
057: import org.cougaar.planning.ldm.plan.RelationshipSchedule;
058: import org.cougaar.planning.ldm.plan.Task;
059: import org.cougaar.planning.ldm.plan.TaskScoreTable;
060: import org.cougaar.planning.ldm.plan.Workflow;
061: import org.cougaar.planning.plugin.util.PluginHelper;
062: import org.cougaar.planning.service.LDMService;
063: import org.cougaar.util.TimeSpan;
064: import org.cougaar.util.UnaryPredicate;
065:
066: public class ReadinessAssessorPlugin extends ComponentPlugin {
067:
068: protected long rollupSpan = 10;
069: protected StringBuffer debugStart = new StringBuffer();
070: private PhasedAggregated allocationAggregator = new PhasedAggregated();
071:
072: private IncrementalSubscription readinessTaskSub;
073: private final UnaryPredicate readinessTaskPred = new UnaryPredicate() {
074: public boolean execute(Object o) {
075: if (o instanceof Task) {
076: Task t = (Task) o;
077: if (t.getVerb().equals(Constants.Verb.AssessReadiness)) {
078: if (!t.getPrepositionalPhrases().hasMoreElements()) {
079: if (t.getPlanElement() == null) {
080: return true;
081: }
082: }
083: }
084: }
085: return false;
086: }
087: };
088:
089: private IncrementalSubscription projectSupplyTaskSub;
090: private final UnaryPredicate projectSupplyTaskPred = new UnaryPredicate() {
091: public boolean execute(Object o) {
092: if (o instanceof Task) {
093: Task t = (Task) o;
094: if (t.getVerb().equals(Constants.Verb.PROJECTSUPPLY)) {
095: if (t
096: .getPrepositionalPhrase(Constants.Preposition.REFILL) == null) {
097: return true;
098: }
099: }
100: }
101: return false;
102: }
103: };
104:
105: private IncrementalSubscription selfOrgSub;
106: private final UnaryPredicate selfOrgPred = new UnaryPredicate() {
107: public boolean execute(Object o) {
108: if (o instanceof Organization) {
109: return ((Organization) o).isSelf();
110: }
111: return false;
112: }
113: };
114:
115: private IncrementalSubscription readinessPESub;
116: // this finds all expanded plan elements. we really only want the ones
117: // whose task's parent is in the readinessTaskSub
118: private final UnaryPredicate readinessPEPred = new UnaryPredicate() {
119: public boolean execute(Object o) {
120: if (o instanceof Allocation) {
121: Allocation pe = (Allocation) o;
122: Task t = pe.getTask();
123: if (t.getVerb().equals(Constants.Verb.AssessReadiness)) {
124: if (!t.getPrepositionalPhrases().hasMoreElements()) {
125: return true;
126: }
127: }
128: }
129: return false;
130: }
131: };
132:
133: protected PlanningFactory rootFactory;
134:
135: // called by introspection
136: public void setLDMService(LDMService service) {
137: rootFactory = service.getFactory();
138: }
139:
140: protected void setupSubscriptions() {
141: projectSupplyTaskSub = (IncrementalSubscription) blackboard
142: .subscribe(projectSupplyTaskPred);
143: readinessTaskSub = (IncrementalSubscription) blackboard
144: .subscribe(readinessTaskPred);
145: selfOrgSub = (IncrementalSubscription) blackboard
146: .subscribe(selfOrgPred);
147: readinessPESub = (IncrementalSubscription) blackboard
148: .subscribe(readinessPEPred);
149:
150: debugStart.append(getAgentIdentifier());
151: debugStart.append(" ReadinessAssessor");
152: }
153:
154: protected void execute() {
155:
156: if (readinessTaskSub.hasChanged()) {
157: // only do one per cycle
158: Collection added = readinessTaskSub.getAddedCollection();
159: if (added.size() > 0) {
160: Task readinessTask = (Task) added.iterator().next();
161: if (readinessTask != null) {
162: processReadinessTask(readinessTask);
163: }
164: }
165: }
166:
167: if (readinessPESub.hasChanged()) {
168:
169: for (Iterator peIt = readinessPESub.getChangedCollection()
170: .iterator(); peIt.hasNext();) {
171: PlanElement pe = (PlanElement) peIt.next();
172: if (PluginHelper.updatePlanElement(pe)) {
173: blackboard.publishChange(pe);
174: }
175: }
176: }
177: }
178:
179: private void processReadinessTask(Task readinessTask) {
180:
181: // hack!
182: long earliest = Long.MAX_VALUE;
183: long latest = Long.MIN_VALUE;
184:
185: earliest = Math.round(readinessTask
186: .getPreferredValue(AspectType.START_TIME));
187: latest = Math.round(readinessTask
188: .getPreferredValue(AspectType.END_TIME));
189: rollupSpan = Math.round(readinessTask
190: .getPreferredValue(AspectType.INTERVAL));
191: // System.out.println(debugStart +" got earliest date: "
192: // +new Date(earliest).toString() +
193: // " and rollupSpan: " + rollupSpan);
194:
195: expandAndAllocateToSubordinates(readinessTask);
196: HashMap pacingItems = new HashMap(13);
197:
198: // Sort project supply tasks by Maintained Item and OfType
199: System.out.println(debugStart + " sorting "
200: + projectSupplyTaskSub.size() + " ProjectSupply tasks");
201: for (Iterator psIterator = projectSupplyTaskSub.iterator(); psIterator
202: .hasNext();) {
203: Task psTask = (Task) psIterator.next();
204:
205: // find the supply type of the task
206: Object directObject = psTask.getDirectObject();
207:
208: // find the latest end times
209: // long end = Math.round(psTask.getPreferredValue(AspectType.END_TIME));
210: // if (end > latest)
211: // latest = end;
212:
213: // Do we really want to bail here, or should we count this task against our readiness?
214: if (psTask.getPlanElement() == null)
215: continue;
216:
217: // find the asset (pacing item) this task is for
218: MaintainedItem pacing = ((MaintainedItem) psTask
219: .getPrepositionalPhrase(
220: Constants.Preposition.MAINTAINING)
221: .getIndirectObject());
222:
223: // find the buckets for that asset
224: HashMap itemBuckets = (HashMap) pacingItems.get(pacing);
225: if (itemBuckets == null) {
226: //System.out.println(debugStart + ": adding new set of buckets for " + pacing.getTypeIdentification());
227: itemBuckets = new HashMap(13);
228: pacingItems.put(pacing, itemBuckets);
229: }
230:
231: // find the bucket for that supply type
232: ArrayList results = (ArrayList) itemBuckets
233: .get(directObject);
234:
235: if (results == null) {
236: //System.out.println(debugStart + ": adding new bucket for " + directObject);
237: results = new ArrayList(13);
238: itemBuckets.put(directObject, results);
239: }
240:
241: ArrayList al = splitResult(psTask.getPlanElement()
242: .getReportedResult(), psTask
243: .getPreferredValue(AlpineAspectType.DEMANDRATE));
244: //System.out.println(debugStart + ": adding result to bucket " + al );
245: results.addAll(al);
246: }
247:
248: if (pacingItems.size() > 0) {
249: ArrayList results = calcResults(readinessTask, pacingItems,
250: earliest, latest);
251: System.out.println("\n\n" + debugStart
252: + " - cluster readiness");
253: printResults(results);
254: // set the allocation result of the toplevel task
255: }
256: }
257:
258: /**
259: * @return an collection of AspectValue[] - part of a phased AllocationResult
260: */
261: protected ArrayList calcResults(Task parentTask, HashMap tree,
262: long start, long end) {
263: ArrayList in = new ArrayList(13);
264:
265: // Collection of AspectValue[] for entire Agent
266: ArrayList overallResults = new ArrayList(13);
267: // Collection of AspectValue[] for a pacing item
268: ArrayList pacingResults = new ArrayList(13);
269: // Collection of AspectValue[] for a pacing item and supply type
270: ArrayList pacingAndSupplyResults = new ArrayList(13);
271:
272: int mergeCount = 0;
273:
274: for (Iterator itemIt = tree.keySet().iterator(); itemIt
275: .hasNext();) {
276: MaintainedItem pacingItem = (MaintainedItem) itemIt.next();
277: // make new subtask of toplevel task
278: Task pacingTask = createSubTask(parentTask, pacingItem,
279: null);
280: publishAddToExpansion(parentTask, pacingTask);
281:
282: HashMap itemBuckets = (HashMap) tree.get(pacingItem);
283: for (Iterator bucketsIt = itemBuckets.keySet().iterator(); bucketsIt
284: .hasNext();) {
285: Asset suppliedItem = (Asset) bucketsIt.next();
286: ArrayList bucket = (ArrayList) itemBuckets
287: .get(suppliedItem);
288:
289: long lastEnd = start;
290: while (lastEnd < end) {
291: long day1 = lastEnd;
292: long dayn = lastEnd + (MILLISPERDAY * rollupSpan);
293: lastEnd = dayn;
294: in.clear();
295: for (Iterator rseIt = bucket.iterator(); rseIt
296: .hasNext();) {
297: RateScheduleElement rse = (RateScheduleElement) rseIt
298: .next();
299: if (inRange(day1, dayn, rse)) {
300: in.add(rse);
301: rseIt.remove(); // counted it once. won't need it again
302: }
303: }
304: AspectValue[] avs = newReadinessAspectArray(day1,
305: dayn, average(in));
306: if (Double.isNaN(avs[2].getValue())) {
307: System.err.println(debugStart
308: + "invalid aspect value " + avs);
309: }
310: pacingAndSupplyResults.add(avs);
311: }
312: // At this point we have the phased allocation result collection for the lowest level task (pacing item, supply type)
313: // make new subtask of pacing item task and fill in its allocation result
314: Task pacingAndSupplyTask = createSubTask(pacingTask,
315: pacingItem, suppliedItem);
316: if (pacingResults.isEmpty()) {
317: pacingResults.addAll(pacingAndSupplyResults);
318: mergeCount = 1;
319: } else {
320: mergeAdd(pacingResults, pacingAndSupplyResults);
321: mergeCount++;
322: }
323: publishAddToExpansion(pacingTask, pacingAndSupplyTask);
324: publishAllocationResult(pacingAndSupplyTask,
325: pacingAndSupplyResults);
326: //System.out.println();
327: //System.out.println(pacingItem + " " + suppliedItem);
328: //printResults(pacingAndSupplyResults);
329: pacingAndSupplyResults.clear();
330: }
331:
332: averageResults(pacingResults, mergeCount);
333: // At this point we have enough info to fill in the allocation result collection for the the pacing item task
334: // fill in allocation result of pacing item subtask
335:
336: if (overallResults.isEmpty()) {
337: overallResults.addAll(pacingResults);
338: } else {
339: merge(overallResults, pacingResults);
340: }
341:
342: publishAddToExpansion(parentTask, pacingTask);
343: publishAllocationResult(pacingTask, pacingResults);
344:
345: // System.out.println(); System.out.println();
346: // System.out.println(debugStart);
347: // System.out.println(pacingItem);
348: // printResults(pacingResults);
349: pacingResults.clear();
350: }
351: publishAllocationResult(parentTask, overallResults);
352: return overallResults;
353: }
354:
355: /**
356: * pick the minimum readiness value of each phase
357: * @param oldList min of previous phased results
358: * @param newList new phased result to merge in
359: **/
360: protected void merge(ArrayList oldList, ArrayList newList) {
361: // sure hope these cover the same time span!
362:
363: if (oldList.size() != newList.size()) {
364: System.err
365: .println(debugStart
366: + ".merge() - bad assumption, Bub. The results have different cardinalities!");
367: return;
368: }
369:
370: for (int i = 0; i < oldList.size(); i++) {
371: AspectValue[] oldAV = (AspectValue[]) oldList.get(i);
372: AspectValue[] newAV = (AspectValue[]) newList.get(i);
373:
374: // arrays should have the same three aspect types
375: if (oldAV[0].getValue() != newAV[0].getValue()) {
376: System.err
377: .println(debugStart
378: + ".merge() - bad assumption, Bub. The AspectValues have different start dates!");
379: return;
380: }
381: if (oldAV[1].getValue() != newAV[1].getValue()) {
382: System.err
383: .println(debugStart
384: + ".merge() - bad assumption, Bub. The AspectValues have different end dates!");
385: return;
386: }
387:
388: // You are the weekest link!
389: if (oldAV[2].getValue() > newAV[2].getValue()) {
390: oldAV[2] = newAV[2];
391: }
392: }
393: }
394:
395: /**
396: * add the readiness value of each phase
397: * @param runningTotalList running total each phase of phased results
398: * @param newList new phased result to add to total
399: **/
400: protected void mergeAdd(ArrayList runningTotalList,
401: ArrayList newList) {
402: // sure hope these cover the same time span!
403:
404: if (runningTotalList.size() != newList.size()) {
405: System.err
406: .println(debugStart
407: + ".mergeAdd() - bad assumption, Bub. The results have different cardinalities!");
408: return;
409: }
410:
411: for (int i = 0; i < runningTotalList.size(); i++) {
412: AspectValue[] oldAV = (AspectValue[]) runningTotalList
413: .get(i);
414: AspectValue[] newAV = (AspectValue[]) newList.get(i);
415:
416: // arrays should have the same three aspect types
417: if (oldAV[0].getValue() != newAV[0].getValue()) {
418: System.err
419: .println(debugStart
420: + ".mergeAdd() - bad assumption, Bub. The AspectValues have different start dates!");
421: return;
422: }
423: if (oldAV[1].getValue() != newAV[1].getValue()) {
424: System.err
425: .println(debugStart
426: + ".mergeAdd() - bad assumption, Bub. The AspectValues have different end dates!");
427: return;
428: }
429:
430: oldAV[2] = oldAV[2].dupAspectValue(oldAV[2].getValue()
431: + newAV[2].getValue());
432: }
433: }
434:
435: /**
436: * divide each qty by the number of items added together to produce the qty.
437: **/
438: protected void averageResults(ArrayList results, int denominator) {
439:
440: // not much point in doing this if denominator is 0
441: if (denominator == 0)
442: return;
443:
444: for (int i = 0; i < results.size(); i++) {
445: AspectValue[] avs = (AspectValue[]) results.get(i);
446: avs[2] = avs[2].dupAspectValue(avs[2].getValue()
447: / denominator);
448: }
449: }
450:
451: protected static final long MILLISPERDAY = 1000 * 60 * 60 * 24;
452:
453: /**
454: * assign a rate value to each day covered by the allocation result ranges
455: **/
456: private ArrayList splitResult(AllocationResult ar,
457: double preferedRate) {
458: ArrayList schedule = new ArrayList(13);
459: if (ar == null)
460: return schedule;
461:
462: // if (!ar.isSuccess()) {
463: // AspectValue[] rollup = ar.getAspectValueResults();
464: // for (int i=0; i<rollup.length; i++) {
465: // if (rollup[i].getAspectType() == AlpineAspectType.DEMANDRATE) {
466: // System.out.println(debugStart + " failed task with rollup demand rate of " + rollup[i].getValue());
467: // break;
468: // }
469: // }
470: // }
471:
472: if (ar.isPhased()) {
473: for (Iterator phasedIterator = ar
474: .getPhasedAspectValueResults().iterator(); phasedIterator
475: .hasNext();) {
476: long start = -1, end = -1;
477: double rate = -1;
478: AspectValue[] avs = (AspectValue[]) phasedIterator
479: .next();
480: // System.out.println("ReadinessAssessor.splitResult ");
481: for (int i = 0; i < avs.length; i++) {
482:
483: // find the start and end dates and the rate
484: switch (avs[i].getAspectType()) {
485: case AspectType.START_TIME:
486: start = avs[i].longValue();
487: break;
488: case AspectType.END_TIME:
489: end = avs[i].longValue();
490: break;
491: case AspectType.POD:
492: //ignore;
493: break;
494: case AlpineAspectType.DEMANDMULTIPLIER:
495: //ignore;
496: break;
497: case AlpineAspectType.DEMANDRATE:
498: rate = avs[i].getValue();
499: if (!ar.isSuccess()) {
500: //System.out.println(debugStart + " failed task DemandRate is " + rate + " task Prefered rate is " + preferedRate);
501: }
502: break;
503: default:
504: System.err.println(debugStart
505: + " Unexpected AspectType: "
506: + avs[i].getAspectType());
507: break;
508: }
509: if (start == -1 || end == -1 || rate == -1)
510: continue;
511: }
512:
513: // don't make one for the last day
514: for (long day = start; day < end; day += MILLISPERDAY) {
515: RateScheduleElement rse;
516: if (preferedRate != 0) {
517: rse = new RateScheduleElement(day, rate
518: / preferedRate);
519: } else {
520: rse = new RateScheduleElement(day, 1.0);
521: System.err.println(debugStart
522: + "preferedRate of task is zero. why?");
523: }
524: // System.out.println("ReadinessAssessor.splitResult() adding " + rse);
525: schedule.add(rse);
526: }
527: }
528: } else {
529: System.err.println(debugStart
530: + ".splitResult() allocation result is not phased");
531: }
532: return schedule;
533: }
534:
535: protected boolean inRange(long startTime, long endTime,
536: RateScheduleElement rse) {
537: if ((rse.date < startTime) || (rse.date >= endTime))
538: return false;
539: return true;
540: }
541:
542: /** find the average readiness of the RateScheduleElements in the collection **/
543: protected double average(Collection rses) {
544: // wipe out existing numbers
545: int weight = 0;
546: double runningTotal = 0;
547: for (Iterator rseIt = rses.iterator(); rseIt.hasNext();) {
548: RateScheduleElement rse = (RateScheduleElement) rseIt
549: .next();
550: runningTotal += rse.readiness;
551: weight++;
552: }
553: if (weight == 0) {
554: //System.out.println(debugStart + "average() - no elements in collection - nothing to average");
555: return 1.0;
556: }
557: return runningTotal / weight;
558: }
559:
560: protected AspectValue[] newReadinessAspectArray(long startTime,
561: long endTime, double readiness) {
562: AspectValue[] values = new AspectValue[3];
563: values[0] = AspectValue.newAspectValue(AspectType.START_TIME,
564: startTime);
565: values[1] = AspectValue.newAspectValue(AspectType.END_TIME,
566: endTime);
567: // where do I put READINESS aspecttype?
568: values[2] = AspectValue.newAspectValue(AspectType.READINESS,
569: readiness);
570: return values;
571: }
572:
573: private void printResults(ArrayList results) {
574: for (int i = 0; i < results.size(); i++) {
575: AspectValue[] avs = (AspectValue[]) results.get(i);
576: StringBuffer buf = new StringBuffer();
577: buf.append("Start Date = ");
578: buf.append((new Date(avs[0].longValue())).toString());
579: buf.append(", End Date = ");
580: buf.append((new Date(avs[1].longValue())).toString());
581: buf.append(", readiness=");
582: buf.append(avs[2].getValue());
583: System.out.println(buf.toString());
584: }
585: }
586:
587: public NewTask createSubTask(Task parent, MaintainedItem pacing,
588: Asset supplyType) {
589: NewTask subtask = rootFactory.newTask();
590: subtask.setParentTask(parent);
591: subtask.setVerb(parent.getVerb());
592: subtask.setPreferences(parent.getPreferences());
593: subtask.setContext(parent.getContext());
594: Vector preps = new Vector(2);
595: NewPrepositionalPhrase prep = null;
596: if (pacing != null) {
597: prep = rootFactory.newPrepositionalPhrase();
598: prep.setPreposition(Constants.Preposition.FOR);
599: prep.setIndirectObject(pacing);
600: preps.add(prep);
601: }
602: if (supplyType != null) {
603: prep = rootFactory.newPrepositionalPhrase();
604: prep.setPreposition(Constants.Preposition.WITH);
605: prep.setIndirectObject(supplyType);
606: preps.add(prep);
607: }
608: subtask.setPrepositionalPhrases(preps.elements());
609: blackboard.publishAdd(subtask);
610: return subtask;
611: }
612:
613: private AspectValue[] calcRollup(List phasedResults) {
614: long startTime = Long.MAX_VALUE;
615: long endTime = Long.MIN_VALUE;
616: double runningTotal = 0;
617:
618: for (Iterator listIt = phasedResults.iterator(); listIt
619: .hasNext();) {
620: AspectValue[] avs = (AspectValue[]) listIt.next();
621: if (avs[0].longValue() < startTime) {
622: startTime = avs[0].longValue();
623: }
624: if (avs[1].longValue() > endTime) {
625: endTime = avs[1].longValue();
626: }
627: runningTotal += avs[2].getValue();
628: }
629:
630: // should I do average or min?
631: double avgReadiness = runningTotal / phasedResults.size();
632: AspectValue[] rollup = newReadinessAspectArray(startTime,
633: endTime, avgReadiness);
634: return rollup;
635: }
636:
637: protected void publishAllocationResult(Task task, List phasedResults) {
638: AspectValue[] rollup = calcRollup(phasedResults);
639: AllocationResult ar = rootFactory.newAVPhasedAllocationResult(
640: 1, true, rollup, phasedResults);
641: PlanElement pe = task.getPlanElement();
642: if (pe == null) {
643: // must be an disposition, rather than a expansion or allocation
644: pe = rootFactory
645: .createDisposition(task.getPlan(), task, ar);
646: pe.setEstimatedResult(ar);
647: blackboard.publishAdd(pe);
648: } else {
649: pe.setEstimatedResult(ar);
650: blackboard.publishChange(pe);
651: }
652: }
653:
654: protected void publishAddToExpansion(Task parent, Task subtask) {
655: // Publish new task
656: // if (!blackboard.publishAdd(subtask)) {
657: // System.err.println("ReadinessAssessorPlugin.publishAddToExpansion fail to publish task" +TaskUtils.taskDesc(subtask));
658: // }
659: PlanElement pe = parent.getPlanElement();
660: Expansion expansion;
661: NewWorkflow wf;
662: // Parent task has not been yet expanded, create an expansion
663: if (pe == null) {
664: // Create workflow
665: wf = (NewWorkflow) rootFactory.newWorkflow();
666: wf.setParentTask(parent);
667: wf.setIsPropagatingToSubtasks(true);
668: wf.addTask(subtask);
669: wf.setAllocationResultAggregator(allocationAggregator);
670: ((NewTask) subtask).setWorkflow(wf);
671: // Build Expansion
672: expansion = rootFactory.createExpansion(parent.getPlan(),
673: parent, wf, null);
674: // Publish Expansion
675: blackboard.publishAdd(expansion);
676: }
677: // Task already has expansion, add task to the workflow and publish the change
678: else if (pe instanceof Expansion) {
679: expansion = (Expansion) pe;
680: wf = (NewWorkflow) expansion.getWorkflow();
681: wf.addTask(subtask);
682: ((NewTask) subtask).setWorkflow(wf);
683: blackboard.publishChange(expansion);
684: } else {
685: System.err
686: .println("ReadinessAssessorPlugin.publishAddToExpansion: problem pe not Expansion?"
687: + pe);
688: }
689: }
690:
691: /**
692: * @param org Organization
693: * @return Collection of subordinates
694: */
695: private Collection findSubordinates(Organization org) {
696:
697: Collection subordinates = org.getRelationshipPG()
698: .getRelationshipSchedule().getMatchingRelationships(
699: Constants.Role.ADMINISTRATIVESUBORDINATE,
700: TimeSpan.MIN_VALUE, TimeSpan.MAX_VALUE);
701: return subordinates;
702: }
703:
704: private void expandAndAllocateToSubordinates(Task parentTask) {
705: Organization selfOrg = getSelfOrg();
706: RelationshipSchedule rs = selfOrg.getRelationshipSchedule();
707:
708: Collection subordinates = findSubordinates(selfOrg);
709:
710: for (Iterator subOrgIt = subordinates.iterator(); subOrgIt
711: .hasNext();) {
712:
713: Relationship rel = (Relationship) subOrgIt.next();
714: Organization subOrg = (Organization) rs.getOther(rel);
715:
716: // create new task
717: Task subtask = createSubTask(parentTask, null, null);
718:
719: // add to expanstion
720: publishAddToExpansion(parentTask, subtask);
721:
722: // allocate it to the subordinate
723: PlanElement pe = rootFactory.createAllocation(subtask
724: .getPlan(), subtask, subOrg, null,
725: Constants.Role.BOGUS);
726: blackboard.publishAdd(pe);
727: System.out.println(debugStart
728: + " allocating task to subordinate organization "
729: + subOrg);
730: }
731: }
732:
733: private Organization getSelfOrg() {
734: // better be something here!
735: return (Organization) selfOrgSub.iterator().next();
736: }
737:
738: protected class RateScheduleElement {
739: public long date;
740: public double readiness;
741:
742: public RateScheduleElement(long date, double readiness) {
743: this .date = date;
744: this .readiness = readiness;
745: }
746:
747: public String toString() {
748: StringBuffer buf = new StringBuffer();
749: buf.append("RateScheduleElement[date=");
750: buf.append((new Date(date)).toString());
751: buf.append(", readiness=");
752: buf.append(readiness);
753: buf.append("] ");
754: return buf.toString();
755: }
756:
757: public boolean equals(Object o) {
758: if (!(o instanceof RateScheduleElement))
759: return false;
760: RateScheduleElement other = (RateScheduleElement) o;
761: if ((date == other.date) && (readiness == other.readiness))
762: return true;
763: return false;
764: }
765: }
766:
767: private class PhasedAggregated implements
768: AllocationResultAggregator {
769: public AllocationResult calculate(Workflow wf,
770: TaskScoreTable tst, AllocationResult currentar) {
771: int count = 0;
772: boolean suc = true;
773: double rating = 0.0;
774: ArrayList mergedPhased = new ArrayList(13);
775:
776: Enumeration tasks = wf.getTasks();
777: if (tasks == null || (!tasks.hasMoreElements()))
778: return null;
779:
780: while (tasks.hasMoreElements()) {
781: Task t = (Task) tasks.nextElement();
782: count++;
783: AllocationResult ar = tst.getAllocationResult(t);
784: if (ar == null) {
785: return null; // bail if undefined
786: }
787:
788: ArrayList currentPhased = null;
789: // better be phased!
790: if (ar.isPhased()) {
791:
792: if (mergedPhased.isEmpty()) {
793: mergedPhased.addAll(ar
794: .getPhasedAspectValueResults());
795: } else {
796: currentPhased = new ArrayList(ar
797: .getPhasedAspectValueResults());
798: mergeAdd(mergedPhased, currentPhased);
799: }
800: }
801:
802: suc = suc && ar.isSuccess();
803: rating += ar.getConfidenceRating();
804: } // end of looping through all subtasks
805: averageResults(mergedPhased, tst.size());
806: AspectValue[] acc = calcRollup(mergedPhased);
807:
808: rating /= count;
809:
810: boolean delta = false;
811:
812: // only check the defined aspects and make sure that the currentar is not null
813: if (currentar == null) {
814: delta = true; // if the current ar == null then set delta true
815: } else {
816: int[] caraspects = currentar.getAspectTypes();
817: if (caraspects.length != acc.length) {
818: //if the current ar length is different than the length of the new
819: // calculations (acc) there's been a change
820: delta = true;
821: } else {
822: for (int i = 0; i < caraspects.length; i++) {
823: int da = caraspects[i];
824: for (int j = 0; j < acc.length; j++) {
825: if (acc[j].getAspectType() == da) {
826: if (acc[j].getValue() != currentar
827: .getValue(da)) {
828: delta = true;
829: break;
830: }
831: }
832: }
833: }
834: }
835:
836: if (!delta) {
837: if (currentar.isSuccess() != suc) {
838: delta = true;
839: } else if (Math.abs(currentar.getConfidenceRating()
840: - rating) > SIGNIFICANT_CONFIDENCE_RATING_DELTA) {
841: delta = true;
842: }
843: }
844: }
845:
846: if (delta) {
847: AllocationResult artoreturn = rootFactory
848: .newAVPhasedAllocationResult(1, true, acc,
849: mergedPhased);
850: return artoreturn;
851: } else {
852: return currentar;
853: }
854: }
855: }
856: }
|