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