001: /*
002: * <copyright>
003: *
004: * Copyright 1997-2004 BBNT Solutions, LLC
005: * under sponsorship of the Defense Advanced Research Projects
006: * Agency (DARPA).
007: *
008: * You can redistribute this software and/or modify it under the
009: * terms of the Cougaar Open Source License as published on the
010: * Cougaar Open Source Website (www.cougaar.org).
011: *
012: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
013: * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
014: * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
015: * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
016: * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
017: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
018: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
019: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
020: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
021: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
022: * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
023: *
024: * </copyright>
025: */
026:
027: package org.cougaar.logistics.plugin.inventory;
028:
029: import java.util.*;
030:
031: import org.cougaar.core.blackboard.IncrementalSubscription;
032: import org.cougaar.core.blackboard.CollectionSubscription;
033: import org.cougaar.planning.ldm.PlanningFactory;
034: import org.cougaar.planning.plugin.util.PluginHelper;
035: import org.cougaar.glm.ldm.asset.Inventory;
036: import org.cougaar.glm.ldm.asset.ScheduledContentPG;
037: import org.cougaar.logistics.ldm.Constants;
038: import org.cougaar.planning.ldm.plan.*;
039: import org.cougaar.util.Enumerator;
040:
041: public class DetReqAggHandler extends InventoryModule {
042:
043: /** The aggMIL task found/created during the current transaction **/
044: private Task aggMILTask = null;
045: private HashMap MILTaskHash = new HashMap();
046:
047: public DetReqAggHandler(InventoryManager imPlugin) {
048: super (imPlugin);
049: }
050:
051: public void aggregateDetermineRequirementsTasks(
052: IncrementalSubscription detReqSubscription,
053: IncrementalSubscription aggMILSubscription) {
054: aggMILTask = null;
055: if (detReqSubscription.hasChanged()) {
056: aggregateDetermineRequirementsTasks(
057: (NewMPTask) getDetermineRequirementsTask(aggMILSubscription),
058: detReqSubscription.getAddedCollection());
059: }
060: }
061:
062: public void handleMILTasks(IncrementalSubscription milSubscription) {
063: if (milSubscription.hasChanged()) {
064: //Added tasks are handled at the time of creation
065: removeMILTasks(milSubscription.getRemovedList());
066: }
067: }
068:
069: public void addMILTasks(Enumeration milTasks) {
070: while (milTasks.hasMoreElements()) {
071: Task task = (Task) milTasks.nextElement();
072: if (logger.isDebugEnabled()) {
073: logger
074: .debug("Maintain Inv task being added... inserting into hashmap "
075: + task.toString());
076: }
077: Inventory inventory = (Inventory) task.getDirectObject();
078: MILTaskHash.put(inventory, task);
079: }
080: }
081:
082: private void removeMILTasks(Enumeration milTasks) {
083: while (milTasks.hasMoreElements()) {
084: Task task = (Task) milTasks.nextElement();
085: if (logger.isDebugEnabled()) {
086: logger
087: .debug("Agent: "
088: + inventoryPlugin.getClusterId()
089: .toString()
090: + "DetReqHandler["
091: + inventoryPlugin.getSupplyType()
092: + "]"
093: + "Maintain Inv task being removed... cleaning out hashmap "
094: + task.toString());
095: }
096: Inventory inventory = (Inventory) task.getDirectObject();
097: MILTaskHash.remove(inventory);
098: }
099: }
100:
101: /**
102: Get _the_ aggregate MIL task. This is complicated because we
103: want to detect when the task has been deleted, but we only want
104: to create one of them. The lag between publishing a new task
105: and its appearance in the subscription poses a problem because,
106: typically, this method is called repeatedly in one transaction.
107: We store the task temporarily in a variable (aggMILTask) to
108: prevent multiple creation, but clear the variable at the
109: beginning of each new transaction. If the task has not yet been
110: created, we try to create it by aggregating all the existing
111: per-oplan DetermineRequirements tasks into it. Subsequent
112: per-oplan tasks will be aggregated in as they arrive. There
113: will be no task if there are no DetermineRequirements tasks to
114: be aggregated.
115: **/
116: public Task getDetermineRequirementsTask(
117: CollectionSubscription aggMILSubscription) {
118: if (aggMILTask == null) {
119: if (!aggMILSubscription.isEmpty()) {
120: aggMILTask = (Task) aggMILSubscription.elements()
121: .nextElement();
122: }
123: }
124: return aggMILTask;
125: }
126:
127: /**
128: Aggregate some DetermineRequirements tasks
129: **/
130: private void aggregateDetermineRequirementsTasks(NewMPTask mpTask,
131: Collection parents) {
132: if (mpTask == null)
133: return;
134: NewComposition composition = (NewComposition) mpTask
135: .getComposition();
136: long minStartTime = 0;
137: long maxEndTime = 0;
138: Iterator parentIt = parents.iterator();
139: while (parentIt.hasNext()) {
140: try {
141: maxEndTime = getTaskUtils().getEndTime(mpTask);
142: } catch (IllegalArgumentException iae) {
143: maxEndTime = Long.MIN_VALUE;
144: }
145: try {
146: minStartTime = getTaskUtils().getStartTime(mpTask);
147: } catch (IllegalArgumentException iae) {
148: minStartTime = Long.MAX_VALUE;
149: }
150: Task parent = (Task) parentIt.next();
151: if (parent.getPlanElement() != null) {
152: logger
153: .error("Det Req for MaintainInventory already disposed: "
154: + parent);
155: }
156: minStartTime = Math.min(minStartTime, getTaskUtils()
157: .getStartTime(parent));
158: maxEndTime = Math.max(maxEndTime, getTaskUtils()
159: .getEndTime(parent));
160: AllocationResult estAR = PluginHelper
161: .createEstimatedAllocationResult(parent,
162: inventoryPlugin.getPlanningFactory(), 1.0,
163: true);
164: Aggregation agg = inventoryPlugin.getPlanningFactory()
165: .createAggregation(parent.getPlan(), parent,
166: composition, estAR);
167: composition.addAggregation(agg);
168: inventoryPlugin.publishAdd(agg);
169: }
170: setStartTimePreference(mpTask, minStartTime);
171: setEndTimePreference(mpTask, maxEndTime);
172: mpTask.setParentTasks(new Enumerator(composition
173: .getParentTasks()));
174: inventoryPlugin.publishAdd(mpTask);
175: // create an expty expansion for the mp maintain inv task to be filled
176: // in later with a MaintainInventory task for each maintained item
177: createTopMIExpansion(mpTask);
178: aggMILTask = mpTask;
179: }
180:
181: /** Create an empty expansion pe for the top level maintain inventory task
182: * that will be filled in with Maintain inventory tasks for each
183: * Maintained item.
184: * @param parent The Top maintain inventory task
185: **/
186: private void createTopMIExpansion(Task parent) {
187: PlanningFactory factory = inventoryPlugin.getPlanningFactory();
188: // Create workflow
189: NewWorkflow wf = (NewWorkflow) factory.newWorkflow();
190: wf.setParentTask(parent);
191: wf.setIsPropagatingToSubtasks(true);
192: // Build Expansion
193: AllocationResult estAR = PluginHelper
194: .createEstimatedAllocationResult(parent,
195: inventoryPlugin.getPlanningFactory(), 1.0, true);
196: Expansion expansion = factory.createExpansion(parent.getPlan(),
197: parent, wf, estAR);
198: // Publish Expansion
199: inventoryPlugin.publishAdd(expansion);
200: }
201:
202: /**
203: Create a MaintainInventory task for an inventory. This task is
204: the parent of all refill tasks for the inventory and is itself
205: a subtask of the aggregated determine requirements tasks.
206: **/
207: private NewTask createMILTask(Task parent, Inventory inventory) {
208: NewTask subtask = inventoryPlugin.getPlanningFactory()
209: .newTask();
210: subtask.setContext(parent.getContext());
211: subtask.setDirectObject(inventory);
212: subtask.setParentTask(parent);
213: subtask.setVerb(Verb.get(Constants.Verb.MAINTAININVENTORY));
214: setStartTimePreference(subtask, getTaskUtils().getStartTime(
215: parent));
216: setEndTimePreference(subtask, getTaskUtils().getEndTime(parent));
217: return subtask;
218: }
219:
220: /**
221: Create the aggregated maintain inventory task. This task is
222: the parent of all the per-inventory MaintainInventory tasks.
223: It, too, uses the MaintainInventory verb but with no direct
224: object. It is an MPTask that combines all the
225: DetermineRequirements tasks of type MaintainInventory. The
226: Composition of this MPTask is non-propagating so it is
227: rescinded only if all the parent tasks are rescinded.
228: @see InventoryPlugin#processDetReq
229: **/
230: public NewMPTask createAggTask(Collection parents) {
231: Task parentTask = null;
232: Iterator tasks = parents.iterator();
233: HashSet set = new HashSet();
234: while (tasks.hasNext()) {
235: parentTask = (Task) tasks.next();
236: if (parentTask.getContext() != null) {
237: set.addAll((ContextOfOplanIds) parentTask.getContext());
238: }
239: }
240: NewMPTask mpTask = inventoryPlugin.getPlanningFactory()
241: .newMPTask();
242: mpTask.setContext(new ContextOfOplanIds(set));
243: NewComposition composition = inventoryPlugin
244: .getPlanningFactory().newComposition();
245: composition.setIsPropagating(false);
246: mpTask.setComposition(composition);
247: composition.setCombinedTask(mpTask);
248: mpTask.setVerb(Verb.get(Constants.Verb.MAINTAININVENTORY));
249: aggregateDetermineRequirementsTasks(mpTask, parents);
250: return mpTask;
251: }
252:
253: /**
254: Find or make the aggregated MIL task for an inventory. If the
255: MILTaskHash_ does not contain an existing task, create a new
256: one and link it to the determine requirements tasks.
257: **/
258: public Task findOrMakeMILTask(Inventory inventory,
259: CollectionSubscription aggMILSubscription) {
260: // Creates the MaintainInventoryLevels Task for this item
261: // if one does not already exist
262: NewTask milTask = (NewTask) MILTaskHash.get(inventory);
263: if (milTask == null) {
264: Task parent = getDetermineRequirementsTask(aggMILSubscription);
265: if (parent == null || parent.getPlanElement() == null) {
266: /**
267: This might happen just after the last determine
268: requirements task is removed. Because of inertia,
269: the inventory manager might still be trying to
270: refill the inventory although, in fact the demand
271: for that inventory is in the process of
272: disappearing. The caller, getting a null return will
273: simply abandon the attempt to do the refill.
274: **/
275: reportWhenCantMakeMaintainInventoryTask(inventory,
276: parent);
277: return null; // Can't make one
278: }
279: milTask = createMILTask(parent, inventory);
280: PlanElement pe = parent.getPlanElement();
281: if (pe instanceof Expansion) {
282: Expansion expansion = (Expansion) pe;
283: NewWorkflow wf = (NewWorkflow) expansion.getWorkflow();
284: wf.addTask(milTask);
285: ((NewTask) milTask).setWorkflow(wf);
286: // Publish new task
287: inventoryPlugin.publishAdd(milTask);
288: MILTaskHash.put(inventory, milTask);
289: inventoryPlugin.publishChange(expansion);
290: if (logger.isDebugEnabled()) {
291: logger.debug("Created new Maintain Inv task: "
292: + milTask.getUID() + " Parent UID is: "
293: + parent.getUID());
294: }
295: } else {
296: logger
297: .error("publish Change to MIL Top Expansion: problem pe not Expansion? "
298: + pe
299: + " parent task is: "
300: + parent.getUID());
301: }
302: }
303: return milTask;
304: }
305:
306: protected void reportWhenCantMakeMaintainInventoryTask(
307: Inventory inventory, Task parent) {
308: if (logger.isWarnEnabled()) {
309: AssetUtils assetUtils = getAssetUtils();
310: if (assetUtils == null) {
311: logger.warn("asset utils is null");
312: }
313: if (inventory == null) {
314: logger.warn("inventory is null");
315: }
316: ScheduledContentPG scheduledContentPG = inventory
317: .getScheduledContentPG();
318: if (scheduledContentPG == null) {
319: logger.warn("scheduled content for " + inventory
320: + " is null");
321: }
322: PlanElement planElement = null;
323: if (parent == null) {
324: logger.warn("parent is null");
325: } else {
326: planElement = parent.getPlanElement();
327: }
328: logger
329: .warn("CANNOT CREATE MILTASK, no parent, parent pe or inventory: "
330: + assetUtils.assetDesc(scheduledContentPG
331: .getAsset())
332: + " PARENT TASK IS: "
333: + parent + " PARENT PE IS: " + planElement);
334: }
335: }
336:
337: private void setStartTimePreference(NewTask mpTask,
338: long newStartTime) {
339: ScoringFunction sf;
340: Preference pref;
341: sf = ScoringFunction.createStrictlyAtValue(AspectValue
342: .newAspectValue(AspectType.START_TIME, newStartTime));
343: pref = inventoryPlugin.getPlanningFactory().newPreference(
344: AspectType.START_TIME, sf);
345: mpTask.setPreference(pref);
346: // mpTask.setCommitmentDate(new Date(newStartTime));
347: }
348:
349: private void setEndTimePreference(NewTask mpTask, long newEndTime) {
350: ScoringFunction sf;
351: Preference pref;
352: sf = ScoringFunction.createStrictlyAtValue(AspectValue
353: .newAspectValue(AspectType.END_TIME, newEndTime));
354: pref = inventoryPlugin.getPlanningFactory().newPreference(
355: AspectType.END_TIME, sf);
356: mpTask.setPreference(pref);
357: }
358:
359: //Reset the task reference to AggMilTask if something was removed from top level MI subscription
360: public void resetAggMITask() {
361: aggMILTask = null;
362: }
363: }
|