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.ArrayList;
030: import java.util.Arrays;
031: import java.util.Enumeration;
032: import java.util.HashMap;
033: import java.util.List;
034: import java.util.ListIterator;
035:
036: import org.cougaar.core.blackboard.IncrementalSubscription;
037: import org.cougaar.core.util.UID;
038: import org.cougaar.glm.ldm.Constants;
039: import org.cougaar.planning.ldm.PlanningFactory;
040: import org.cougaar.planning.ldm.plan.AllocationResult;
041: import org.cougaar.planning.ldm.plan.BulkEstimate;
042: import org.cougaar.planning.ldm.plan.Expansion;
043: import org.cougaar.planning.ldm.plan.NewBulkEstimate;
044: import org.cougaar.planning.ldm.plan.NewTask;
045: import org.cougaar.planning.ldm.plan.NewWorkflow;
046: import org.cougaar.planning.ldm.plan.Preference;
047: import org.cougaar.planning.ldm.plan.Task;
048: import org.cougaar.planning.plugin.legacy.SimplePlugin;
049: import org.cougaar.util.Enumerator;
050: import org.cougaar.util.UnaryPredicate;
051:
052: /** Plugin that subscribes to all BulkEstimate objects. For each BulkEstimate
053: * the Plugin unpacks the object to get the task and the collection of preference
054: * sets. The plugin creates a root task with a verb of BulkEstimate and an expansion
055: * in which the subtask is the BE task with one of the preference sets attached.
056: * When the subtask gets published, a "real" plugin will dispose it and the results
057: * will flow back up to our Expansion PlanElement. When the allocation result reaches
058: * the specified confidence rating, the result information will be stored and the
059: * root task will be rescinded (along with everything underneath it). If there
060: * are more preference sets in the BulkEstimate, the process will repeat until all
061: * preference sets have been used. At that point, this plugin will compile all results
062: * and place them in the BulkEstimate object, set the IsComplete flag to true and
063: * publishChange the BulkEstimate object.
064: **/
065:
066: public class ProvideEstimatesPlugin extends SimplePlugin {
067:
068: private IncrementalSubscription bulkestimates;
069: private IncrementalSubscription selfasset;
070: private List expsubs = new ArrayList();
071: private HashMap exp_be_map = new HashMap();
072:
073: protected void setupSubscriptions() {
074: // get all BulkEstimate objects
075: bulkestimates = (IncrementalSubscription) subscribe(bulkestimatespred());
076: }
077:
078: public synchronized void execute() {
079: if (bulkestimates.hasChanged()) {
080: Enumeration e = bulkestimates.getAddedList();
081: while (e.hasMoreElements()) {
082: BulkEstimate be = (BulkEstimate) e.nextElement();
083: IncrementalSubscription toadd = provideEstimates(be, 0);
084: if (toadd != null) {
085: expsubs.add(toadd);
086: }
087: }
088: }
089: if (!expsubs.isEmpty()) {
090: ListIterator lit = expsubs.listIterator();
091: while (lit.hasNext()) {
092: IncrementalSubscription exp = (IncrementalSubscription) lit
093: .next();
094: if (exp.hasChanged()) {
095: Enumeration echange = exp.getChangedList();
096: while (echange.hasMoreElements()) {
097: Expansion changed = (Expansion) echange
098: .nextElement();
099: BEStatus thebe = checkChange(changed, lit);
100: }
101: }
102: }
103: }
104:
105: }
106:
107: // return the subscription to add to expsubs so that we don't
108: // have ConcurrentModificationException problems with the list.
109: private IncrementalSubscription provideEstimates(BulkEstimate be,
110: int prefsetnumber) {
111: //System.err.println("provideEstimates being called for preference set: " + prefsetnumber);
112: PlanningFactory factory = getFactory();
113: // unpack the BulkEstimate
114: Task thetask = be.getTask();
115: List preferencesets = be.getPreferenceSets();
116: Preference[] pset = (Preference[]) preferencesets
117: .get(prefsetnumber);
118: List plist = Arrays.asList(pset);
119: Enumerator penum = new Enumerator(plist);
120: // make a new copy of the task to send.
121: NewTask copytask = factory.newTask();
122: copytask.setPrepositionalPhrases(thetask
123: .getPrepositionalPhrases());
124: copytask.setVerb(thetask.getVerb());
125: copytask.setDirectObject(thetask.getDirectObject());
126: copytask.setPlan(thetask.getPlan());
127: copytask.setPreferences(penum);
128:
129: // create a bogus Expansion so that we have our own planelement to monitor
130: Expansion newexp = createExpansion(copytask);
131: // create a unary predicate for this expansion
132: UnaryPredicate pred = createPredicate(newexp);
133: // create a subscription
134: IncrementalSubscription isub = (IncrementalSubscription) subscribe(pred);
135: // save expansion-bulkestimate-preferenceset index-pred-subscription information
136: BEStatus bep = new BEStatus(be, prefsetnumber, pred, isub);
137: exp_be_map.put(newexp.getUID(), bep);
138: return isub;
139: }
140:
141: private Expansion createExpansion(Task sub) {
142: PlanningFactory factory = getFactory();
143:
144: //make a bogus bulk estimate parent task
145: NewTask betask = factory.newTask();
146: betask.setVerb(Constants.Verb.BulkEstimate);
147: betask.setPlan(sub.getPlan());
148: publishAdd(betask);
149:
150: // expand the bulkestimate task
151: NewWorkflow wf = factory.newWorkflow();
152: wf.setParentTask(betask);
153: ((NewTask) sub).setParentTask(betask);
154: ((NewTask) sub).setWorkflow(wf);
155: wf.addTask(sub);
156: wf.setIsPropagatingToSubtasks(true);
157:
158: // create the actual Expansion PlanElement
159: Expansion exp = factory.createExpansion(sub.getPlan(), betask,
160: wf, null);
161:
162: // publish the expansion
163: publishAdd(exp);
164:
165: // publish the single subtask of the workflow
166: publishAdd(sub);
167:
168: return exp;
169: }
170:
171: // return the BEStatus to do things in the execute method
172: private BEStatus checkChange(Expansion exp, ListIterator lit) {
173: AllocationResult represult = exp.getReportedResult();
174: double alloccr = represult.getConfidenceRating();
175: BEStatus bes = (BEStatus) exp_be_map.get(exp.getUID());
176: if (bes != null) {
177: BulkEstimate mybe = bes.getBE();
178: double becr = mybe.getConfidenceRating();
179: // see if we have matched the confidencerating we want
180: if (becr == alloccr) {
181: // if we have then fill in the allocationresult for this pref set.
182: ((NewBulkEstimate) mybe).setSingleResult(
183: bes.getIndex(), represult);
184: // rescind the fake bulkestimate root task and everything below it
185: publishRemove(exp.getTask());
186: // remove the expansion from the exp subs list
187: lit.remove();
188: // unsubscribe to this allocation
189: unsubscribe(bes.getIncSubscription());
190: // create the next estimate
191: IncrementalSubscription wantadded = nextEstimate(bes);
192: if (wantadded != null) {
193: lit.add(wantadded);
194: }
195:
196: }
197: }
198: // if we couldn't find that status or the confidence rating wasn't met
199: // don't do anything, wait for another change with another result.
200:
201: // return the BEStatus even if its null
202: return bes;
203: }
204:
205: // return any subscriptions to add so that the add is done in execute to
206: // get rid of ConcurrentModificationExceptions with the expsub List.
207: private IncrementalSubscription nextEstimate(BEStatus astatus) {
208: // if we call provideestimates return the subscription to be added to the expsubs list
209: IncrementalSubscription add = null;
210: // get the last index and see if we have more preference sets to try
211: BulkEstimate be = astatus.getBE();
212: int lastindex = astatus.getIndex();
213: int newindex = lastindex + 1;
214: int prefsize = be.getPreferenceSets().size();
215: //System.err.println("next Estimate being called: lastindex = " + lastindex
216: //+ " newindex = " + newindex +
217: // " prefsize = " + prefsize);
218: if (newindex < prefsize) {
219: // set off another round of estimates with the next preference set
220: add = provideEstimates(be, newindex);
221: } else if (newindex == prefsize) {
222: // if the newindex is = to the pref size we might be done with this BulkEstimate
223: // check the preference set size against the allocationresult size
224: int arsize = be.getAllocationResults().length;
225: if (arsize == prefsize) {
226: // set the isComplete flag and publish the change on the BulkEstimate
227: ((NewBulkEstimate) be).setIsComplete(true);
228: publishChange(be);
229: } else {
230: System.err
231: .println("WARNING!!!! BulkEstimate final result number does not "
232: + "match the preference set number. BulkEstimate may not be able to complete estimates!!");
233: }
234: } else {
235: // if we got here there is a problem with the index
236: System.err
237: .println("WARNING!!! BulkEstimate index problem. BulkEstimate may not be able to complete estimates!!");
238: }
239: return add;
240: }
241:
242: // utility inner class to keep track of the bulk estimate and the
243: // preference set used (marked by the index)
244: class BEStatus {
245: int index;
246: BulkEstimate thebe;
247: UnaryPredicate thepred;
248: IncrementalSubscription theisub;
249:
250: public BEStatus(BulkEstimate abe, int anindex,
251: UnaryPredicate apred, IncrementalSubscription asub) {
252: thebe = abe;
253: index = anindex;
254: thepred = apred;
255: theisub = asub;
256: }
257:
258: public int getIndex() {
259: return index;
260: }
261:
262: public BulkEstimate getBE() {
263: return thebe;
264: }
265:
266: public UnaryPredicate getPredicate() {
267: return thepred;
268: }
269:
270: public IncrementalSubscription getIncSubscription() {
271: return theisub;
272: }
273: }
274:
275: // utility to create unary predicates for the expansion
276: private UnaryPredicate createPredicate(Expansion anexp) {
277: UnaryPredicate newpred = new AllocIDUnaryPredicate(anexp);
278: return newpred;
279: }
280:
281: // special unarypredicate subclass that compares expansion uids
282: private final class AllocIDUnaryPredicate implements UnaryPredicate {
283: private UID aluid;
284:
285: public AllocIDUnaryPredicate(Expansion anexp) {
286: super ();
287: aluid = anexp.getUID();
288: }
289:
290: public boolean execute(Object o) {
291: if (o instanceof Expansion) {
292: UID testid = ((Expansion) o).getUID();
293: if (testid.equals(aluid)) {
294: return true;
295: }
296: }
297: return false;
298: }
299: }
300:
301: // predicate for getting all BulkEstimate objects
302: private static UnaryPredicate bulkestimatespred() {
303: return new UnaryPredicate() {
304: public boolean execute(Object o) {
305: return (o instanceof BulkEstimate);
306: }
307: };
308: }
309:
310: }
|