001: /*
002: * <copyright>
003: *
004: * Copyright 2001-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.callback.UTILAllocationCallback;
029: import org.cougaar.lib.callback.UTILFilterCallback;
030: import org.cougaar.lib.callback.UTILGenericListener;
031: import org.cougaar.lib.callback.UTILWorkflowCallback;
032: import org.cougaar.lib.filter.UTILAllocatorPlugin;
033: import org.cougaar.planning.ldm.asset.Asset;
034: import org.cougaar.planning.ldm.plan.Allocation;
035: import org.cougaar.planning.ldm.plan.AspectType;
036: import org.cougaar.planning.ldm.plan.AspectValue;
037: import org.cougaar.planning.ldm.plan.PlanElement;
038: import org.cougaar.planning.ldm.plan.Role;
039: import org.cougaar.planning.ldm.plan.Task;
040:
041: import java.util.Date;
042: import java.util.Iterator;
043: import java.util.List;
044: import java.util.Vector;
045:
046: /**
047: * Vishnu plugin that takes Vishnu assignments and creates allocations out of them
048: *
049: */
050: public class VishnuAllocatorPlugin extends VishnuPlugin implements
051: UTILAllocatorPlugin {
052: /**
053: * <pre>
054: * The idea is to add subscriptions (via the filterCallback), and when
055: * they change, to have the callback react to the change, and tell
056: * the listener (many times the plugin) what to do.
057: *
058: * Override and call super to add new filters, or override
059: * createXXXCallback to change callback behaviour.
060: *
061: * By default adds allocation callback after creating it.
062: *
063: * </pre>
064: * @see #createAllocCallback
065: */
066: public void setupFilters() {
067: super .setupFilters();
068:
069: if (isInfoEnabled())
070: info(getName() + " : Filtering for Allocations...");
071:
072: addFilter(myAllocCallback = createAllocCallback());
073: }
074:
075: /**
076: * <pre>
077: * Callback for input tasks
078: *
079: * Provide the callback that is paired with the buffering thread, which is a
080: * listener. The buffering thread is the listener to the callback
081: *
082: * Creates an instance of the WorkflowCallback, which means the plugin
083: * is looking for tasks that are part of workflows.
084: *
085: * </pre>
086: * @param bufferingThread -- the thread the callback informs when there are new input tasks
087: * @return a WorkflowCallback with the buffering thread as its listener
088: */
089: protected UTILFilterCallback createThreadCallback(
090: UTILGenericListener bufferingThread) {
091: if (isInfoEnabled())
092: info(getName() + " Filtering for tasks with Workflows...");
093:
094: myWorkflowCallback = new UTILWorkflowCallback(bufferingThread,
095: logger);
096: return myWorkflowCallback;
097: }
098:
099: protected UTILFilterCallback getWorkflowCallback() {
100: return myWorkflowCallback;
101: }
102:
103: protected UTILAllocationCallback getAllocCallback() {
104: return myAllocCallback;
105: }
106:
107: /**
108: * Override to replace with a callback that has a different predicate
109: * or different behaviour when triggered.
110: */
111: protected UTILAllocationCallback createAllocCallback() {
112: return new UTILAllocationCallback(this , logger);
113: }
114:
115: /**
116: * Implemented for UTILBufferingPlugin <p>
117: *
118: * Got an ill-formed task, now handle it, by <br>
119: * publishing a failed plan allocation for the task.
120: * @param t badly-formed task to handle
121: */
122: public void handleIllFormedTask(Task t) {
123: reportIllFormedTask(t);
124: Object obj = allocHelper.makeFailedDisposition(null, ldmf, t);
125: publishAddWithCheck(obj);
126: }
127:
128: /**
129: * Implemented for UTILAllocationListener <p>
130: *
131: * OVERRIDE to specify task notifications (i.e. changed
132: * (allocations) the plugin is interested in. <p>
133: *
134: * Just calls interestingTask by default, which is generally
135: * what you want.
136: *
137: * @param t task to check for notification
138: * @return boolean true if task is interesting
139: */
140: public boolean interestingNotification(Task t) {
141: return interestingTask(t);
142: }
143:
144: /**
145: * <pre>
146: * Implemented for UTILAllocationListener
147: *
148: * Defines conditions for rescinding tasks.
149: *
150: * Only return true if the plugin can do something different
151: * with the task that failed. See allocHelper.isFailedPE.
152: *
153: * When returns TRUE, handleRescindedAlloc is called.
154: *
155: * If in making an allocation, a preference
156: * threshold is exceeded, the returned plan element will be
157: * a Disposition (see UTILAllocate.makeAllocation ()).
158: *
159: * Called by UTILAllocationCallback.reactToChangedAlloc.
160: *
161: * </pre>
162: * @param alloc the allocation to check
163: * @return boolean true if the allocation needs to be rescinded
164: * Also returns false if there is no reported alloc result
165: * attached to allocation
166: * @see #handleRescindedAlloc
167: * @see org.cougaar.lib.callback.UTILAllocationCallback#reactToChangedAlloc
168: * @see org.cougaar.lib.util.UTILAllocate#makeAllocation
169: * @see org.cougaar.lib.util.UTILAllocate#isFailedPE
170: */
171: public boolean needToRescind(Allocation alloc) {
172: return false;
173: }
174:
175: /**
176: * <pre>
177: * Implemented for UTILAllocationListener
178: *
179: * Public version of publishRemove
180: *
181: * Called by UTILAllocationCallback.reactToChangedAlloc.
182: *
183: * </pre>
184: * @param alloc Allocation to remove from cluster's logPlan
185: * @see org.cougaar.lib.callback.UTILAllocationCallback#reactToChangedAlloc
186: */
187: public void publishRemovalOfAllocation(Allocation alloc) {
188: publishRemove(alloc);
189: }
190:
191: /**
192: * <pre>
193: * Implemented for UTILAllocationListener
194: *
195: * Defines re-allocation of a rescinded task.
196: * Overriders need to take into consideration that
197: * the asset chosen last time is not available this time.
198: *
199: * Note that updateAllocationResult is called automatically by
200: * the UTILAllocationCallback if the allocation has changed
201: * (typically if its allocation result has changed)
202: * but it does NOT need to be rescinded.
203: *
204: * Called by UTILAllocationCallback.reactToChangedAlloc.
205: *
206: * Only called when needToRescind returns TRUE.
207: * See comment on needToRescind.
208: *
209: * Does nothing by default.
210: *
211: * </pre>
212: * @param alloc the allocation that should be rescinded
213: * @return false since doesn't rescind the allocation
214: * @see org.cougaar.lib.filter.UTILPluginAdapter#updateAllocationResult
215: * @see org.cougaar.lib.callback.UTILAllocationListener#updateAllocationResult
216: * @see org.cougaar.lib.callback.UTILAllocationCallback#reactToChangedAlloc
217: * @see #needToRescind
218: */
219: public boolean handleRescindedAlloc(Allocation alloc) {
220: return false;
221: }
222:
223: /**
224: * <pre>
225: * Implemented for UTILAllocationListener
226: *
227: * Called automatically by the UTILAllocationCallback
228: * if the allocation has changed but it does NOT need
229: * to be rescinded.
230: * updateAllocationResult is called first and then this method
231: * gets called.
232: *
233: * Called by UTILAllocationCallback.reactToChangedAlloc.
234: *
235: * Only called when needToRescind returns FALSE.
236: * See comment on needToRescind.
237: *
238: * Does nothing by default.
239: *
240: * </pre>
241: * @param alloc the allocation that was successful
242: * @see org.cougaar.lib.filter.UTILPluginAdapter#updateAllocationResult
243: * @see org.cougaar.lib.callback.UTILAllocationListener#updateAllocationResult
244: * @see org.cougaar.lib.callback.UTILAllocationCallback#reactToChangedAlloc
245: * @see #needToRescind
246: */
247: public void handleSuccessfulAlloc(Allocation alloc) {
248: }
249:
250: /**
251: * <pre>
252: * Called when an allocation is removed from the cluster.
253: * I.e. an upstream cluster removed an allocation, and that
254: * rescind has resulted in this allocation being removed.
255: *
256: * If the plugin maintains some local state of the availability
257: * of assets, it should update them here.
258: *
259: * This is different from the needToRescind-handleRescindedAlloc pair
260: * which are used when the plugin gets a result that it wants to
261: * replan. If needToRescind returns true, a downstream
262: * cluster will see handleRemovedAlloc get called.
263: *
264: * Calls VishnuPlugin.handleRemovedTasks. If in incremental mode,
265: * the SchedulerLifecycle Mode will tell the scheduler to forget about
266: * the removed task.
267: * </pre>
268: * @param alloc that was removed from the blackboard
269: * @see org.cougaar.lib.vishnu.client.VishnuPlugin#handleRemovedTasks
270: * @see org.cougaar.lib.vishnu.client.InternalMode#handleRemovedTasks
271: * @see org.cougaar.lib.vishnu.client.ExternalMode#handleRemovedTasks
272: */
273: public void handleRemovedAlloc(Allocation alloc) {
274: if (isDebugEnabled()) {
275: String owner = "?";
276: try {
277: owner = alloc.getTask().getDirectObject().getUID()
278: .getOwner();
279: } catch (Exception e) {
280: }
281:
282: debug(getName() + ".handleRemovedAlloc called for task "
283: + alloc.getTask().getUID() + " from unit " + owner);
284: }
285:
286: Vector removedTasks = new Vector();
287: removedTasks.add(alloc.getTask());
288:
289: handleRemovedTasks(removedTasks.elements());
290: }
291:
292: /**
293: * Makes allocations given the task to asset assignment. <p>
294: *
295: * If the task has a setup or wrapup duration, and expansion is made and <br>
296: * then the subtasks get allocated with the setup and wrapup durations. <p>
297: *
298: * Calls <code>createAllocation</code> to create the allocation of
299: * task to asset, and <code>makeSetupAndWrapupTasks</code> to create the
300: * optional setup and wrapup tasks. <code>createAllocation</code>is called
301: * using <code>getConfidence</code> and <code>getRole</code>.
302: *
303: * @see #createAllocation
304: * @see #makeSetupAndWrapupTasks
305: * @param task task being assigned to asset
306: * @param asset asset handling the task
307: * @param start start of the main task
308: * @param end end of the main task
309: * @param setupStart start of a setup task, equal to start if there is no setup task
310: * @param wrapupEnd end of a wrapup task, equal to end if there is no wrapup task
311: **/
312: public void handleAssignment(
313: org.cougaar.planning.ldm.plan.Task task, Asset asset,
314: Date start, Date end, Date setupStart, Date wrapupEnd,
315: String contribs, String taskText) {
316: if (isDebugEnabled())
317: debug("got here with " + task + " and asset " + asset
318: + " with contribs " + contribs + " and taskText "
319: + taskText);
320:
321: if (isDebugEnabled())
322: debug("VishnuAllocatorPlugin.makePlanElement : "
323: + " assigning " + task.getUID() + "\nto "
324: + asset.getUID() + " from " + start + " to " + end);
325:
326: double quantity = -1;
327: try {
328: quantity = Double.parseDouble(contribs);
329: } catch (Exception e) {
330: info("Could not parse <" + contribs + "> as double.");
331: }
332:
333: if (makeSetupAndWrapupTasks
334: && ((setupStart.getTime() < start.getTime()) || (wrapupEnd
335: .getTime() > end.getTime()))) {
336: List subtasks = makeSetupWrapupExpansion(task, asset,
337: start, end, setupStart, wrapupEnd);
338:
339: for (Iterator iter = subtasks.iterator(); iter.hasNext();) {
340: Task subtask = (Task) iter.next();
341:
342: createAllocation(subtask, asset, prefHelper
343: .getReadyAt(subtask), prefHelper
344: .getBestDate(subtask), getConfidence(asset),
345: getRole(), quantity);
346: }
347: } else {
348: createAllocation(task, asset, start, end,
349: getConfidence(asset), getRole(), quantity);
350: }
351: }
352:
353: /**
354: * <pre>
355: * By default, sets highest confidence on allocation. <br>
356: * This is usually only appropriate for allocation to Physical Assets. <br>
357: * If your allocator allocates to organizations, you probably want to override <br>
358: * this function and set the confidence to alloc.MEDIUM_CONFIDENCE. <p>
359: *
360: * Or you could do : <code>
361: * double confidence = ((GLMAsset) asset).hasPhysicalPG () ?
362: * alloc.HIGHEST_CONFIDENCE : alloc.MEDIUM_CONFIDENCE; </code>
363: * </pre>
364: **/
365: protected double getConfidence(Asset asset) {
366: return allocHelper.HIGHEST_CONFIDENCE;
367: }
368:
369: /**
370: * Transporter by default, override to use a different role
371: * Specifies role in the allocation plan element.
372: */
373: protected Role getRole() {
374: return Role.getRole("Transporter");
375: }
376:
377: /**
378: * Creates an allocation or dispostion if the start and end times
379: * violate the preferences.
380: *
381: * @param task task being assigned to asset
382: * @param asset asset handling the task
383: * @param start start of the task
384: * @param end end of the task
385: * @param confidence of the allocation
386: * @param role of the allocation
387: * @return Allocation or Disposition
388: */
389: protected PlanElement createAllocation(Task task, Asset asset,
390: Date start, Date end, double confidence, Role role,
391: double quantity) {
392: AspectValue[] aspects;
393:
394: if (prefHelper.hasPrefWithAspectType(task, AspectType.QUANTITY)) {
395: aspects = new AspectValue[3];
396: aspects[2] = AspectValue.newAspectValue(
397: AspectType.QUANTITY, quantity);
398: } else {
399: aspects = new AspectValue[2];
400: }
401:
402: aspects[0] = AspectValue.newAspectValue(AspectType.START_TIME,
403: start.getTime());
404: aspects[1] = AspectValue.newAspectValue(AspectType.END_TIME,
405: end.getTime());
406:
407: PlanElement allocation = allocHelper.makeAllocation(this , ldmf,
408: realityPlan, task, asset, aspects, confidence, role);
409:
410: publishAdd(allocation);
411: return allocation;
412: }
413:
414: /** callback handling/monitoring incoming tasks */
415: protected UTILWorkflowCallback myWorkflowCallback;
416: /** callback handling/monitoring outgoing allocation */
417: protected UTILAllocationCallback myAllocCallback;
418: }
|