001: /*
002: * <copyright>
003: *
004: * Copyright 1997-2004 BBNT Solutions, LLC
005: * under sponsorship of the Defense Advanced Research Projects
006: * Agency (DARPA).
007: *
008: * You can redistribute this software and/or modify it under the
009: * terms of the Cougaar Open Source License as published on the
010: * Cougaar Open Source Website (www.cougaar.org).
011: *
012: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
013: * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
014: * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
015: * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
016: * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
017: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
018: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
019: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
020: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
021: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
022: * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
023: *
024: * </copyright>
025: */
026:
027: package org.cougaar.mlm.plugin.sample;
028:
029: import java.util.Collection;
030: import java.util.Date;
031: import java.util.Enumeration;
032: import java.util.Vector;
033:
034: import org.cougaar.core.blackboard.IncrementalSubscription;
035: import org.cougaar.glm.ldm.Constants;
036: import org.cougaar.glm.ldm.asset.CargoVehicle;
037: import org.cougaar.glm.ldm.policy.ShipPolicy;
038: import org.cougaar.planning.ldm.asset.Asset;
039: import org.cougaar.planning.ldm.plan.Allocation;
040: import org.cougaar.planning.ldm.plan.AllocationResult;
041: import org.cougaar.planning.ldm.plan.AspectType;
042: import org.cougaar.planning.ldm.plan.AuxiliaryQueryType;
043: import org.cougaar.planning.ldm.plan.Disposition;
044: import org.cougaar.planning.ldm.plan.MPTask;
045: import org.cougaar.planning.ldm.plan.PlanElement;
046: import org.cougaar.planning.ldm.plan.Preference;
047: import org.cougaar.planning.ldm.plan.RoleSchedule;
048: import org.cougaar.planning.ldm.plan.Task;
049: import org.cougaar.planning.plugin.legacy.SimplePlugin;
050: import org.cougaar.util.UnaryPredicate;
051:
052: public class MCCAllocatorPlugin extends SimplePlugin {
053:
054: // Convenience Class for handling of pairs of Assets/AllocationResults
055: static class AssetTuple {
056: private Asset myAsset;
057: private AllocationResult myAR;
058:
059: public AssetTuple(Asset asset, AllocationResult ar) {
060: this .myAsset = asset;
061: this .myAR = ar;
062: }
063:
064: public Asset getAsset() {
065: return myAsset;
066: }
067:
068: public AllocationResult getAllocationResult() {
069: return myAR;
070: }
071: }
072:
073: private IncrementalSubscription transportAssets;
074: private IncrementalSubscription policies;
075: private IncrementalSubscription myTasks;
076:
077: private Vector waitingTasks = new Vector();
078:
079: private static long ONE_DAY = 86400000L;
080:
081: // Predicate for our transportation Assets (ships, HETS, and the like)...
082: private static UnaryPredicate assetPred() {
083: return new UnaryPredicate() {
084: public boolean execute(Object o) {
085: return (o instanceof CargoVehicle);
086: }
087: };
088: }
089:
090: // Predicate for this Cluster's Policies
091: private static UnaryPredicate policyPred() {
092: return new UnaryPredicate() {
093: public boolean execute(Object o) {
094: return (o instanceof ShipPolicy);
095: }
096: };
097: }
098:
099: // Predicate for _ALL_ TRANSPORTMISSION Tasks
100: private static UnaryPredicate taskPred() {
101: return new UnaryPredicate() {
102: public boolean execute(Object o) {
103: if (o instanceof Task) {
104: Task t = (Task) o;
105: if (t.getVerb().equals(
106: Constants.Verb.TRANSPORTATIONMISSION))
107: return true;
108: }
109: return false;
110: }
111: };
112: }
113:
114: /**
115: * Set up the initial subscriptions of the Plugin;
116: * Currently interested in allocatable Workflows of
117: * Transport Tasks.
118: */
119: public void setupSubscriptions() {
120:
121: // Setup Subscription for Cluster transport Assets
122: transportAssets = (IncrementalSubscription) subscribe(assetPred());
123:
124: // Setup Subscription for Cluster's Policies
125: policies = (IncrementalSubscription) subscribe(policyPred());
126:
127: // Setup Subscription for Tasks to be allocated
128: myTasks = (IncrementalSubscription) subscribe(taskPred());
129:
130: }
131:
132: /**
133: * Called when there are changes to our subscriptions
134: */
135: public void execute() {
136: try {
137: // New Cluster Assets available
138: if (transportAssets.hasChanged()) {
139: Enumeration newassets = transportAssets.getAddedList();
140: checkNewAssets(newassets);
141: }
142:
143: // We have to be kind of careful here; We're maintaining a Container
144: // of _ALL_ Tasks (not just the expandable kind). We have to check to
145: // make sure that the _NEW_ Tasks are actually expandable (BTW, we actually
146: // pass over this step and go straight to Allocation here; we can only do this
147: // because we are replacing a pass-through Expander - how's that for
148: // deterministic?) - they should be, but one can never tell...
149: if (myTasks.hasChanged()) {
150: Enumeration newTasks = myTasks.getAddedList();
151: while (newTasks.hasMoreElements()) {
152: MPTask newTask = (MPTask) newTasks.nextElement();
153: //if (( newTask.getWorkflow() == null ) &&
154: // ( newTask.getPlanElement() == null ))
155: allocate(newTask);
156: }
157: Enumeration changedTasks = myTasks.getChangedList();
158: while (changedTasks.hasMoreElements()) {
159: MPTask changedTask = (MPTask) changedTasks
160: .nextElement();
161: allocate(changedTask);
162: }
163: }
164:
165: } catch (RuntimeException pe) {
166: pe.printStackTrace();
167: }
168: }
169:
170: private void checkNewAssets(Enumeration newassets) {
171: //while ( newassets.hasMoreElements() ) {
172: //CargoVehicle cv = (CargoVehicle)newassets.nextElement();
173: // check to see if we have any unallocated Tasks lying about...
174: if (!(waitingTasks.isEmpty())) {
175: Vector newv = new Vector();
176: Vector tmp = waitingTasks;
177: waitingTasks = newv;
178: Enumeration e = tmp.elements();
179: while (e.hasMoreElements()) {
180: MPTask t = (MPTask) e.nextElement();
181: // No, no, no...need to be a bit more discerning here;
182: // Want to employ some scheduling here to match wf with cv,
183: // albeit some rather stupid scheduling...
184: AssetTuple at = chooseAsset(newassets, t);
185: createTheAllocation(t, at);
186: }
187: }
188: }
189:
190: private void createTheAllocation(MPTask t, AssetTuple at) {
191: // make the allocation
192: if (at != null) {
193: if (at.getAllocationResult().isSuccess()) {
194: Allocation alloc = theLDMF.createAllocation(theLDMF
195: .getRealityPlan(), t, at.getAsset(), at
196: .getAllocationResult(),
197: Constants.Role.TRANSPORTER);
198: /*
199: System.err.println( "\nAllocation succeeded: " + t + "\n" + alloc );
200: */
201: publishAdd(alloc);
202: } else {
203: // check for auxquery requests
204: boolean reqfailreason = false;
205: int[] aqr = t.getAuxiliaryQueryTypes();
206: for (int q = 0; q < aqr.length; q++) {
207: int checktype = aqr[q];
208: if (checktype == AuxiliaryQueryType.FAILURE_REASON) {
209: reqfailreason = true;
210: }
211: }
212: if (reqfailreason) {
213: // set a failure reason on the allocation result
214: at.getAllocationResult().addAuxiliaryQueryInfo(
215: AuxiliaryQueryType.FAILURE_REASON,
216: "No HETs available");
217: }
218: PlanElement falloc = theLDMF.createFailedDisposition(
219: theLDMF.getRealityPlan(), t, at
220: .getAllocationResult());
221: /*
222: System.err.println( "\nAllocation failed: " + t + "\n" + falloc );
223: if (reqfailreason) {
224: System.err.println("FAILURE REASON: " + falloc.getEstimatedResult().auxiliaryQuery(AuxiliaryQueryType.FAILURE_REASON) );
225: }
226: */
227: publishAdd(falloc);
228: }
229: } else
230: throw new RuntimeException("No Assets to Allocate Against.");
231: }
232:
233: // If the Task already has an Allocation (PE) associated with it, we don't
234: // want to create a new Allocation, just modify the old one and mark it as
235: // changed.
236: private void alterTheAllocation(MPTask t, AssetTuple at) {
237: if (at != null) {
238: PlanElement pe = t.getPlanElement();
239: if (pe instanceof Allocation) {
240: // want to _alter_ original Allocation and mark as changed;
241: Allocation alloc = (Allocation) t.getPlanElement();
242: alloc.setEstimatedResult(at.getAllocationResult());
243: publishChange(alloc);
244: } else if (pe instanceof Disposition) {
245: if (!((Disposition) pe).isSuccess()) {
246: publishRemove(pe);
247: createTheAllocation(t, at);
248: }
249: }
250: } else
251: throw new RuntimeException("No Assets to Allocate Against.");
252: }
253:
254: private void allocate(MPTask task) {
255: Collection assets = transportAssets.getCollection();
256: if (assets.size() != 0) {
257: // find a transport organization asset
258: Enumeration thetransassets = new org.cougaar.util.Enumerator(
259: assets);
260: // Find an available mode of transport...
261: AssetTuple at = chooseAsset(thetransassets, task);
262: if (task.getPlanElement() == null)
263: createTheAllocation(task, at);
264: else
265: alterTheAllocation(task, at);
266: } else {
267: // if you don't have a transport organization asset - wait for one
268: waitingTasks.addElement(task);
269: }
270: }
271:
272: private AllocationResult createEstimatedAllocationResult(
273: boolean is_good, Date start, Date end) {
274: // Only interested in START_TIME, END_TIME for now
275:
276: // allocate as if you can do it at the "Best" point
277: // Going to have to make this more interesting soon...
278: AllocationResult myestimate = null;
279: if (is_good) {
280: int[] aspectarray = new int[2];
281: double[] resultsarray = new double[2];
282: aspectarray[0] = AspectType.START_TIME;
283: aspectarray[1] = AspectType.END_TIME;
284:
285: resultsarray[0] = (double) start.getTime();
286: resultsarray[1] = (double) end.getTime();
287:
288: myestimate = theLDMF.newAllocationResult(1.0, is_good,
289: aspectarray, resultsarray);
290: } else
291: myestimate = theLDMF.newAllocationResult(1.0, is_good,
292: new int[1], new double[1]);
293: return myestimate;
294: }
295:
296: /**
297: * Choose the best Asset for the job (in a rather simple way)
298: */
299: private AssetTuple chooseAsset(Enumeration assets, MPTask t) {
300: // Insert scheduler here...
301: // For now, however, just look for first one.
302: if (assets.hasMoreElements()) {
303: // Get Policy (only expecting one in the Cluster)
304: Enumeration myPolicies = policies.elements();
305: ShipPolicy sp = null;
306: if (myPolicies != null) {
307: if (myPolicies.hasMoreElements())
308: sp = (ShipPolicy) myPolicies.nextElement();
309: }
310: Asset myAsset = null;
311: AllocationResult myAR = null;
312: Date start = null;
313: Date end = null;
314: Enumeration preferences = t.getPreferences();
315: if (preferences != null && preferences.hasMoreElements()) {
316: // Get start/end times
317: while (preferences.hasMoreElements()) {
318: Preference pref = (Preference) preferences
319: .nextElement();
320: int at = pref.getAspectType();
321: if (at == AspectType.START_TIME)
322: start = new Date(pref.getScoringFunction()
323: .getBest().getAspectValue().longValue());
324: if (at == AspectType.END_TIME)
325: end = new Date(pref.getScoringFunction()
326: .getBest().getAspectValue().longValue());
327: }
328: }
329: int policy_value = 1;
330: if (sp != null)
331: policy_value = sp.getShipDays();
332: if ((start != null) && (end != null)) {
333: while (assets.hasMoreElements()) {
334: myAsset = (Asset) assets.nextElement();
335: //System.err.print( "\nTrying Asset " + myAsset + "..." );
336: myAR = ruAvailable(myAsset.getRoleSchedule(),
337: start, end, (policy_value * ONE_DAY));
338: if (myAR.isSuccess() == true) {
339: return new AssetTuple(myAsset, myAR);
340: }
341: }
342: }
343: return new AssetTuple(myAsset, myAR);
344: }
345: return null;
346: }
347:
348: private AllocationResult ruAvailable(RoleSchedule rs, Date start,
349: Date end, long rt) {
350: if (start.after(end) || start.equals(end))
351: return createEstimatedAllocationResult(false, start, end);
352: //System.err.println( "\nTrying between " + start + " and " + new Date( start.getTime() + rt ) );
353: int size = rs.getOverlappingRoleSchedule(start.getTime(),
354: start.getTime() + rt).size();
355: if (size == 0)
356: return createEstimatedAllocationResult(true, start,
357: new Date(start.getTime() + rt));
358: else {
359: return ruAvailable(rs, new Date(start.getTime() + rt), end,
360: rt);
361: }
362: }
363:
364: }
|