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.HashMap;
033: import java.util.Iterator;
034: import java.util.ListIterator;
035: import java.util.Map;
036: import java.util.StringTokenizer;
037: import java.util.regex.Matcher;
038: import java.util.regex.Pattern;
039:
040: import org.cougaar.core.blackboard.IncrementalSubscription;
041: import org.cougaar.core.logging.LoggingServiceWithPrefix;
042: import org.cougaar.core.service.LoggingService;
043: import org.cougaar.glm.ldm.Constants;
044: import org.cougaar.glm.ldm.plan.AlpineAspectType;
045: import org.cougaar.planning.ldm.asset.AbstractAsset;
046: import org.cougaar.planning.ldm.asset.Asset;
047: import org.cougaar.planning.ldm.asset.TypeIdentificationPG;
048: import org.cougaar.planning.ldm.plan.Allocation;
049: import org.cougaar.planning.ldm.plan.AllocationResult;
050: import org.cougaar.planning.ldm.plan.AspectRate;
051: import org.cougaar.planning.ldm.plan.AspectType;
052: import org.cougaar.planning.ldm.plan.AspectValue;
053: import org.cougaar.planning.ldm.plan.Preference;
054: import org.cougaar.planning.ldm.plan.Role;
055: import org.cougaar.planning.ldm.plan.Schedule;
056: import org.cougaar.planning.ldm.plan.ScheduleElement;
057: import org.cougaar.planning.ldm.plan.ScheduleElementImpl;
058: import org.cougaar.planning.ldm.plan.ScheduleImpl;
059: import org.cougaar.planning.ldm.plan.ScoringFunction;
060: import org.cougaar.planning.ldm.plan.Task;
061: import org.cougaar.planning.ldm.plan.Verb;
062: import org.cougaar.planning.plugin.legacy.SimplePlugin;
063: import org.cougaar.planning.plugin.util.AllocationResultHelper;
064: import org.cougaar.util.TimeSpan;
065: import org.cougaar.util.UnaryPredicate;
066:
067: // Simple plugin that says 'yes' to any task fed to it
068: // Optionally, if arguments are given, will only allocate tasks with given verbs
069: public class UniversalAllocatorPlugin extends SimplePlugin {
070: private static class Filter {
071: public Verb verb;
072: public Pattern regex;
073: public Schedule schedule; // The schedule of failing periods (if any)
074:
075: public String toString() {
076: if (schedule == null)
077: return verb.toString();
078: StringBuffer buf = new StringBuffer();
079: buf.append(verb);
080: for (ListIterator i = schedule.listIterator(); i.hasNext();) {
081: ScheduleElement el = (ScheduleElement) i.next();
082: buf.append(';');
083: if (el.getStartTime() > TimeSpan.MIN_VALUE) {
084: buf.append(el.getStartDate());
085: }
086: buf.append("..");
087: if (el.getEndTime() < TimeSpan.MAX_VALUE) {
088: buf.append(el.getEndDate());
089: }
090: }
091: return buf.toString();
092: }
093:
094: public boolean mayFail() {
095: return schedule != null && !schedule.isEmpty();
096: }
097: }
098:
099: private IncrementalSubscription allTasks;
100: private UnaryPredicate allTasksPredicate = new UnaryPredicate() {
101: public boolean execute(Object o) {
102: if (o instanceof Task) {
103: if (verbMap.isEmpty())
104: return true;
105: if (verbMap.get(((Task) o).getVerb()) != null) {
106: return true;
107: }
108: }
109: return false;
110: }
111: };
112:
113: /** Map a Verb to a Filter **/
114: private Map verbMap = new HashMap();
115:
116: private LoggingService logger;
117:
118: /**
119: * Create a single dummy asset to which to allocate all
120: * appropriate tasks
121: **/
122: private Asset sink_asset = null;
123:
124: public void setupSubscriptions() {
125: logger = (LoggingService) getDelegate().getServiceBroker()
126: .getService(this , LoggingService.class, null);
127: logger = LoggingServiceWithPrefix.add(logger,
128: getAgentIdentifier().toString() + ": ");
129: allTasks = (IncrementalSubscription) subscribe(allTasksPredicate);
130: parseParams();
131: }
132:
133: /**
134: * Parameters are of the form:
135: * [-]<verb>{;[<startdate>]..[<enddate>]}*
136: * ...optional minus, verb, and zero or more date ranges. The
137: * start or end of a date range may be omitted signifying min or
138: * max respectively. The initial minus signifies that the default
139: * is to fail the allocations. The date ranges specify exceptions
140: * to the default. So, for example:
141: * Supply;9/7/2005..10/3/2005
142: * would fail in the time period from September 7, 2005 to October
143: * 3, 2005.
144: **/
145: private void parseParams() {
146: StringBuffer assetName = new StringBuffer();
147:
148: assetName.append("UniversalSink");
149: for (Enumeration e = getParameters().elements(); e
150: .hasMoreElements();) {
151: String param = (String) e.nextElement();
152: Filter filter = new Filter();
153: ScheduleElement el;
154: Schedule schedule = new ScheduleImpl();
155: boolean defaultIsFailure = param.startsWith("-");
156: if (defaultIsFailure)
157: param = param.substring(1);
158: StringTokenizer tokens = new StringTokenizer(param, ";");
159: String verbPattern = tokens.nextToken();
160: int slashPos = verbPattern.indexOf('/');
161: if (slashPos >= 0) {
162: filter.verb = Verb.get(verbPattern.substring(0,
163: slashPos));
164: filter.regex = Pattern.compile(verbPattern
165: .substring(slashPos + 1));
166: } else {
167: filter.verb = Verb.get(verbPattern);
168: filter.regex = null;
169: }
170: while (tokens.hasMoreTokens()) {
171: String token = tokens.nextToken();
172: String sub;
173: int dotdot = token.indexOf("..");
174: long from = TimeSpan.MIN_VALUE;
175: long to = TimeSpan.MAX_VALUE;
176: if (dotdot < 0) {
177: from = Date.parse(token);
178: } else {
179: sub = token.substring(0, dotdot);
180: if (sub.length() > 0) {
181: from = Date.parse(sub);
182: }
183: sub = token.substring(dotdot + 2);
184: if (sub.length() > 0) {
185: to = Date.parse(sub);
186: }
187: }
188: el = new ScheduleElementImpl(from, to);
189: schedule.add(el);
190: }
191: if (defaultIsFailure) {
192: /* We built a schedule of exceptions to failure (a
193: success schedule). It must be converted to a
194: failure schedule. */
195: long startTime = TimeSpan.MIN_VALUE;
196: filter.schedule = new ScheduleImpl();
197: for (ListIterator i = schedule.listIterator(); i
198: .hasNext();) {
199: ScheduleElement el2 = (ScheduleElement) i.next();
200: el = new ScheduleElementImpl(startTime, el2
201: .getStartTime());
202: filter.schedule.add(el);
203: startTime = el2.getEndTime();
204: }
205: el = new ScheduleElementImpl(startTime,
206: TimeSpan.MAX_VALUE);
207: filter.schedule.add(el);
208: } else {
209: /* We build a schedule of exceptions to success (a
210: failure schedule) and that is exactly what we need */
211: filter.schedule = schedule;
212: }
213: verbMap.put(filter.verb, filter);
214: // System.out.println("UniversalAllocatorPlugin adding " + filter);
215: assetName.append('_');
216: assetName.append(filter.verb);
217: }
218:
219: final String aName = assetName.substring(0);
220:
221: // See if an AbstractAsset with the appropriate TypeID already exists if rehydrating
222: if (didRehydrate()) {
223: Collection sinks = query(new UnaryPredicate() {
224: public boolean execute(Object o) {
225: if (o instanceof AbstractAsset) {
226: Asset a = (Asset) o;
227: // Must be a prototype with appropriate name
228: // the assetName is the TypeId and the classname of the Asset is AbstractAsset
229: TypeIdentificationPG tip = a
230: .getTypeIdentificationPG();
231: if (tip != null
232: && aName.equals(tip
233: .getTypeIdentification()))
234: return true;
235: }
236: return false;
237: }
238: });
239: if (sinks != null && !sinks.isEmpty()) {
240: Iterator iter = sinks.iterator();
241: if (iter.hasNext())
242: sink_asset = (Asset) iter.next();
243: }
244: } // end didRehydrate test
245:
246: if (sink_asset == null) {
247: if (logger.isDebugEnabled())
248: logger.debug(getAgentIdentifier()
249: + " creating new AbAsset " + aName);
250: sink_asset = theLDMF
251: .createPrototype("AbstractAsset", aName);
252: publishAdd(sink_asset);
253: } else {
254: if (logger.isDebugEnabled())
255: logger.debug(getAgentIdentifier()
256: + " found old AbAsset " + aName);
257: }
258: }
259:
260: /**
261: * Is this a task we're interested in? Either we didn't specify a
262: * verb, or the task has a verb among those specified
263: **/
264: private boolean isInterestingTask(Task task) {
265: if (verbMap.size() == 0)
266: return true;
267: Filter filter = (Filter) verbMap.get(task.getVerb());
268: if (filter == null)
269: return false;
270: if (filter.regex == null)
271: return true;
272: String input = task.toString();
273: Matcher m = filter.regex.matcher(input);
274: if (m.matches()) {
275: // System.out.println("Match " + input);
276: return true;
277: } else {
278: // System.out.println("No match " + input);
279: return false;
280: }
281: }
282:
283: public void execute() {
284: // System.out.println("In UniversalAllocatorPlugin.execute");
285:
286: addTasks(allTasks.getAddedList());
287: changeTasks(allTasks.getChangedList());
288: removeTasks(allTasks.getRemovedList());
289: }
290:
291: private void addTasks(Enumeration e) {
292: while (e.hasMoreElements()) {
293: Task task = (Task) e.nextElement();
294:
295: if (!isInterestingTask(task))
296: continue;
297: print(" add", task);
298: AllocationResult ar = computeAllocationResult(task);
299:
300: // Allocate task to sink_asset
301: Allocation allocation = theLDMF
302: .createAllocation(theLDMF.getRealityPlan(), task,
303: sink_asset, ar, Role.BOGUS);
304: publishAdd(allocation);
305: }
306: }
307:
308: private void changeTasks(Enumeration e) {
309: // NEEDS TO BE FIXED!!
310: // all task changes are not necessarily allocationresult changes
311: // allocation result updates should be done as a result of a subscription
312: // for this plugins planelements!!!!
313: while (e.hasMoreElements()) {
314: Task task = (Task) e.nextElement();
315:
316: if (!isInterestingTask(task))
317: continue;
318:
319: print("change", task);
320: AllocationResult ar = computeAllocationResult(task);
321: Allocation allocation = (Allocation) task.getPlanElement();
322: if (allocation != null) {
323: AllocationResult estAR = allocation
324: .getEstimatedResult();
325: if (estAR != null) {
326: if (!ar.isEqual(estAR)) {
327: allocation.setEstimatedResult(ar);
328: publishChange(allocation);
329: }
330: }
331: }
332: }
333: }
334:
335: private void removeTasks(Enumeration e) {
336: while (e.hasMoreElements()) {
337: Task task = (Task) e.nextElement();
338:
339: if (!isInterestingTask(task))
340: continue;
341:
342: print("remove", task);
343: }
344: }
345:
346: private void print(String m, Task task) {
347: // System.out.println("UA " + m + ": " + (TaskUtils.isProjection(task) ? TaskUtils.projectionDesc(task) : TaskUtils.taskDesc(task)));
348: }
349:
350: /**
351: * Compute an allocation result for this task. We use an
352: * AllocationResultHelper to do most of the work. Our job is to
353: * enumerate the schedule failure time periods and ask the helper
354: * to indicate a failure (zero value) for the applicable part of
355: * those failure time intervals.
356: **/
357: private AllocationResult computeAllocationResult(Task task) {
358: Verb verb = task.getVerb();
359: Filter filter = (Filter) verbMap.get(verb);
360: AllocationResultHelper helper = new AllocationResultHelper(
361: task, null);
362: boolean isSupply = verb.equals(Constants.Verb.SUPPLY);
363: boolean isProjectSupply = verb
364: .equals(Constants.Verb.PROJECTSUPPLY);
365: if (filter != null && filter.schedule != null) { // There are some failure time periods
366: for (ListIterator i = filter.schedule.listIterator(); i
367: .hasNext();) {
368: ScheduleElement el = (ScheduleElement) i.next();
369: if (isSupply) {
370: helper.setFailed(AspectType.QUANTITY, el
371: .getStartTime(), el.getEndTime());
372: continue;
373: }
374: if (isProjectSupply) {
375: helper.setFailed(AlpineAspectType.DEMANDRATE, el
376: .getStartTime(), el.getEndTime());
377: continue;
378: }
379: // Don't know how to fail anything else.
380: }
381: }
382: // if (false) { // This code delivers everything a day early
383: // if (isSupply && !helper.isChanged()) {
384: // long endTime = helper.getPhase(0).getEndTime() - TimeUtils.MSEC_PER_DAY;
385: // AspectValue av = new TimeAspectValue(AspectType.END_TIME, endTime);
386: // helper.setAspect(av);
387: // }
388: // }
389: AllocationResult ret = helper.getAllocationResult(1.0);
390: if (ret.isSuccess() || filter.mayFail())
391: return ret;
392: if (logger.isWarnEnabled()) {
393: AspectValue[] avs = ret.getAspectValueResults();
394: boolean found = false;
395: for (int i = 0; i < avs.length; i++) {
396: AspectValue av = avs[i];
397: int aspectType = av.getAspectType();
398: Preference pref = task.getPreference(aspectType);
399: ScoringFunction sf = pref.getScoringFunction();
400: double this Score = sf.getScore(av);
401: AspectValue best = pref.getScoringFunction().getBest()
402: .getAspectValue();
403: if (this Score >= ScoringFunction.HIGH_THRESHOLD) {
404: String avRateClass = null;
405: String bestRateClass = null;
406: if (best instanceof AspectRate) {
407: ((AspectRate) best).getRateValue().getClass()
408: .getName();
409: }
410: if (av instanceof AspectRate) {
411: ((AspectRate) av).getRateValue().getClass()
412: .getName();
413: }
414: logger
415: .warn("Unexpected failure in computeAllocationResult:"
416: + " task="
417: + task
418: + " AspectType="
419: + aspectType
420: + " AspectValue="
421: + av
422: + " scoringFunction="
423: + sf
424: + " best="
425: + best
426: + " score="
427: + this Score
428: + " avRateClass="
429: + avRateClass
430: + " bestRateClass="
431: + bestRateClass);
432: found = true;
433: }
434: }
435: if (!found) {
436: logger
437: .warn("Failure in computeAllocationResult with not apparent reason");
438: }
439: }
440: return helper.getAllocationResult(1.0, true);
441: }
442: }
|