001: /*
002: * <copyright>
003: *
004: * Copyright 2003-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: package org.cougaar.lib.vishnu.client;
027:
028: import org.cougaar.lib.param.ParamMap;
029: import com.bbn.vishnu.scheduling.Assignment;
030: import com.bbn.vishnu.scheduling.MultitaskAssignment;
031: import com.bbn.vishnu.scheduling.Resource;
032: import com.bbn.vishnu.scheduling.Scheduler;
033: import com.bbn.vishnu.scheduling.SchedulingData;
034: import com.bbn.vishnu.scheduling.TimeOps;
035: import org.cougaar.util.StringKey;
036: import org.cougaar.util.MutableTimeSpan;
037: import org.cougaar.util.TimeSpan;
038: import org.cougaar.util.TimeSpanSet;
039: import org.cougaar.util.NonOverlappingTimeSpanSet;
040: import org.cougaar.util.log.Logger;
041:
042: import org.cougaar.planning.ldm.plan.Task;
043: import org.cougaar.planning.ldm.asset.Asset;
044:
045: import org.w3c.dom.Document;
046:
047: import java.util.ArrayList;
048: import java.util.Date;
049: import java.util.Iterator;
050: import java.util.HashMap;
051: import java.util.HashSet;
052: import java.util.List;
053: import java.util.Map;
054: import java.util.Set;
055: import java.util.Vector;
056:
057: /**
058: * <pre>
059: * For Direct mode. Handles results returned directly from scheduler.
060: *
061: * Creates an internal instance of the scheduler and talks to it, instead
062: * of to a web server. Uses direct translation of Cougaar to Vishnu objects,
063: * and reads the assignments directly. <b>No XML involved.</b>
064: *
065: * Needs the plugin to be a DirectResultListener. Mainly this means implementing
066: * the prepareVishnuObjects method.
067: * </pre>
068: * @see DirectResultListener#prepareVishnuObjects
069: */
070: public class DirectResultHandler extends PluginHelper implements
071: ResultHandler {
072:
073: /**
074: * For every assignment, remember the start time + resource id, which uniquely identifies each assignment
075: * This way we can tell if the resource has been used before
076: */
077: Set knownTimeResourceIDPairs = new HashSet();
078:
079: /** records reference to ResultListener parent */
080: public DirectResultHandler(ModeListener parent, VishnuComm comm,
081: XMLProcessor xmlProcessor, VishnuDomUtil domUtil,
082: VishnuConfig config, ParamMap myParamTable, Logger logger) {
083: super (parent, comm, xmlProcessor, domUtil, config,
084: myParamTable, logger);
085: resultListener = (ResultListener) parent;
086: localSetup();
087: }
088:
089: /** sets parameter : debugParseAnswer */
090: protected void localSetup() {
091: super .localSetup();
092:
093: try {
094: debugParseAnswer = getMyParams().getBooleanParam(
095: "debugParseAnswer");
096: } catch (Exception e) {
097: debugParseAnswer = false;
098: }
099:
100: try {
101: if (getMyParams().hasParam("writeXMLToFile"))
102: writeXMLToFile = getMyParams().getBooleanParam(
103: "writeXMLToFile");
104: else
105: writeXMLToFile = false;
106: } catch (Exception e) {
107: }
108: }
109:
110: /**
111: * <pre>
112: * Directly handle assignments.
113: *
114: * If the assignment is a one-to-one assignment, call parseAssignment directly.
115: * parseAssignment will call the resultHandler's handleAssignment. This typically
116: * results in an allocation or expansion.
117: *
118: * Otherwise if it's a multi-task assignment, calls handleMultiAssignment. This
119: * typically results in an aggregation set and an MPTask.
120: *
121: * Asks the scheduler for which assignment is being done.
122: * Asks the scheduler data for the list of tasks and resources.
123: * Uses the time ops object to convert Vishnu time into ALP time.
124: *
125: * WARNING WARNING WARNING WARNING WARNING WARNING
126: *
127: * The multitask flag must be set to grouped if using a VishnuAggregator.
128: * If not, things won't work properly here.
129: *
130: * WARNING WARNING WARNING WARNING WARNING WARNING
131: *
132: * </pre>
133: * @see com.bbn.vishnu.scheduling.Scheduler#assignmentsMultitask
134: * @see com.bbn.vishnu.scheduling.SchedulingData#getTasks
135: * @see com.bbn.vishnu.scheduling.SchedulingData#getResources
136: * @see ResultListener#handleAssignment
137: * @see ResultListener#handleMultiAssignment
138: **/
139: Map resourcesToTimeSpanSet = new HashMap();
140:
141: public void directlyHandleAssignments(Scheduler sched,
142: SchedulingData data, TimeOps timeOps) {
143: Date start = new Date();
144:
145: // This shows how to extract the assignments after scheduling.
146: // When sched.assignmentsMultitask() is true, the assignments
147: // will actually be MultitaskAssignment objects instead.
148: StringBuffer buffer = new StringBuffer();
149: if (!sched.assignmentsMultitask()) {
150: com.bbn.vishnu.scheduling.Task[] tasks = data.getTasks();
151:
152: for (int i = 0; i < tasks.length; i++) {
153: boolean hasChanged = (!tasks[i].isFrozen() || data
154: .changedSinceCheckpoint(tasks[i]));
155: if (!hasChanged)
156: continue;
157:
158: if (logger.isDebugEnabled()) {
159: logger.debug("Task " + tasks[i].getKey()
160: + " frozen " + tasks[i].isFrozen()
161: + " changed "
162: + data.changedSinceCheckpoint(tasks[i]));
163: }
164:
165: Assignment assign = tasks[i].getAssignment();
166:
167: if (logger.isDebugEnabled())
168: logger.debug("Assign was " + assign);
169:
170: if (assign != null) {
171: com.bbn.vishnu.scheduling.Task task = assign
172: .getTask();
173: Resource resource = assign.getResource();
174:
175: if (writeXMLToFile) {
176: String assignXML = assign.toString(); // must repair since doesn't include task text
177: assignXML = assignXML.replaceFirst("text=\"\"",
178: "text=\""
179: + sched.getSpecs().taskText(
180: task) + "\"");
181: buffer.append(assignXML);
182: }
183:
184: parseAssignment(
185: task.getKey(),
186: resource.getKey(),
187: timeOps.timeToDate(assign
188: .getTaskStartTime()),
189: timeOps.timeToDate(assign.getTaskEndTime()),
190: timeOps.timeToDate(assign.getStartTime()), // setup
191: timeOps.timeToDate(assign.getEndTime()), // wrapup
192: assign.getContribString(), sched.getSpecs()
193: .taskText(task));
194:
195: /*
196: TimeSpanSet timeSpanSet;
197: if ((timeSpanSet = (TimeSpanSet) resourcesToTimeSpanSet.get(resource)) == null) {
198: timeSpanSet = new NonOverlappingTimeSpanSet ();
199: resourcesToTimeSpanSet.put (resource, timeSpanSet);
200: }
201:
202: MutableTimeSpan timeSpan = new MutableTimeSpan ();
203: timeSpan.setTimeSpan (
204: timeOps.timeToDate (assign.getTaskStartTime()).getTime(),
205: timeOps.timeToDate (assign.getTaskEndTime()).getTime());
206: try {
207: timeSpanSet.add (timeSpan);
208: System.out.println ("Adding task " + task.getKey() + " to resource " + resource.getKey() + " " +
209: timeOps.timeToDate (assign.getTaskStartTime()) + "-" +
210: timeOps.timeToDate (assign.getTaskEndTime()) + " Performance ");
211: } catch (IllegalArgumentException iae) {
212: logger.error (getName () + ".directlyHandleAssignments - overlapping time spans for resource " +
213: resource.getKey() + "\n\tTime spans were\n" + timeSpanSet +
214: "\n\tAnd overlapping new one was\n" +
215: new Date(timeSpan.getStartTime()) + "-" + new Date(timeSpan.getEndTime()));
216: }
217:
218: timeSpan = new MutableTimeSpan ();
219: try {
220: timeSpan.setTimeSpan (
221: timeOps.timeToDate (assign.getStartTime()).getTime(), // setup
222: timeOps.timeToDate (assign.getTaskStartTime()).getTime());
223: System.out.println ("Adding task " + task.getKey() + " to resource " + resource.getKey() + " " +
224: timeOps.timeToDate (assign.getStartTime()) + "-" +
225: timeOps.timeToDate (assign.getTaskStartTime()) + " setup ");
226: } catch (Exception e) {}
227: try {
228: timeSpanSet.add (timeSpan);
229: } catch (IllegalArgumentException iae) {
230: logger.error (getName () + ".directlyHandleAssignments - overlapping time spans for resource " +
231: resource.getKey() + "\n\tTime spans were\n" + timeSpanSet +
232: "\n\tAnd overlapping new one was\n" +
233: new Date(timeSpan.getStartTime()) + "-" + new Date(timeSpan.getEndTime()));
234: }
235:
236: timeSpan = new MutableTimeSpan ();
237: try {
238: timeSpan.setTimeSpan (
239: timeOps.timeToDate (assign.getTaskEndTime()).getTime(),
240: timeOps.timeToDate (assign.getEndTime()).getTime()); // wrapup
241: System.out.println ("Adding task " + task.getKey() + " to resource " + resource.getKey() + " " +
242: timeOps.timeToDate (assign.getTaskEndTime()) + "-" +
243: timeOps.timeToDate (assign.getEndTime()) + " wrapup ");
244: } catch (Exception e) {}
245: try {
246: timeSpanSet.add (timeSpan);
247: } catch (IllegalArgumentException iae) {
248: logger.error (getName () + ".directlyHandleAssignments - overlapping time spans for resource " +
249: resource.getKey() + "\n\tTime spans were\n" + timeSpanSet +
250: "\n\tAnd overlapping new one was\n" +
251: new Date(timeSpan.getStartTime()) + "-" + new Date(timeSpan.getEndTime()));
252: }
253:
254: int j=0;
255: System.out.println ("resource " + resource.getKey()+ " role schedule now:");
256:
257: for (Iterator iter = timeSpanSet.iterator(); iter.hasNext(); ) {
258: TimeSpan ts = (TimeSpan) iter.next();
259: System.out.println ("#" + (j++) + " " + new Date(ts.getStartTime()) + "-" + new Date(ts.getEndTime()));
260: }
261: */
262: } else
263: logger
264: .debug(getName()
265: + ".directlyHandleAssignments - no assignment for task "
266: + tasks[i].getKey() + "?");
267: }
268: } else {
269: Resource[] resources = data.getResources();
270:
271: if (logger.isDebugEnabled())
272: logger.debug(getName() + " scanning "
273: + resources.length + " resources.");
274:
275: for (int i = 0; i < resources.length; i++) {
276: MultitaskAssignment[] multi = resources[i]
277: .getMultitaskAssignments();
278: if (multi.length == 0) {
279: if (logger.isDebugEnabled())
280: logger
281: .debug(getName() + " huh? "
282: + resources[i]
283: + " had no assignments?");
284: }
285: if (multi.length > 0) {
286: if (logger.isInfoEnabled())
287: logger.info(getName() + " for resource "
288: + resources[i].getKey() + " got "
289: + multi.length
290: + " task groups assigned.");
291:
292: for (int j = 0; j < multi.length; j++) {
293: boolean assetWasUsedBefore = false;
294: Vector tasks = new Vector();
295: MultitaskAssignment assign = multi[j];
296:
297: if (logger.isInfoEnabled()) {
298: logger.info(getName()
299: + " for resource "
300: + resources[i].getKey()
301: + " multi assign #"
302: + j
303: + " had "
304: + multi[j].getTasks().size()
305: + " tasks, start time was "
306: + timeOps.timeToDate(assign
307: .getTaskStartTime())
308: + " end "
309: + timeOps.timeToDate(assign
310: .getTaskEndTime()));
311: }
312:
313: String resourceKey = assign.getResource()
314: .getKey();
315: boolean printedMsg = false;
316: for (Iterator iter = multi[j].getTasks()
317: .iterator(); iter.hasNext();) {
318: com.bbn.vishnu.scheduling.Task vishnuTask = (com.bbn.vishnu.scheduling.Task) iter
319: .next();
320:
321: boolean hasChanged = (!vishnuTask
322: .isFrozen() || data
323: .changedSinceCheckpoint(vishnuTask));
324: if (!hasChanged)
325: continue;
326:
327: Task task = getTaskFromAssignment(vishnuTask
328: .getKey());
329: if (task != null) {
330: tasks.add(task);
331: } else { // if this is a task from an earlier batch, then this resource was used before
332: if (logger.isInfoEnabled()
333: && !printedMsg) {
334: logger
335: .info(getName()
336: + " - asset "
337: + resourceKey
338: + " was used before at "
339: + timeOps
340: .timeToDate(assign
341: .getTaskStartTime()));
342: printedMsg = true;
343: }
344:
345: assetWasUsedBefore = true;
346: }
347: }
348:
349: if (!tasks.isEmpty()) {
350: resultListener.handleMultiAssignment(tasks,
351: getAssignedAsset(resourceKey),
352: timeOps.timeToDate(assign
353: .getTaskStartTime()),
354: timeOps.timeToDate(assign
355: .getTaskEndTime()), timeOps
356: .timeToDate(assign
357: .getStartTime()), // setup
358: timeOps.timeToDate(assign
359: .getEndTime()),// wrapup
360: assetWasUsedBefore);
361:
362: /*
363: TimeSpanSet timeSpanSet;
364: if ((timeSpanSet = (TimeSpanSet) resourcesToTimeSpanSet.get(assign.getResource())) == null) {
365: timeSpanSet = new NonOverlappingTimeSpanSet ();
366: resourcesToTimeSpanSet.put (assign.getResource(), timeSpanSet);
367: }
368:
369: MutableTimeSpan timeSpan = new MutableTimeSpan ();
370: timeSpan.setTimeSpan (
371: timeOps.timeToDate (assign.getTaskStartTime()).getTime(),
372: timeOps.timeToDate (assign.getTaskEndTime()).getTime());
373: try {
374: timeSpanSet.add (timeSpan);
375: } catch (IllegalArgumentException iae) {
376: logger.error (getName () + ".directlyHandleAssignments - (performance) overlapping time spans for resource " +
377: assign.getResource().getKey() +
378: "\n\tAnd overlapping new one was\n" +
379: new Date(timeSpan.getStartTime()) + "-" + new Date(timeSpan.getEndTime()));
380: int k=0;
381: logger.error ("resource " + assign.getResource().getKey()+ " role schedule now:");
382:
383: java.util.Collection overlapped = timeSpanSet.intersectingSet (timeSpan);
384:
385: for (Iterator iter = timeSpanSet.iterator(); iter.hasNext(); ) {
386: TimeSpan ts = (TimeSpan) iter.next();
387: boolean overlap = overlapped.contains(ts);
388: logger.error ("#" + (k++) + " " + new Date(ts.getStartTime()) + "-" + new Date(ts.getEndTime()) + (overlap ? " OVERLAP!" : ""));
389: }
390: }
391:
392: timeSpan = new MutableTimeSpan ();
393: try {
394: timeSpan.setTimeSpan (
395: timeOps.timeToDate (assign.getStartTime()).getTime(), // setup
396: timeOps.timeToDate (assign.getTaskStartTime()).getTime());
397: } catch (Exception e) {}
398: try {
399: timeSpanSet.add (timeSpan);
400: } catch (IllegalArgumentException iae) {
401: logger.error (getName () + ".directlyHandleAssignments - (setup) overlapping time spans for resource " +
402: assign.getResource().getKey() +
403: "\n\tAnd overlapping new one was\n" +
404: new Date(timeSpan.getStartTime()) + "-" + new Date(timeSpan.getEndTime()));
405: int k=0;
406: logger.error ("resource " + assign.getResource().getKey()+ " role schedule now:");
407:
408: java.util.Collection overlapped = timeSpanSet.intersectingSet (timeSpan);
409:
410: for (Iterator iter = timeSpanSet.iterator(); iter.hasNext(); ) {
411: TimeSpan ts = (TimeSpan) iter.next();
412: boolean overlap = overlapped.contains(ts);
413: logger.error ("#" + (k++) + " " + new Date(ts.getStartTime()) + "-" + new Date(ts.getEndTime()) + (overlap ? " OVERLAP!" : ""));
414: }
415: }
416:
417: timeSpan = new MutableTimeSpan ();
418: try {
419: timeSpan.setTimeSpan (
420: timeOps.timeToDate (assign.getTaskEndTime()).getTime(),
421: timeOps.timeToDate (assign.getEndTime()).getTime()); // wrapup
422: } catch (Exception e) {}
423: try {
424: timeSpanSet.add (timeSpan);
425: } catch (IllegalArgumentException iae) {
426: logger.error (getName () + ".directlyHandleAssignments - (wrapup) overlapping time spans for resource " +
427: assign.getResource().getKey() +
428: "\n\tAnd overlapping new one was\n" +
429: new Date(timeSpan.getStartTime()) + "-" + new Date(timeSpan.getEndTime()) + "\n\tTime spans were\n");
430: int k=0;
431: logger.error ("resource " + assign.getResource().getKey()+ " role schedule now:");
432:
433: java.util.Collection overlapped = timeSpanSet.intersectingSet (timeSpan);
434:
435: for (Iterator iter = timeSpanSet.iterator(); iter.hasNext(); ) {
436: TimeSpan ts = (TimeSpan) iter.next();
437: boolean overlap = overlapped.contains(ts);
438: logger.error ("#" + (k++) + " " + new Date(ts.getStartTime()) + "-" + new Date(ts.getEndTime()) + (overlap ? " OVERLAP!" : ""));
439: }
440: }
441: */
442: /*
443: int j=0;
444: System.out.println ("resource " + resource.getKey()+ " role schedule now:");
445:
446: for (Iterator iter = timeSpanSet.iterator(); iter.hasNext(); ) {
447: TimeSpan ts = (TimeSpan) iter.next();
448: System.out.println ("#" + (j++) + " " + new Date(ts.getStartTime()) + "-" + new Date(ts.getEndTime()));
449: }
450: */
451:
452: }
453: }
454: }
455: }
456: }
457:
458: if (writeXMLToFile)
459: comm.writeBufferToFile("assignment", buffer.toString());
460:
461: if (showTiming)
462: domUtil
463: .reportTime(
464: ".directlyHandleAssignments - parsed assignments in ",
465: start);
466: }
467:
468: /**
469: * Called by directlyHandleAssignment when the scheduler is finished for each assignment <p>
470: *
471: * Calls resultHandler's handleAssignment after calling getTaskFromAssignment and getAssignedAsset
472: *
473: * @see #directlyHandleAssignments
474: * @see #getTaskFromAssignment
475: * @see #getAssignedAsset
476: * @see VishnuPlugin#handleAssignment
477: * @see VishnuAggregatorPlugin#handleAssignment
478: * @see VishnuAllocatorPlugin#handleAssignment
479: */
480: protected void parseAssignment(String task, String resource,
481: Date assignedStart, Date assignedEnd, Date assignedSetup,
482: Date assignedWrapup, String contribs, String taskText) {
483: if (debugParseAnswer)
484: logger.debug("Assignment: " + "\ntask = " + task
485: + "\nresource = " + resource + "\nsetup = "
486: + assignedSetup + "\nstart = " + assignedStart
487: + "\nend = " + assignedEnd + "\nwrapup = "
488: + assignedWrapup + "\ncontribs = " + contribs
489: + "\ntask-text = " + taskText);
490:
491: Task handledTask = getTaskFromAssignment(task);
492: Asset assignedAsset = getAssignedAsset(resource);
493:
494: if (handledTask != null) {
495: resultListener.handleAssignment(handledTask, assignedAsset,
496: assignedStart, assignedEnd, assignedSetup,
497: assignedWrapup, contribs, taskText);
498: } else
499: logger.warn(getName()
500: + ".parseAssignment - handledTask was null?");
501: }
502:
503: /**
504: * Asks resultListener for task corresponding to key <tt>task</tt>.<p>
505: *
506: * Removes the task from the the list of known tasks kept in the plugin
507: *
508: * @see VishnuPlugin#removeTask
509: * @param task key returned from assignment xml
510: * @return equivalent ALP task
511: */
512: protected Task getTaskFromAssignment(String task) {
513: StringKey taskKey = new StringKey(task);
514: Task handledTask = resultListener.getTaskForKey(taskKey);
515: if (handledTask == null) {
516: if (logger.isDebugEnabled())
517: logger
518: .debug(getName()
519: + ".getTaskFromAssignment - NOTE - no ALP task found for task key "
520: + taskKey);
521: return null;
522: } else {
523: resultListener.removeTask(taskKey);
524: }
525:
526: return handledTask;
527: }
528:
529: /**
530: * Asks resultListener for asset corresponding to key <tt>resource</tt>
531: *
532: * @param resource key returned from assignment xml
533: * @return equivalent ALP asset
534: */
535: protected Asset getAssignedAsset(String resource) {
536: Asset assignedAsset = resultListener
537: .getAssetForKey(new StringKey(resource));
538: if (assignedAsset == null)
539: logger
540: .warn(getName()
541: + ".parseMultiAssignment - ERROR - no asset found with "
542: + resource);
543: return assignedAsset;
544: }
545:
546: protected String getName() {
547: return parent.getName() + "-DirectResultHandler";
548: }
549:
550: protected boolean debugParseAnswer = false;
551: ResultListener resultListener;
552: /** parameter -- write xml to a file */
553: protected boolean writeXMLToFile = false;
554: }
|