0001: /*
0002: * <copyright>
0003: *
0004: * Copyright 2001-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: package org.cougaar.lib.vishnu.client;
0027:
0028: import org.cougaar.core.util.UID;
0029: import org.cougaar.lib.callback.UTILAggregationCallback;
0030: import org.cougaar.lib.callback.UTILExpansionCallback;
0031: import org.cougaar.lib.callback.UTILExpansionListener;
0032: import org.cougaar.lib.callback.UTILFilterCallback;
0033: import org.cougaar.lib.callback.UTILFilterCallbackAdapter;
0034: import org.cougaar.lib.callback.UTILGenericListener;
0035: import org.cougaar.lib.callback.UTILWorkflowCallback;
0036: import org.cougaar.lib.filter.UTILAggregatorPlugin;
0037: import org.cougaar.lib.util.UTILPluginException;
0038: import org.cougaar.lib.util.UTILRuntimeException;
0039: import org.cougaar.planning.Constants;
0040: import org.cougaar.planning.ldm.asset.Asset;
0041: import org.cougaar.planning.ldm.asset.AssetGroup;
0042: import org.cougaar.planning.ldm.asset.NewItemIdentificationPG;
0043: import org.cougaar.planning.ldm.plan.Aggregation;
0044: import org.cougaar.planning.ldm.plan.AllocationResult;
0045: import org.cougaar.planning.ldm.plan.AspectScorePoint;
0046: import org.cougaar.planning.ldm.plan.AspectType;
0047: import org.cougaar.planning.ldm.plan.AspectValue;
0048: import org.cougaar.planning.ldm.plan.Composition;
0049: import org.cougaar.planning.ldm.plan.Expansion;
0050: import org.cougaar.planning.ldm.plan.MPTask;
0051: import org.cougaar.planning.ldm.plan.NewComposition;
0052: import org.cougaar.planning.ldm.plan.NewMPTask;
0053: import org.cougaar.planning.ldm.plan.NewTask;
0054: import org.cougaar.planning.ldm.plan.PlanElement;
0055: import org.cougaar.planning.ldm.plan.Preference;
0056: import org.cougaar.planning.ldm.plan.ScoringFunction;
0057: import org.cougaar.planning.ldm.plan.Task;
0058: import org.cougaar.planning.ldm.plan.Verb;
0059: import org.cougaar.planning.ldm.plan.Workflow;
0060: import org.cougaar.util.UnaryPredicate;
0061:
0062: import java.util.Collection;
0063: import java.util.Collections;
0064: import java.util.Date;
0065: import java.util.Enumeration;
0066: import java.util.HashMap;
0067: import java.util.HashSet;
0068: import java.util.Iterator;
0069: import java.util.List;
0070: import java.util.Map;
0071: import java.util.Set;
0072: import java.util.Vector;
0073:
0074: /**
0075: * Aggregator version of ALP-Vishnu Bridge.
0076: * <p>
0077: * The key thing to note is that the asset in the task->asset <br>
0078: * association is on the WITH preposition of the generated MPTask.
0079: * <p>
0080: * This is critical, because the allocator downstream will look for this <br>
0081: * prep and pluck the asset off to make the allocation.
0082: * <p>
0083: * Uses the assigned start and end times to set the preferences and <br>
0084: * allocation results.
0085: * <p>
0086: * Adjust preferences so that the start time preference is the assigned <br>
0087: * start time, and the end time preference has a best date that is the <br>
0088: * assigned end time. The early and late dates of the end time preference <br>
0089: * are the same as the first parent task. (This isn't very important, as the<br>
0090: * downstream allocator should just allocate to the start and best times.)
0091: * <p>
0092: * Many times subclasses will want to redefine <br>
0093: * <code>interestingTask</code> and <code>interestingAsset</code> to filter <br>
0094: * what goes to the Vishnu scheduler. If you do, it's good form to call <br>
0095: * super.interestingTask().
0096: * <p>
0097: * @see org.cougaar.lib.vishnu.client.VishnuPlugin#interestingAsset
0098: * <!--
0099: * (When printed, any longer line will wrap...)
0100: *345678901234567890123456789012345678901234567890123456789012345678901234567890
0101: * 1 2 3 4 5 6 7 8
0102: * -->
0103: */
0104: public class VishnuAggregatorPlugin extends VishnuPlugin implements
0105: UTILAggregatorPlugin, UTILExpansionListener {
0106: // see explanation below for bug #11866
0107: protected Map tripletToTask = new HashMap();
0108: protected Map taskToTriplet = new HashMap();
0109: // avoids blackboard query
0110: protected Map uidToMPTask = new HashMap();
0111: protected UTILFilterCallback mpTaskCallback;
0112:
0113: boolean propagateRescindPastAggregation;
0114:
0115: /** creates an XMLResultHandler specially for this plugin */
0116: protected XMLResultHandler createXMLResultHandler() {
0117: return new AggregateXMLResultHandler(this , comm, xmlProcessor,
0118: domUtil, config, getMyParams(), logger);
0119: }
0120:
0121: public void localSetup() {
0122: super .localSetup();
0123:
0124: try {
0125: if (getMyParams().hasParam(
0126: "propagateRescindPastAggregation"))
0127: propagateRescindPastAggregation = getMyParams()
0128: .getBooleanParam(
0129: "propagateRescindPastAggregation");
0130: else
0131: propagateRescindPastAggregation = true;
0132: } catch (Exception e) {
0133: }
0134: }
0135:
0136: /**
0137: * adds the aggregation filter and two map filters
0138: *
0139: * - one filter looks for MPTasks and keeps track of a map of uid->MPTask,
0140: * which is used when we need to add new parent tasks to an existing MPTask.
0141: *
0142: * - one filter looks for subtasks of the MPTask and updates the triplet->task
0143: * and task->triplet maps when tasks are removed. These are also used
0144: * when we need to add new parent tasks to an existing MPTask and its subtasks.
0145: *
0146: * @see #forgetTripletToTask
0147: */
0148: public void setupFilters() {
0149: super .setupFilters();
0150:
0151: if (isInfoEnabled()) {
0152: info(getName() + " : Filtering for Aggregations...");
0153: }
0154:
0155: addFilter(myAggCallback = createAggCallback());
0156:
0157: if (isInfoEnabled()) {
0158: info(getName() + " : Filtering for Expansions...");
0159: }
0160:
0161: addFilter(new UTILExpansionCallback(this , logger));
0162:
0163: addFilter(mpTaskCallback = new UTILFilterCallbackAdapter(this ,
0164: logger) {
0165: protected UnaryPredicate getPredicate() {
0166: return new UnaryPredicate() {
0167: public boolean execute(Object o) {
0168: return (o instanceof MPTask);
0169: }
0170: };
0171: }
0172:
0173: public void reactToChangedFilter() {
0174: Enumeration addedtasks = getSubscription()
0175: .getAddedList();
0176: while (addedtasks.hasMoreElements()) {
0177: Task t = (Task) addedtasks.nextElement();
0178:
0179: if (!(t instanceof MPTask))
0180: error("huh? " + t + " is not an MPTask??");
0181:
0182: if (isInfoEnabled()) {
0183: info("uidToMPTask - mapping mptask "
0184: + t.getUID());
0185: }
0186:
0187: uidToMPTask.put(t.getUID(), t);
0188: }
0189:
0190: if (getSubscription().getRemovedList()
0191: .hasMoreElements()) {
0192: Enumeration removedtasks = getSubscription()
0193: .getRemovedList();
0194: while (removedtasks.hasMoreElements()) {
0195: MPTask mpt = (MPTask) removedtasks
0196: .nextElement();
0197:
0198: if (uidToMPTask.remove(mpt.getUID()) == null) {
0199: if (isDebugEnabled()) {
0200: debug("no mp task in map with uid "
0201: + mpt.getUID());
0202: }
0203: } else {
0204: if (isInfoEnabled()) {
0205: info("uidToMPTask - removing mp task uid "
0206: + mpt.getUID() + " from map");
0207: }
0208: // OK somehow there's a race where we can add a parent to an MPTask
0209: // and then immediately after the MPTask is removed, WITHOUT the Aggregation being
0210: // removed. How this is possible, I don't completely understand...
0211: Collection parentsToReplan = new HashSet();
0212:
0213: for (Enumeration en = ((MPTask) mpt)
0214: .getParentTasks(); en
0215: .hasMoreElements();) {
0216: Task parent = (Task) en.nextElement();
0217: if (parent.getPlanElement() != null) {
0218: if (isInfoEnabled()) {
0219: info("uidToMPTask - from MPTask parent enumeration - removing plan element from parent "
0220: + parent.getUID());
0221: }
0222: parentsToReplan.add(parent);
0223: }
0224: }
0225:
0226: for (Iterator iter = mpt.getComposition()
0227: .getParentTasks().iterator(); iter
0228: .hasNext();) {
0229: Task parent = (Task) iter.next();
0230: if (parent.getPlanElement() != null) {
0231: if (isInfoEnabled()) {
0232: info("uidToMPTask - from composition parent tasks - removing plan element from parent "
0233: + parent.getUID());
0234: }
0235: parentsToReplan.add(parent);
0236: }
0237: }
0238:
0239: for (Iterator iter = parentsToReplan
0240: .iterator(); iter.hasNext();) {
0241: Task parent = (Task) iter.next();
0242: publishRemove(parent.getPlanElement());
0243: publishChange(parent);
0244: }
0245:
0246: if (!parentsToReplan.isEmpty()) {
0247: // remember to tell scheduler to forget about them too!
0248: handleRemovedTasks(Collections
0249: .enumeration(parentsToReplan));
0250: }
0251: }
0252: }
0253: }
0254: }
0255: });
0256:
0257: addFilter(new UTILFilterCallbackAdapter(this , logger) {
0258: protected UnaryPredicate getPredicate() {
0259: return new UnaryPredicate() {
0260: public boolean execute(Object o) {
0261: if (!(o instanceof Task))
0262: return false;
0263: Task task = (Task) o;
0264: PlanElement pe = task.getPlanElement();
0265: boolean hasPE = (pe != null);
0266: if (hasPE && pe instanceof Aggregation)
0267: return false;
0268: if (o instanceof MPTask)
0269: return false;
0270: else
0271: // non-MPTasks that don't have aggregations
0272: return true;
0273: }
0274: };
0275: }
0276:
0277: public void reactToChangedFilter() {
0278: if (getSubscription().getRemovedList()
0279: .hasMoreElements()) {
0280: Enumeration removedtasks = getSubscription()
0281: .getRemovedList();
0282: while (removedtasks.hasMoreElements()) {
0283: Task removed = (Task) removedtasks
0284: .nextElement();
0285:
0286: if (!forgetTripletToTask(removed)) {
0287: if (isInfoEnabled()) {
0288: info("no task in map with uid "
0289: + removed.getUID());
0290: }
0291: } else if (isInfoEnabled()) {
0292: info("removing task uid "
0293: + removed.getUID() + " from maps");
0294: }
0295: }
0296: }
0297: }
0298: });
0299: }
0300:
0301: /*** Callback for input tasks ***/
0302: protected UTILWorkflowCallback myWorkflowCallback;
0303:
0304: /**
0305: * Callback for input tasks
0306: *
0307: * Creates an instance of the WorkflowCallback, which means the plugin
0308: * is looking for tasks that are part of workflows.
0309: *
0310: * @param bufferingThread -- the thread the callback informs when there are new input tasks
0311: * @return UTILFilterCallback -- an instance of UTILWorkflowCallback
0312: **/
0313: protected UTILFilterCallback createThreadCallback(
0314: UTILGenericListener bufferingThread) {
0315: if (isInfoEnabled()) {
0316: info(getName() + " Filtering for tasks with Workflows...");
0317: }
0318:
0319: myWorkflowCallback = new UTILWorkflowCallback(bufferingThread,
0320: logger);
0321:
0322: return myWorkflowCallback;
0323: }
0324:
0325: /** Callback for input tasks ***/
0326: protected UTILFilterCallback getWorkflowCallback() {
0327: return myWorkflowCallback;
0328: }
0329:
0330: /*** Callback for Aggregations ***/
0331: /** Callback for Aggregations **/
0332: protected UTILAggregationCallback myAggCallback;
0333:
0334: /** Callback for Aggregations **/
0335: protected UTILAggregationCallback getAggCallback() {
0336: return myAggCallback;
0337: }
0338:
0339: /** Callback for Aggregations **/
0340: protected UTILAggregationCallback createAggCallback() {
0341: return new UTILAggregationCallback(this , logger);
0342: }
0343:
0344: /*** Stuff for AggregationListener ***/
0345:
0346: /**
0347: * Should almost always call interestingTask.
0348: **/
0349: public boolean interestingParentTask(Task t) {
0350: boolean isInteresting = interestingTask(t);
0351:
0352: if (!isInteresting
0353: && ((t.getPlanElement().getReportedResult() != null) && !t
0354: .getPlanElement().getReportedResult()
0355: .isSuccess())) {
0356: debug(getName()
0357: + ".interestingParentTask - ignoring failed task : "
0358: + t.getUID());
0359: }
0360:
0361: return isInteresting;
0362: }
0363:
0364: /** implemented for AggregationListener */
0365: public boolean needToRescind(Aggregation agg) {
0366: return false;
0367: }
0368:
0369: /** implemented for AggregationListener */
0370: public void reportChangedAggregation(Aggregation agg) {
0371: updateAllocationResult(agg);
0372: }
0373:
0374: /** implemented for AggregationListener */
0375: public void handleSuccessfulAggregation(Aggregation agg) {
0376: if (agg.getEstimatedResult().getConfidenceRating() > allocHelper.MEDIUM_CONFIDENCE) {
0377: // don't do anything
0378: } else if (isDebugEnabled()) {
0379: debug(getName()
0380: + ".handleSuccessfulAggregation : got changed agg ("
0381: + agg.getUID() + ") with intermediate confidence.");
0382: }
0383: }
0384:
0385: /**
0386: * implemented for AggregationListener
0387: *
0388: * Cleans up maps of triplets to tasks, task to mptasks
0389: */
0390: public void handleRemovedAggregation(Aggregation agg) {
0391: Vector removedTasks = new Vector();
0392: removedTasks.add(agg.getTask());
0393:
0394: handleRemovedTasks(removedTasks.elements());
0395:
0396: MPTask mpTask = agg.getComposition().getCombinedTask();
0397: if (mpTask == null)
0398: error("no mp task on aggregation of "
0399: + agg.getTask().getUID());
0400: else {
0401: AssetGroup newGroup = removeFromDirectObject(agg.getTask(),
0402: mpTask);
0403: Expansion exp = (Expansion) mpTask.getPlanElement();
0404: if (exp == null) {
0405: warn("no expansion of mp task " + mpTask.getUID()
0406: + " must be in the middle of rescinds...");
0407: } else {
0408: Enumeration en = exp.getWorkflow().getTasks();
0409: while (en.hasMoreElements()) {
0410: Task subtask = (Task) en.nextElement();
0411:
0412: Vector newSet = new Vector();
0413: newSet.addAll(newGroup.getAssets());
0414: AssetGroup newAssetGroup = assetHelper
0415: .makeAssetGroup(getLDMService().getLDM()
0416: .getFactory(), newSet);
0417: ((NewItemIdentificationPG) newAssetGroup
0418: .getItemIdentificationPG())
0419: .setItemIdentification("group_for_subtask_of_"
0420: + mpTask.getUID()
0421: + "_with_"
0422: + newSet.size() + "_members");
0423: ((NewTask) subtask).setDirectObject(newAssetGroup);
0424:
0425: publishChange(subtask); // tell persistence these have changed too!
0426: }
0427:
0428: // post condition check
0429: if (isInfoEnabled()) {
0430: checkMPTaskDO(mpTask);
0431: }
0432: }
0433: }
0434: }
0435:
0436: /** implemented for AggregationListener */
0437: public boolean handleRescindedAggregation(Aggregation agg) {
0438: return false;
0439: }
0440:
0441: /** implemented for AggregationListener */
0442: public void publishRemovalOfAggregation(Aggregation aggToRemove) {
0443: Task changedTask = aggToRemove.getTask();
0444: publishRemove(aggToRemove);
0445: publishChange(changedTask);
0446: }
0447:
0448: /**
0449: * Implemented for ExpansionListener
0450: *
0451: * Interested in expansions created by this plugin, labeled with a VISHNU prep.
0452: * (That's how it knows which to be interested in.)
0453: */
0454: public boolean interestingExpandedTask(Task t) {
0455: Expansion exp = (Expansion) t.getPlanElement();
0456: if (exp == null)
0457: return false;
0458:
0459: Workflow wf = exp.getWorkflow();
0460:
0461: Enumeration en = wf.getTasks();
0462:
0463: Object firstTask = null;
0464:
0465: if (en.hasMoreElements())
0466: firstTask = en.nextElement();
0467: if (firstTask != null)
0468: return prepHelper.hasPrepNamed((Task) firstTask, "VISHNU");
0469: else
0470: return false;
0471: }
0472:
0473: public boolean wantToChangeExpansion(Expansion exp) {
0474: return false;
0475: }
0476:
0477: public void changeExpansion(Expansion exp) {
0478: }
0479:
0480: public void publishChangedExpansion(Expansion exp) {
0481: publishChange(exp);
0482: }
0483:
0484: public void handleConstraintViolation(Expansion exp,
0485: List violatedConstraints) {
0486: }
0487:
0488: public void handleFailedExpansion(Expansion exp, List failedSubTasks) {
0489: reportChangedExpansion(exp);
0490: }
0491:
0492: public void handleSuccessfulExpansion(Expansion exp,
0493: List successfulSubtasks) {
0494: }
0495:
0496: /**
0497: * Implemented for ExpansionListener
0498: * Report to superior that the expansion has changed. Usually just a pass
0499: * through to the UTILPluginAdapter's updateAllocationResult.
0500: *
0501: * @param exp Expansion that has changed.
0502: * @see org.cougaar.lib.callback.UTILExpansionListener
0503: */
0504: public void reportChangedExpansion(Expansion exp) {
0505: if (logger.isDebugEnabled()
0506: || (exp.getReportedResult() != null && !exp
0507: .getReportedResult().isSuccess()))
0508: debug(getName()
0509: + ".reportChangedExpansion : reporting "
0510: + (exp.getReportedResult().isSuccess() ? ""
0511: : " - FAILED - ") + " changed expansion "
0512: + exp.getUID() + " of " + exp.getTask().getUID()
0513: + " to superior.");
0514:
0515: updateAllocationResult(exp);
0516: }
0517:
0518: public void handleIllFormedTask(Task t) {
0519: reportIllFormedTask(t);
0520: }
0521:
0522: /**
0523: * define in subclass -- create an aggregation
0524: *
0525: * The parameters are what got returned from the vishnu scheduler.
0526: *
0527: * @param tasks tasks to be aggregated together and assigned to asset
0528: * @param asset asset handling task
0529: * @param start of main task
0530: * @param end of main task
0531: * @param setupStart start of setup task
0532: * @param wrapupEnd end of wrapup task
0533: */
0534: public void handleMultiAssignment(Vector tasks, Asset asset,
0535: Date start, Date end, Date setupStart, Date wrapupEnd,
0536: boolean assetWasUsedBefore) {
0537: if (isDebugEnabled()) {
0538: debug(getName() + ".handleMultiAssignment : ");
0539: debug("\nAssigned tasks : ");
0540: for (int i = 0; i < tasks.size(); i++) {
0541: Task task = (Task) tasks.get(i);
0542:
0543: Date ready = prefHelper.getReadyAt(task);
0544: Date early = prefHelper.getEarlyDate(task);
0545: Date late = prefHelper.getLateDate(task);
0546:
0547: if (start.before(ready) || end.before(early)
0548: || end.after(late))
0549: warn(""
0550: + task.getUID()
0551: + " - ready "
0552: + ready
0553: + (start.before(ready) ? (" AFTER start " + start)
0554: : "")
0555: + " early "
0556: + early
0557: + (end.before(early) ? (" AFTER end " + end)
0558: : "")
0559: + " best "
0560: + prefHelper.getBestDate(task)
0561: + " late "
0562: + late
0563: + (end.after(late) ? (" BEFORE end " + end)
0564: : ""));
0565: else
0566: debug(""
0567: + task.getUID()
0568: + " - ready "
0569: + ready
0570: + (start.before(ready) ? (" AFTER start " + start)
0571: : "")
0572: + " early "
0573: + early
0574: + (end.before(early) ? (" AFTER end " + end)
0575: : "")
0576: + " best "
0577: + prefHelper.getBestDate(task)
0578: + " late "
0579: + late
0580: + (end.after(late) ? (" BEFORE end " + end)
0581: : ""));
0582: }
0583: debug("\nresource = " + asset + "\nsetup = "
0584: + setupStart + "\nstart = " + start
0585: + "\nend = " + end + "\nwrapup = "
0586: + wrapupEnd);
0587: }
0588:
0589: makePlanElement(tasks, asset, start, end, setupStart,
0590: wrapupEnd, assetWasUsedBefore);
0591: }
0592:
0593: /**
0594: * <pre>
0595: * Background : the missions for a conveyance (ship, plane, truck)
0596: * are represented by MPTasks which assign an asset group of items
0597: * to a conveyance for a certain period of time. We want to prevent
0598: * the case where multiple MPTasks together represent one actual
0599: * mission, i.e. they are for the same conveyance and the same period
0600: * of time. It's better for memory footprint, simplicity, and the
0601: * asset usage display in the TPFDD Viewer.
0602: * See bug #11866 : https://bugs.ultralog.net/show_bug.cgi?id=11866
0603: *
0604: * Makes an aggregation given a list of assignments.
0605: *
0606: * Makes an aggregation with a medium confidence and publishes it.
0607: * Also makes an expansion of the MPTask. This may be a 1-to-1,
0608: * 1-to-2, or 1-to-3 expansion depending on the dates. If the
0609: * setup start is before the task start, then a separate setup task
0610: * is created and added to the expansion. Similarly for wrapup.
0611: * These dates are different if the vishnu scheduling specs define
0612: * setup (e.g. fueling an airplane) or wrapup (e.g. servicing an airplane)
0613: * durations. See referenced Vishnu documentation for details on specs.
0614: *
0615: * Calls the base class function makeSetupWrapupExpansion.
0616: *
0617: * Adds to a previously created MPTask when new tasks are assigned to an
0618: * asset.
0619: *
0620: * </pre>
0621: * @param tasklist - tasks for this asset
0622: * @param anAsset that these tasks are grouped for
0623: * @param start time start
0624: * @param end time end
0625: * @param setupStart setup start
0626: * @param wrapupEnd wrapup end
0627: * @see org.cougaar.planning.ldm.plan.Aggregation
0628: * @see org.cougaar.planning.ldm.plan.MPTask
0629: * @see org.cougaar.lib.vishnu.client.VishnuPlugin#makeSetupWrapupExpansion
0630: * @see <a href="http://www.cougaar.org/projects/vishnu/fulldoc.html#specs">
0631: * Click here for more on setup and wrapup specifications.</a>
0632: * @see #addToPrevious
0633: */
0634: public void makePlanElement(Vector tasklist, Asset anAsset,
0635: Date start, Date end, Date setupStart, Date wrapupEnd,
0636: boolean assetWasUsedBefore) {
0637: if (assetWasUsedBefore) {
0638: if (addToPrevious(tasklist, anAsset, start, end,
0639: setupStart, wrapupEnd))
0640: return;
0641: else {
0642: if (isInfoEnabled()) {
0643: info("Though we believe "
0644: + anAsset
0645: + " was used before at "
0646: + start
0647: + " we could not find the previous task, so making a new one.");
0648: }
0649: }
0650: }
0651:
0652: List aggResults = aggregateHelper.makeAggregation(this , ldmf,
0653: realityPlan, tasklist, getVerbForAgg(tasklist),
0654: getPrepPhrasesForAgg(anAsset, tasklist),
0655: getDirectObjectsForAgg(tasklist), getPreferencesForAgg(
0656: anAsset, tasklist, start, end),
0657: getAgentIdentifier(), getAspectValuesMap(tasklist,
0658: start, end), allocHelper.MEDIUM_CONFIDENCE);
0659: publishList(aggResults);
0660:
0661: cleanupAggregation(anAsset, tasklist, aggResults);
0662:
0663: Task mpTask = findMPTask(aggResults);
0664:
0665: if (uidToMPTask.get(mpTask.getUID()) == null) {
0666: if (isInfoEnabled()) {
0667: info("uidToMPTask - mapping mptask " + mpTask.getUID());
0668: }
0669: uidToMPTask.put(mpTask.getUID(), mpTask);
0670:
0671: if (isInfoEnabled()) {
0672: int numParents = 0;
0673: for (Enumeration en = ((MPTask) mpTask)
0674: .getParentTasks(); en.hasMoreElements();) {
0675: Task parent = (Task) en.nextElement();
0676: numParents++;
0677: }
0678: info(getName() + ".addToPrevious - MPTask "
0679: + mpTask.getUID() + " has " + numParents
0680: + " parents.");
0681: }
0682: }
0683:
0684: // store each distinct assignment so we can get it later in addToPrevious
0685: //
0686: // Bug #11866:
0687: //
0688: // The problem (https://bugs.ultralog.net/show_bug.cgi?id=11866) is that
0689: // addToPrevious initially looks on the role schedule for mptasks assigned to an asset.
0690: // BUT the allocator plugin has to get a chance to run to update the role schedule. So
0691: // it may seem like no previous task has been assigned, if you just look at the role schedule,
0692: // even though the assignment has been made (an MPTask created) but not yet reflected in
0693: // the role schedule via an allocation. This results in multiple MPTasks being made for the same
0694: // mission - the same conveyance and for the same period of time.
0695: //
0696: // We need to remember the assignment locally through a map to avoid this problem.
0697:
0698: if (assetWasUsedBefore) {
0699: if (isInfoEnabled()) {
0700: info("asset was used before, but made a new mptask : "
0701: + mpTask.getUID());
0702: }
0703: }
0704:
0705: Collection subtasks = makeSetupWrapupExpansion(mpTask, anAsset,
0706: start, end, setupStart, wrapupEnd);
0707:
0708: for (Iterator iter = subtasks.iterator(); iter.hasNext();) {
0709: Task subtask = (Task) iter.next();
0710: String taskKey = anAsset.getUID().toString() + "-"
0711: + prefHelper.getReadyAt(subtask).getTime() + "-"
0712: + prefHelper.getBestDate(subtask).getTime();
0713:
0714: Task alreadyTask;
0715: if ((alreadyTask = (Task) tripletToTask.get(taskKey)) == null) {
0716: if (isInfoEnabled()) {
0717: info(getName() + " mapping " + taskKey + " to "
0718: + subtask.getUID() + " mptask "
0719: + mpTask.getUID());
0720: }
0721: } else {
0722: if (isWarnEnabled()) {
0723: warn(getName()
0724: + " - unexpected : there already is a task "
0725: + subtask.getUID() + " in table with key "
0726: + taskKey + " it was "
0727: + alreadyTask.getUID());
0728: }
0729: }
0730:
0731: rememberTripletToTask(taskKey, subtask);
0732: }
0733: }
0734:
0735: /**
0736: * Fixes up the following when additional tasks are added to a previous
0737: * assignment:
0738: * 1) Adds to the d.o. of the transport task allocated to the asset
0739: * 2) (Optional) If setup task, adds to the d.o. of the task
0740: * 3) (Optional) If wrapup task, adds to the d.o. of the task
0741: * 4) Adds to the d.o. of the mp task
0742: * 5) Makes Mp task parent task list reflect new parent tasks
0743: * 6) Makes aggregations connecting parent tasks to mp task
0744: *
0745: * @param tasklist - tasks for this asset
0746: * @param anAsset that these tasks are grouped for/assigned to
0747: * @param start time start
0748: * @param end time end
0749: * @param setupStart setup start
0750: * @param wrapupEnd wrapup end
0751: */
0752: public boolean addToPrevious(Vector tasklist, Asset anAsset,
0753: Date start, Date end, Date setupStart, Date wrapupEnd) {
0754: // see explanation for bug #11866 above
0755: Task previousTask;
0756: String taskKey = anAsset.getUID().toString() + "-"
0757: + start.getTime() + "-" + end.getTime();
0758: previousTask = (Task) tripletToTask.get(taskKey);
0759:
0760: if (previousTask == null) {
0761: if (isInfoEnabled()) {
0762: info(getName() + " - couldn't find task with key "
0763: + taskKey + " so looking in role schedule of "
0764: + anAsset.getUID());
0765: }
0766: previousTask = getEncapsulatedTask(anAsset, start, end); // look on asset's role schedule
0767: if (previousTask != null) {
0768: rememberTripletToTask(taskKey, previousTask);
0769: }
0770: }
0771:
0772: if (previousTask != null) { // found transport task
0773: if (isDebugEnabled())
0774: debug(getName()
0775: + ".addToPrevious - found previous task for asset "
0776: + anAsset.getUID());
0777:
0778: Vector directObjects = getDirectObjectsForAgg(tasklist);
0779: // step 1 - add to d.o. of transport task
0780: AssetGroup directObject = addToDirectObject(previousTask,
0781: directObjects);
0782: if (makeSetupAndWrapupTasks) {
0783: if (setupStart.getTime() < start.getTime()) {
0784: // step 2 - add to d.o. of setup
0785: Vector newSet = new Vector();
0786: Vector assetsInGroup = directObject.getAssets();
0787: newSet.addAll(assetsInGroup);
0788: AssetGroup newAssetGroup = assetHelper
0789: .makeAssetGroup(getLDMService().getLDM()
0790: .getFactory(), newSet);
0791: ((NewItemIdentificationPG) newAssetGroup
0792: .getItemIdentificationPG())
0793: .setItemIdentification("setup_group_with_"
0794: + newSet.size() + "_members");
0795:
0796: addToPreviousSetupWrapup(anAsset, newAssetGroup,
0797: setupStart, start, "setup");
0798: }
0799: if (wrapupEnd.getTime() > end.getTime()) {
0800: // step 3 - add to d.o. of wrapup
0801: Vector newSet = new Vector();
0802: Vector assetsInGroup = directObject.getAssets();
0803: newSet.addAll(assetsInGroup);
0804: AssetGroup newAssetGroup = assetHelper
0805: .makeAssetGroup(getLDMService().getLDM()
0806: .getFactory(), newSet);
0807: ((NewItemIdentificationPG) newAssetGroup
0808: .getItemIdentificationPG())
0809: .setItemIdentification("wrapup_group_with_"
0810: + newSet.size() + "_members");
0811:
0812: addToPreviousSetupWrapup(anAsset, newAssetGroup,
0813: end, wrapupEnd, "wrapup");
0814: }
0815: }
0816:
0817: if (isInfoEnabled()) {
0818: info(getName() + " - looking task "
0819: + previousTask.getUID()
0820: + "'s mptask parent uid "
0821: + previousTask.getParentTaskUID());
0822: }
0823:
0824: MPTask mpTask = (MPTask) uidToMPTask.get(previousTask
0825: .getParentTaskUID());
0826: if (mpTask == null) { // should only happen after rehydration
0827: if (isInfoEnabled()) {
0828: info(getName()
0829: + " - looking for mptask parent of "
0830: + previousTask.getUID()
0831: + " on blackboard via expensive query, since parent uid "
0832: + previousTask.getParentTaskUID()
0833: + " is not in " + uidToMPTask.keySet());
0834: }
0835: // do expensive blackboard query
0836: mpTask = getMPTask(previousTask.getParentTaskUID());
0837: }
0838:
0839: if (mpTask == null) {
0840: if (isInfoEnabled()) {
0841: info("Can't find mptask "
0842: + previousTask.getParentTaskUID()
0843: + " parent of " + previousTask.getUID()
0844: + " on blackboard. Must have been removed.");
0845: }
0846:
0847: return false; // the MP task was removed from the blackboard while scheduler was running
0848: }
0849:
0850: // step 4 - add to d.o. of MPTask parent
0851: Vector newSet = new Vector();
0852: Vector assetsInGroup = directObject.getAssets();
0853: newSet.addAll(assetsInGroup);
0854: AssetGroup newAssetGroup = assetHelper.makeAssetGroup(
0855: getLDMService().getLDM().getFactory(), newSet);
0856: ((NewItemIdentificationPG) newAssetGroup
0857: .getItemIdentificationPG())
0858: .setItemIdentification("mpt_transport_group_with_"
0859: + newSet.size() + "_members");
0860:
0861: ((NewMPTask) mpTask).setDirectObject(newAssetGroup);
0862:
0863: // step 5 - Make MP Task know of new parents
0864: Enumeration parents = mpTask.getParentTasks();
0865: Vector parentsVector = enumToVector(parents);
0866: ((NewMPTask) mpTask).setParentTasks(getEnumWithNewParents(
0867: parentsVector, tasklist));
0868: if (isInfoEnabled()) {
0869: info(getName() + " - publish changing "
0870: + mpTask.getUID());
0871: }
0872: publishChange(mpTask);
0873:
0874: // step 6 - make aggregations for connecting parent tasks to MPTask
0875: NewComposition comp = (NewComposition) mpTask
0876: .getComposition();
0877: addAggregations(comp, tasklist, start, end);
0878: publishChange(comp);
0879:
0880: if (isInfoEnabled()) {
0881: int numParents = 0;
0882: for (Enumeration en = mpTask.getParentTasks(); en
0883: .hasMoreElements();) {
0884: Task parent = (Task) en.nextElement();
0885: numParents++;
0886: }
0887:
0888: info(getName() + ".addToPrevious - MPTask "
0889: + mpTask.getUID() + " has " + numParents
0890: + " parents.");
0891: }
0892:
0893: return true;
0894: }
0895: return false;
0896: }
0897:
0898: /**
0899: * Update the directObject of the setup and wrapup tasks when we get new assignments
0900: * to an existing mission. publishChanges the task.
0901: *
0902: * We need a triplet - the assigned asset and the start and end dates to unique identify
0903: * a setup or wrapup task. These come from the anAsset, start, and end parameters.
0904: *
0905: * First looks in the tripletToTask map, and if can't find the task there, looks at the
0906: * asset's role schedule, which is problematic (the allocator must have run), see above
0907: * discussion. The only time the tripletToTask map will be empty will be after rehydration.
0908: *
0909: * @param anAsset - first part of the triplet key
0910: * @param start - second part of the triplet key
0911: * @param end - third part of the triplet key
0912: * @param directObject contains the additional assets to add to the direct object of the updated
0913: * task
0914: */
0915: protected void addToPreviousSetupWrapup(Asset anAsset,
0916: Asset directObject, Date start, Date end, String info) {
0917: Task setupTask;
0918: String taskKey = anAsset.getUID().toString() + "-"
0919: + start.getTime() + "-" + end.getTime();
0920: if (isInfoEnabled()) {
0921: info(getName() + " - " + info
0922: + " - checking tripletToTask map for " + taskKey);
0923: }
0924: setupTask = (Task) tripletToTask.get(taskKey);
0925:
0926: if (setupTask == null) {
0927: if (isInfoEnabled()) {
0928: info(getName()
0929: + " - setup - nothing in tripletToTask map for "
0930: + taskKey + " so checking role schedule.");
0931: }
0932: setupTask = getEncapsulatedTask(anAsset, start, end);
0933: if (setupTask != null)
0934: rememberTripletToTask(taskKey, setupTask);
0935: }
0936:
0937: if (setupTask == null) { // shouldn't happen
0938: if (isWarnEnabled()) {
0939: warn(getAgentIdentifier() + " - " + " on " + anAsset
0940: + " missing a " + info + " task from " + start
0941: + " to " + end + "?");
0942: }
0943: } else {
0944: ((NewTask) setupTask).setDirectObject(directObject);
0945: if (isInfoEnabled()) {
0946: info(getName() + " - publish changing "
0947: + setupTask.getUID());
0948: }
0949: publishChange(setupTask);
0950: }
0951: }
0952:
0953: /**
0954: * Update both tripletToTask and taskToTriplet maps - add the subtask to them
0955: * with the asset-start-end triplet key.
0956: */
0957: protected void rememberTripletToTask(String taskKey, Task subtask) {
0958: if (isInfoEnabled())
0959: info("remembering " + subtask.getUID() + " key " + taskKey);
0960:
0961: tripletToTask.put(taskKey, subtask);
0962: taskToTriplet.put(subtask, taskKey);
0963: }
0964:
0965: /**
0966: * Update both tripletToTask and taskToTriplet maps - remove the subtask from them
0967: */
0968: protected boolean forgetTripletToTask(Object subtask) {
0969: if (isInfoEnabled()) {
0970: info("forgetting " + ((Task) subtask).getUID());
0971: }
0972:
0973: boolean retval = true;
0974:
0975: Object triplet = taskToTriplet.remove(subtask);
0976: if (triplet != null) {
0977: if (isInfoEnabled()) {
0978: info("forgetting key " + triplet);
0979: }
0980:
0981: if (tripletToTask.remove(triplet) == null) {
0982: retval = false;
0983: if (isInfoEnabled()) {
0984: info("no task for " + triplet);
0985: }
0986: }
0987:
0988: } else {
0989: retval = false;
0990: if (isInfoEnabled()) {
0991: info("no triplet for " + subtask);
0992: }
0993: }
0994:
0995: return retval;
0996: }
0997:
0998: /**
0999: * Look for a plan element on the role schedule of the asset
1000: * that covers exactly the same span of time
1001: *
1002: * @param asset to look at role schedule
1003: * @param start time of pe on role schedule
1004: * @param end time of pe on role schedule
1005: * @return task that is on role schedule of asset from exactly start to end
1006: */
1007: protected Task getEncapsulatedTask(Asset asset, Date start, Date end) {
1008: Collection tasks = asset.getRoleSchedule()
1009: .getEncapsulatedRoleSchedule(start.getTime(),
1010: end.getTime());
1011: if (tasks.isEmpty()) {
1012: if (isInfoEnabled()) {
1013: info("no task on role schedule of " + asset.getUID()
1014: + " - " + asset + " between " + start + " and "
1015: + end + "\nschedule was "
1016: + asset.getRoleSchedule());
1017: }
1018: return null;
1019: }
1020: for (Iterator iter = tasks.iterator(); iter.hasNext();) {
1021: PlanElement pe = (PlanElement) iter.next();
1022: long startTime = (long) pe.getEstimatedResult().getValue(
1023: AspectType.START_TIME);
1024: long endTime = (long) pe.getEstimatedResult().getValue(
1025: AspectType.END_TIME);
1026: if (startTime == start.getTime()
1027: && endTime == end.getTime()) {
1028: return pe.getTask();
1029: } else {
1030: if (isInfoEnabled()) {
1031: if (startTime == start.getTime()) {
1032: info(asset.getUID()
1033: + " - end times are different, pe end "
1034: + new Date(endTime) + " vs assigned "
1035: + new Date(end.getTime()) + " for "
1036: + asset);
1037: } else if (endTime == end.getTime()) {
1038: info(asset.getUID()
1039: + " - start times are different, pe start "
1040: + new Date(startTime) + " vs assigned "
1041: + new Date(start.getTime()) + " for "
1042: + asset);
1043: } else {
1044: info(asset.getUID()
1045: + " - both start and end times are different for "
1046: + asset);
1047: }
1048: }
1049: }
1050: }
1051: return null;
1052: }
1053:
1054: /**
1055: * Add objects to task's direct object
1056: *
1057: * @param task to add the objects to
1058: * @param objects to add to the task's d.o.
1059: * @return AssetGroup with objects added to it
1060: */
1061: protected AssetGroup addToDirectObject(Task task, Vector objects) {
1062: AssetGroup group = (AssetGroup) task.getDirectObject();
1063: Vector assetsInGroup = group.getAssets();
1064:
1065: Vector newSet = new Vector();
1066: newSet.addAll(assetsInGroup);
1067: newSet.addAll(objects);
1068: AssetGroup newAssetGroup = assetHelper.makeAssetGroup(
1069: getLDMService().getLDM().getFactory(), newSet);
1070:
1071: ((NewTask) task).setDirectObject(newAssetGroup);
1072: ((NewItemIdentificationPG) newAssetGroup
1073: .getItemIdentificationPG())
1074: .setItemIdentification("transport_group_with_"
1075: + newSet.size() + "_members");
1076:
1077: if (isInfoEnabled()) {
1078: info(getName() + " - publish changing " + task.getUID()
1079: + " now has " + newSet.size() + " items in d.o.");
1080: }
1081:
1082: publishChange(task);
1083:
1084: return newAssetGroup;
1085: }
1086:
1087: /**
1088: * Remove the parent task's direct object from the child mpTask's group
1089: * of direct objects.
1090: *
1091: * @param removedTask to task with the direct object to remove
1092: * @param mpTask to remove the direct object from
1093: * @return AssetGroup with objects removed from it
1094: */
1095: protected AssetGroup removeFromDirectObject(Task removedTask,
1096: MPTask mpTask) {
1097: AssetGroup group = (AssetGroup) mpTask.getDirectObject();
1098: Vector assetsInGroup = group.getAssets();
1099: // assetsInGroup.remove (removedTask.getDirectObject());
1100: if (isInfoEnabled()) {
1101: info(getName() + " - removing " + removedTask.getUID()
1102: + "'s direct object "
1103: + removedTask.getDirectObject() + " from mptask "
1104: + mpTask.getUID() + "'s direct object");
1105: }
1106:
1107: Vector newSet = new Vector();
1108: newSet.addAll(assetsInGroup);
1109: if (!newSet.remove(removedTask.getDirectObject())) {
1110: error(getName() + " removed task " + removedTask.getUID()
1111: + "'s d.o. " + removedTask.getDirectObject()
1112: + " is not part of mp task d.o. for mp task "
1113: + mpTask.getUID());
1114: }
1115:
1116: AssetGroup newAssetGroup = assetHelper.makeAssetGroup(
1117: getLDMService().getLDM().getFactory(), newSet);
1118:
1119: ((NewMPTask) mpTask).setDirectObject(newAssetGroup);
1120:
1121: publishChange(mpTask);
1122:
1123: return newAssetGroup;
1124: }
1125:
1126: /**
1127: * post-condition check : MPTask d.o. should be the sum of all parents' d.o.s
1128: * no more, no less
1129: */
1130: protected void checkMPTaskDO(MPTask mpTask) {
1131: Vector mpTaskDOVector = ((AssetGroup) mpTask.getDirectObject())
1132: .getAssets();
1133:
1134: Set parentDirectObjects = new HashSet();
1135:
1136: int numParents = 0;
1137: for (Enumeration en = mpTask.getParentTasks(); en
1138: .hasMoreElements();) {
1139: Task parent = (Task) en.nextElement();
1140: parentDirectObjects.add(parent.getDirectObject());
1141: numParents++;
1142: }
1143:
1144: info(getName() + " - MPTask " + mpTask.getUID() + " has "
1145: + numParents + " parents.");
1146:
1147: Set parentsNotRepresentedInMPTask = new HashSet(
1148: parentDirectObjects);
1149: parentsNotRepresentedInMPTask.removeAll(mpTaskDOVector);
1150: if (!parentsNotRepresentedInMPTask.isEmpty()) {
1151: for (Iterator iter = parentsNotRepresentedInMPTask
1152: .iterator(); iter.hasNext();) {
1153: info(getName() + " - MPTask " + mpTask.getUID()
1154: + " d.o. is missing parent's d.o. "
1155: + iter.next());
1156: }
1157: }
1158:
1159: if (false) { // this has excessive false positives
1160: Set excessAssetsInMPTaskDO = new HashSet(mpTaskDOVector);
1161: excessAssetsInMPTaskDO.removeAll(parentDirectObjects);
1162: if (!excessAssetsInMPTaskDO.isEmpty()) {
1163: for (Iterator iter = excessAssetsInMPTaskDO.iterator(); iter
1164: .hasNext();) {
1165: info(getName()
1166: + " - MPTask "
1167: + mpTask.getUID()
1168: + " d.o. has extra asset that is not in any parent "
1169: + iter.next());
1170: }
1171: }
1172: }
1173: }
1174:
1175: /**
1176: * very expensive - must examine every object on the blackboard - avoid if possible
1177: *
1178: * @param parentUID - uid of MPTask we want from the blackboard
1179: * @return MPTask with UID equal to the param parentUID
1180: */
1181: protected MPTask getMPTask(final UID parentUID) {
1182: Collection stuff = blackboard.query(new UnaryPredicate() {
1183: public boolean execute(Object obj) {
1184: boolean isMPTask = (obj instanceof MPTask);
1185: if (!isMPTask)
1186: return false;
1187: boolean match = ((MPTask) obj).getUID().toString()
1188: .equals(parentUID.toString());
1189: return match;
1190: }
1191: });
1192:
1193: if (stuff.iterator().hasNext())
1194: return (MPTask) stuff.iterator().next(); // better be only one!
1195: else
1196: return null;
1197: }
1198:
1199: protected Vector enumToVector(Enumeration en) {
1200: Vector vector = new Vector(13);
1201: for (; en.hasMoreElements();) {
1202: vector.add(en.nextElement());
1203: }
1204: return vector;
1205: }
1206:
1207: protected Enumeration getEnumWithNewParents(Vector oldParents,
1208: Vector tasklist) {
1209: oldParents.addAll(tasklist);
1210: return oldParents.elements();
1211: }
1212:
1213: /**
1214: * make and publish aggregations for parentTasks
1215: */
1216: protected void addAggregations(NewComposition comp,
1217: Vector parentTasks, Date start, Date end) {
1218: Map avMap = getAspectValuesMap(parentTasks, start, end);
1219: // create aggregations for each parent task
1220: for (Iterator i = parentTasks.iterator(); i.hasNext();) {
1221: Task parentTask = (Task) i.next();
1222: AspectValue[] aspectValues = (AspectValue[]) avMap
1223: .get(parentTask);
1224:
1225: boolean isSuccess = !allocHelper.exceedsPreferences(
1226: parentTask, aspectValues);
1227:
1228: if (!isSuccess) {
1229: if (isWarnEnabled()) {
1230: warn("VishnuAggregatorPlugin.addAggregations - making failed aggregation for "
1231: + parentTask);
1232: }
1233: expandHelper.showPlanElement(parentTask);
1234: }
1235:
1236: AllocationResult estAR = ldmf.newAllocationResult(
1237: allocHelper.HIGHEST_CONFIDENCE, isSuccess,
1238: aspectValues);
1239: Aggregation agg = ldmf.createAggregation(parentTask
1240: .getPlan(), parentTask, comp, estAR);
1241: if (isDebugEnabled())
1242: debug("VishnuAggregatorPlugin.makeAggregation - Making aggregation for task "
1243: + parentTask.getUID() + " agg " + agg.getUID());
1244: publishAddWithCheck(agg);
1245: comp.addAggregation(agg);
1246: }
1247: }
1248:
1249: /**
1250: * hook for post-publish processing <br>
1251: * Default does nothing. <br>
1252: * might want to do : Task mpTask = findMPTask (aggResults);
1253: */
1254: protected void cleanupAggregation(Asset a, List tasklist,
1255: List aggResults) {
1256: // Task mpTask = findMPTask (aggResults);
1257: }
1258:
1259: /**
1260: * Find MPTask in list returned from UTILAggregate.makeAggregation
1261: *
1262: * @see org.cougaar.lib.util.UTILAggregate#makeAggregation
1263: */
1264: protected MPTask findMPTask(List results) {
1265: Iterator i = results.iterator();
1266: while (i.hasNext()) {
1267: Object next = i.next();
1268: if (next instanceof MPTask)
1269: return ((MPTask) next);
1270: }
1271: throw new UTILPluginException(
1272: myClusterName
1273: + " couldn't find MPTask in list of Aggregation products");
1274: }
1275:
1276: /**
1277: * Defines the verb of the MPTask
1278: * Transport by default
1279: *
1280: * @return Verb - Transport
1281: */
1282: protected Verb getVerbForAgg(List g) {
1283: return Verb.get("Transport");
1284: }
1285:
1286: /**
1287: * Aggregates direct objects of parent tasks into a vector
1288: *
1289: * @return aggregate of parent direct objects
1290: */
1291: protected Vector getDirectObjectsForAgg(List parentTasks) {
1292: Vector assets = new Vector();
1293:
1294: Iterator pt_i = parentTasks.iterator();
1295: // prepPhrases and directObjects
1296: while (pt_i.hasNext()) {
1297: Task currentTask = (Task) pt_i.next();
1298: assets.addElement(currentTask.getDirectObject());
1299: }
1300:
1301: return assets;
1302: }
1303:
1304: /**
1305: * Adjust preferences so that the start time preference is the assigned
1306: * start time, and the end time preference has a best date that is the
1307: * assigned end time. The early and late dates of the end time preference
1308: * are the same as the first parent task. (This isn't very important, as the
1309: * downstream allocator should just allocate to the start and best times.) <p>
1310: *
1311: * If there is a quantity preference on the first task, will calculate an aggregate <br>
1312: * quantity preference. Assumes then that all tasks will have a quantity pref.
1313: * @param a - the asset associated with the MPTask
1314: * @param g - parent task list
1315: * @param start - the date for the START_TIME preference
1316: * @param end - the best date for the END_TIME preference
1317: * @return Vector - list of preferences for the MPTask
1318: */
1319: protected Vector getPreferencesForAgg(Asset a, List g, Date start,
1320: Date end) {
1321: Task firstParentTask = (Task) g.get(0);
1322:
1323: Date earlyDate = start.after(prefHelper
1324: .getEarlyDate(firstParentTask)) ? start : prefHelper
1325: .getEarlyDate(firstParentTask);
1326:
1327: Vector prefs;
1328:
1329: synchronized (firstParentTask) { // bug #2124
1330: prefs = allocHelper.enumToVector(firstParentTask
1331: .getPreferences());
1332: }
1333: ;
1334:
1335: prefs = prefHelper.replacePreference(prefs, prefHelper
1336: .makeStartDatePreference(ldmf, start));
1337: prefs = prefHelper.replacePreference(prefs, prefHelper
1338: .makeEndDatePreference(ldmf, earlyDate, end, prefHelper
1339: .getLateDate(firstParentTask)));
1340: long totalQuantity = 0l;
1341: if (prefHelper.hasPrefWithAspectType(firstParentTask,
1342: AspectType.QUANTITY)) {
1343: for (Iterator iter = g.iterator(); iter.hasNext();) {
1344: try {
1345: totalQuantity += prefHelper.getQuantity((Task) iter
1346: .next());
1347: } catch (UTILRuntimeException re) {
1348: totalQuantity += 1; // the task didn't have a quantity preference
1349: }
1350: }
1351:
1352: prefs = prefHelper.replacePreference(prefs, prefHelper
1353: .makeQuantityPreference(ldmf, totalQuantity));
1354: }
1355:
1356: return prefs;
1357: }
1358:
1359: /**
1360: * Defines how to get the asset representing the task->asset association.
1361: *
1362: * Should be in sync with getPrepPhrasesForAgg, which attaches the prep.
1363: * @see #getPrepPhrasesForAgg
1364: * @param combinedTask - the MPTask generated by the plugin
1365: * @return the asset on the task
1366: */
1367: protected Asset getAssetFromMPTask(MPTask combinedTask) {
1368: return (Asset) prepHelper.getIndirectObject(combinedTask,
1369: Constants.Preposition.WITH);
1370: }
1371:
1372: /**
1373: * <pre>
1374: * Defines how the MPTask holds the asset for the task->asset association.
1375: *
1376: * Should be in sync with getAssetFromMPTask, which accesses the prep.
1377: *
1378: * Critical, because the allocator downstream will look for this prep and
1379: * pluck the asset off to make the allocation.
1380: *
1381: * </pre>
1382: * @see #getAssetFromMPTask
1383: * @param a - asset to attach to task
1384: * @param g - parent tasks
1385: * @return the original set of prep phrases from the first parent task PLUS the WITH
1386: * prep with the asset
1387: */
1388: protected Vector getPrepPhrasesForAgg(Asset a, List g) {
1389: Vector firstTaskPreps = allocHelper.enumToVector(((Task) g
1390: .get(0)).getPrepositionalPhrases());
1391: Vector preps = new Vector(firstTaskPreps);
1392:
1393: preps.addElement(prepHelper.makePrepositionalPhrase(ldmf,
1394: Constants.Preposition.WITH, a));
1395: return preps;
1396: }
1397:
1398: /**
1399: * Create aspect values so that the start time aspect is the assigned
1400: * start time, and the end time aspect is the
1401: * assigned end time.
1402: * (The downstream allocator should just echo these values.)
1403: *
1404: * Gets the preferences and makes aspect values that echo them. At this
1405: * point the start and end time preferences have been set to the assigned
1406: * times.
1407: *
1408: * @param a - the asset associated with the MPTask
1409: * @param g - parent task list
1410: * @return AspectValue[] - returned aspect values
1411: */
1412: protected AspectValue[] getAVsForAgg(Asset a, List g, Date start,
1413: Date end) {
1414: return makeAVsFromPrefs(getPreferencesForAgg(a, g, start, end));
1415: }
1416:
1417: /**
1418: * Create aspect values so that the start time aspect is the assigned
1419: * start time, and the end time aspect is the
1420: * assigned end time.
1421: * (The downstream allocator should just echo these values.)
1422: *
1423: * Gets the preferences and makes aspect values that echo them. At this
1424: * point the start and end time preferences have been set to the assigned
1425: * times.
1426: *
1427: * Does not create excess aspect value arrays.
1428: *
1429: * @param g - parent task list
1430: * @return AspectValue[] - returned aspect values
1431: */
1432: protected Map getAspectValuesMap(List g, Date start, Date end) {
1433: Map taskToAspectValue = new HashMap();
1434: AspectValue[] timeOnlyAspects = null;
1435: int i = 0;
1436: for (Iterator iter = g.iterator(); iter.hasNext();) {
1437: Task task = (Task) iter.next();
1438: Vector preferences;
1439: synchronized (task) { // synchronize on a task's preferences when you get them - bug #2124
1440: preferences = allocHelper.enumToVector(task
1441: .getPreferences());
1442: }
1443: // all the time-only preference items will share the same aspects
1444: if (preferences.size() == 2) {
1445: if (timeOnlyAspects == null)
1446: timeOnlyAspects = makeAVsFromPrefs(preferences,
1447: start, end);
1448: taskToAspectValue.put(task, timeOnlyAspects);
1449: i++;
1450: } else {
1451: taskToAspectValue.put(task, makeAVsFromPrefs(
1452: preferences, start, end));
1453: }
1454: }
1455:
1456: return taskToAspectValue;
1457: }
1458:
1459: /**
1460: * Create aspect values so that the start time aspect is the assigned
1461: * start time, and the end time aspect is the
1462: * assigned end time.
1463: * (The downstream allocator should just echo these values.)
1464: *
1465: * Takes the preferences and makes aspect values that echo them. At this
1466: * point the start and end time preferences have been set to the assigned
1467: * times.
1468: *
1469: * @param prefs - the preferences associated with the MPTask
1470: * @return AspectValue[] - returned aspect values
1471: */
1472: protected AspectValue[] makeAVsFromPrefs(Vector prefs) {
1473: Vector tmp_av_vec = new Vector(prefs.size());
1474: Iterator pref_i = prefs.iterator();
1475: while (pref_i.hasNext()) {
1476: // do something really simple for now.
1477: Preference pref = (Preference) pref_i.next();
1478: int at = pref.getAspectType();
1479:
1480: ScoringFunction sf = pref.getScoringFunction();
1481: // allocate as if you can do it at the "Best" point
1482: double result = ((AspectScorePoint) sf.getBest())
1483: .getValue();
1484:
1485: // sometimes would fail task due to rounding error
1486: // (time would appear a few millis before the START_TIME pref)
1487: if (at == AspectType.START_TIME)
1488: result += 1000.0d; // BOZO : hack -- still needed?
1489:
1490: tmp_av_vec.addElement(AspectValue
1491: .newAspectValue(at, result));
1492:
1493: //debug (getName() + ".makeAVsFromPrefs - adding type " + at + " value " + result);
1494: }
1495:
1496: AspectValue[] avs = new AspectValue[tmp_av_vec.size()];
1497: Iterator av_i = tmp_av_vec.iterator();
1498: int i = 0;
1499: while (av_i.hasNext())
1500: avs[i++] = (AspectValue) av_i.next();
1501:
1502: // if there were no preferences...return an empty vector (0 elements)
1503: return avs;
1504: }
1505:
1506: /** replace start and end time aspect values with those from the assignment */
1507: protected AspectValue[] makeAVsFromPrefs(Vector prefs, Date start,
1508: Date end) {
1509: Vector tmp_av_vec = new Vector(prefs.size());
1510: Iterator pref_i = prefs.iterator();
1511: while (pref_i.hasNext()) {
1512: // do something really simple for now.
1513: Preference pref = (Preference) pref_i.next();
1514: int at = pref.getAspectType();
1515: double result = 0;
1516:
1517: if (at == AspectType.START_TIME) {
1518: result = (double) start.getTime();
1519: } else if (at == AspectType.END_TIME) {
1520: result = (double) end.getTime();
1521: } else {
1522: ScoringFunction sf = pref.getScoringFunction();
1523: // allocate as if you can do it at the "Best" point
1524: result = ((AspectScorePoint) sf.getBest()).getValue();
1525: }
1526: tmp_av_vec.addElement(AspectValue
1527: .newAspectValue(at, result));
1528: }
1529:
1530: AspectValue[] avs = new AspectValue[tmp_av_vec.size()];
1531: Iterator av_i = tmp_av_vec.iterator();
1532: int i = 0;
1533: while (av_i.hasNext())
1534: avs[i++] = (AspectValue) av_i.next();
1535:
1536: // if there were no preferences...return an empty vector (0 elements)
1537: return avs;
1538: }
1539:
1540: /**
1541: * publish the generated plan elements, compositions, and tasks
1542: *
1543: * Also informs of failed tasks.
1544: *
1545: * @param toPublish stuff to publish
1546: */
1547: protected void publishList(List toPublish) {
1548: Iterator i = toPublish.iterator();
1549: while (i.hasNext()) {
1550: Object next_o = i.next();
1551: if (next_o instanceof Task) {
1552: Task taskToPublish = (Task) next_o;
1553: PlanElement pe = taskToPublish.getPlanElement();
1554: if (pe != null && !pe.getEstimatedResult().isSuccess()
1555: && isDebugEnabled()) {
1556: debug(getName() + ".publishList - Task "
1557: + taskToPublish.getUID() + " failed : ");
1558: expandHelper.showPlanElement(taskToPublish);
1559: }
1560: } else if (next_o instanceof Composition) {
1561: ((NewComposition) next_o)
1562: .setIsPropagating(propagateRescindPastAggregation);
1563: }
1564:
1565: publishAddWithCheck(next_o);
1566: }
1567: }
1568: }
|