0001: /*
0002: * <copyright>
0003: *
0004: * Copyright 1997-2004 BBNT Solutions, LLC
0005: * under sponsorship of the Defense Advanced Research Projects
0006: * Agency (DARPA).
0007: *
0008: * You can redistribute this software and/or modify it under the
0009: * terms of the Cougaar Open Source License as published on the
0010: * Cougaar Open Source Website (www.cougaar.org).
0011: *
0012: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
0013: * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
0014: * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
0015: * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
0016: * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
0017: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
0018: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
0019: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
0020: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
0021: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
0022: * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
0023: *
0024: * </copyright>
0025: */
0026:
0027: package org.cougaar.logistics.plugin.demand;
0028:
0029: import org.cougaar.core.agent.service.alarm.Alarm;
0030: import org.cougaar.core.blackboard.IncrementalSubscription;
0031: import org.cougaar.core.component.ServiceRevokedEvent;
0032: import org.cougaar.core.component.ServiceRevokedListener;
0033: import org.cougaar.core.plugin.ComponentPlugin;
0034: import org.cougaar.core.service.BlackboardService;
0035: import org.cougaar.core.service.DomainService;
0036: import org.cougaar.core.service.LoggingService;
0037: import org.cougaar.glm.ldm.asset.Organization;
0038: import org.cougaar.glm.ldm.asset.Inventory;
0039: import org.cougaar.glm.ldm.asset.ScheduledContentPG;
0040: import org.cougaar.logistics.ldm.Constants;
0041: import org.cougaar.logistics.plugin.inventory.*;
0042: import org.cougaar.logistics.plugin.utils.ScheduleUtils;
0043: import org.cougaar.planning.ldm.PlanningFactory;
0044: import org.cougaar.planning.ldm.asset.Asset;
0045: import org.cougaar.planning.ldm.plan.Task;
0046: import org.cougaar.planning.ldm.plan.Verb;
0047: import org.cougaar.util.Collectors;
0048: import org.cougaar.util.Thunk;
0049: import org.cougaar.util.UnaryPredicate;
0050:
0051: import java.lang.reflect.Constructor;
0052: import java.util.ArrayList;
0053: import java.util.Collection;
0054: import java.util.Date;
0055: import java.util.Enumeration;
0056: import java.util.HashMap;
0057: import java.util.Iterator;
0058: import java.util.List;
0059:
0060: /**
0061: * The DemandGeneratorPlugin generates demand during execution.
0062: */
0063:
0064: public class DemandGeneratorPlugin extends ComponentPlugin implements
0065: UtilsProvider {
0066: private DomainService domainService;
0067: private LoggingService logger;
0068: private TaskUtils taskUtils;
0069: private TimeUtils timeUtils;
0070: private AssetUtils AssetUtils;
0071: private ScheduleUtils scheduleUtils;
0072: private HashMap pluginParams;
0073:
0074: protected HashMap inventoryHash;
0075:
0076: private DemandTaskGeneratorIfc demandGenerator;
0077: private DGClass9Scheduler class9Scheduler;
0078: private DemandGeneratorOutputModule demandOutputModule;
0079:
0080: protected String supplyType;
0081: private long period;
0082: private long stepPeriod;
0083:
0084: public final String SUPPLY_TYPE = "SUPPLY_TYPE";
0085: public final String GENERATE_PERIOD = "GENERATE_PERIOD";
0086: public final String STEP_PERIOD = "STEP_PERIOD";
0087: public final String RANDOM_DEVIATION_ON = "RANDOM_DEVIATION_ON";
0088:
0089: public final String DEMAND_GENERATOR = "DEMAND_GENERATOR";
0090: public final String DG_TO_FILE = "DG_TO_FILE";
0091:
0092: private boolean poissonOn = true;
0093:
0094: private Organization myOrganization;
0095: private String myOrgName;
0096:
0097: //TODO: MWD Remove
0098: //private long orgStartTime=-1;
0099: //private long orgEndTime=-1;
0100:
0101: LogisticsOPlan logOPlan = null;
0102:
0103: /**
0104: * A timer for recurrent events. All access should be synchronized on timerLock *
0105: */
0106: private Alarm timer = null;
0107:
0108: /**
0109: * Lock for accessing timer *
0110: */
0111: private final Object timerLock = new Object();
0112:
0113: //TODO: remove calendar variable that old version of getStartOfPeriod() depended upon.
0114: //private Calendar calendar = new GregorianCalendar(TimeZone.getTimeZone("GMT"));
0115:
0116: public void load() {
0117: super .load();
0118: logger = getLoggingService(this );
0119: timeUtils = new TimeUtils(this );
0120: AssetUtils = new AssetUtils(this );
0121: taskUtils = new TaskUtils(this );
0122: scheduleUtils = new ScheduleUtils(this );
0123: pluginParams = readParameters();
0124:
0125: inventoryHash = new HashMap();
0126:
0127: domainService = (DomainService) getServiceBroker().getService(
0128: this , DomainService.class,
0129: new ServiceRevokedListener() {
0130: public void serviceRevoked(ServiceRevokedEvent re) {
0131: if (DomainService.class.equals(re.getService()))
0132: domainService = null;
0133: }
0134: });
0135:
0136: logger = getLoggingService(this );
0137:
0138: String dg_to_file = (String) pluginParams.get(DG_TO_FILE);
0139: if (dg_to_file != null && dg_to_file.equalsIgnoreCase("true")) {
0140: demandOutputModule = getDemandOutputModule();
0141:
0142: String demandGen = (String) pluginParams
0143: .get(DEMAND_GENERATOR);
0144: if (demandGen != null
0145: && demandGen.endsWith("DemandGeneratorInputModule")) {
0146: if (logger.isWarnEnabled()) {
0147: logger
0148: .warn("Invalid Combination of Plugin Params: Cannot output AND "
0149: + "input demand info in same run. Changing Demand "
0150: + "Generator Module to default!");
0151: }
0152: pluginParams.remove(DEMAND_GENERATOR);
0153: }
0154: }
0155:
0156: demandGenerator = getDemandTaskGeneratorModule();
0157: class9Scheduler = getClass9SchedulerModule();
0158:
0159: }
0160:
0161: private DemandGeneratorOutputModule getDemandOutputModule() {
0162: return new DemandGeneratorOutputModule(this );
0163: }
0164:
0165: public void unload() {
0166: super .unload();
0167: cancelTimer();
0168: if (domainService != null) {
0169: getServiceBroker().releaseService(this ,
0170: DomainService.class, domainService);
0171: }
0172: }
0173:
0174: /**
0175: * Subscription for the Organization(s) in which this plugin resides *
0176: */
0177: private IncrementalSubscription selfOrganizations;
0178:
0179: private IncrementalSubscription projectionTaskSubscription;
0180: private IncrementalSubscription genSupplyTaskSubscription;
0181:
0182: /**
0183: * TODO: MWD Remove
0184: * private IncrementalSubscription orgActivities;
0185: * private IncrementalSubscription oplanSubscription;
0186: */
0187: private IncrementalSubscription logisticsOPlanSubscription;
0188:
0189: public void setupSubscriptions() {
0190:
0191: selfOrganizations = (IncrementalSubscription) blackboard
0192: .subscribe(orgsPredicate);
0193: //TODO: MWD Remove
0194: //UnaryPredicate orgActivityPred = new OrgActivityPred();
0195: //orgActivities = (IncrementalSubscription) blackboard.subscribe(orgActivityPred);
0196: //oplanSubscription = (IncrementalSubscription) blackboard.subscribe(oplanPredicate);
0197: logisticsOPlanSubscription = (IncrementalSubscription) blackboard
0198: .subscribe(new LogisticsOPlanPredicate());
0199:
0200: }
0201:
0202: //Temp debugging task if Expansion turns out to be dispostion
0203: public boolean checkIfTaskOnBlackboard(Task task) {
0204: Collection tasks = blackboard
0205: .query(new TaskOnBlackboardPredicate(task));
0206: return !tasks.isEmpty();
0207: }
0208:
0209: private void checkDateOfBlackboard() {
0210: // get the start of the interval, e.g., beginning of the DAY or HOUR
0211: long currentPeriod = getStartOfPeriod(getCurrentTimeMillis());
0212: Collection supplyTasks = blackboard
0213: .query(new LocalTaskPredicate(supplyType, getOrgName(),
0214: Constants.Verb.Supply, taskUtils));
0215: if (supplyTasks.size() == 0) {
0216: return;
0217: }
0218: long lastTaskTime = findLastSupplyTaskTime(supplyTasks);
0219: long lastTaskPeriod = getStartOfPeriod(lastTaskTime);
0220:
0221: if (currentPeriod > lastTaskPeriod) {
0222: if (logger.isErrorEnabled()) {
0223: logger
0224: .error(myOrgName
0225: + supplyType
0226: + ": Rehydrated blackboard is in the past, last task time found was for : "
0227: + new Date(lastTaskTime)
0228: + " the current society time is "
0229: + new Date(getCurrentTimeMillis()));
0230: }
0231: }
0232: }
0233:
0234: /**
0235: * Debugging task to see if orphaned tasks *
0236: */
0237: private static class TaskOnBlackboardPredicate implements
0238: UnaryPredicate {
0239: private Task task;
0240:
0241: public TaskOnBlackboardPredicate(Task aTask) {
0242: super ();
0243: task = aTask;
0244: }
0245:
0246: public boolean execute(Object o) {
0247: if (o instanceof Task) {
0248: Task compareTask = (Task) o;
0249: return (task.getUID().equals(compareTask.getUID()));
0250: }
0251: return false;
0252: }
0253: }
0254:
0255: /**
0256: * Selects the LogisticsOPlan objects *
0257: */
0258: private static class LogisticsOPlanPredicate implements
0259: UnaryPredicate {
0260: public boolean execute(Object o) {
0261: return o instanceof LogisticsOPlan;
0262: }
0263: }
0264:
0265: private static class LocalTaskPredicate implements UnaryPredicate {
0266: String supplyType;
0267: String orgName;
0268: Verb verb;
0269: TaskUtils taskUtils;
0270:
0271: public LocalTaskPredicate(String type, String orgname,
0272: Verb verb, TaskUtils aTaskUtils) {
0273: supplyType = type;
0274: orgName = orgname;
0275: this .verb = verb;
0276: taskUtils = aTaskUtils;
0277: }
0278:
0279: public boolean execute(Object o) {
0280: if (o instanceof Task) {
0281: Task task = (Task) o;
0282: if (task.getVerb().equals(verb)) {
0283: if (!taskUtils.isLevel2(task)) {
0284: if (taskUtils.isDirectObjectOfType(task,
0285: supplyType)) {
0286: //if (!taskUtils.isMyInventoryProjection(task, orgName)) {
0287: if (taskUtils.isMyDemandForecastProjection(
0288: task, orgName)) {
0289: return true;
0290: }
0291: }
0292: }
0293: }
0294: }
0295: return false;
0296: }
0297:
0298: }
0299:
0300: private static UnaryPredicate orgsPredicate = new UnaryPredicate() {
0301: public boolean execute(Object o) {
0302: if (o instanceof Organization) {
0303: return ((Organization) o).isSelf();
0304: }
0305: return false;
0306: }
0307: };
0308:
0309: /**
0310: * TODO: MWD Remove
0311: * Find the earliest and latest times of all the org activites.
0312: * <p/>
0313: * private void computeOrgTimes(Enumeration orgActs) {
0314: * long latestEnd = 0;
0315: * long earliestStart = 0;
0316: * while(orgActs.hasMoreElements()) {
0317: * OrgActivity oa = (OrgActivity) orgActs.nextElement();
0318: * long endTime = oa.getEndTime();
0319: * if (endTime > latestEnd) {
0320: * latestEnd = endTime;
0321: * }
0322: * long startTime = oa.getStartTime();
0323: * if (startTime < earliestStart) {
0324: * earliestStart = startTime;
0325: * }
0326: * }
0327: * orgEndTime = latestEnd;
0328: * orgStartTime = earliestStart;
0329: * }
0330: * <p/>
0331: * public long getOrgStartTime() {
0332: * return orgStartTime;
0333: * }
0334: * <p/>
0335: * public long getOrgEndTime() {
0336: * return orgEndTime;
0337: * }
0338: * <p/>
0339: * *
0340: */
0341:
0342: public double getCapacityForTask(Task task) {
0343: Inventory inv = getInventoryForTask(task);
0344: LogisticsInventoryPG logInvPG = (LogisticsInventoryPG) inv
0345: .searchForPropertyGroup(LogisticsInventoryPG.class);
0346:
0347: double capacity = logInvPG.getCapacity();
0348:
0349: if ((capacity == 0.0) || (Double.isNaN(capacity))) {
0350: return -1.0d;
0351: }
0352:
0353: return capacity;
0354: }
0355:
0356: public Inventory getInventoryForTask(Task task) {
0357: return getInventoryForAsset((Asset) task.getDirectObject());
0358: }
0359:
0360: public Inventory getInventoryForAsset(Asset asset) {
0361: Inventory inv = null;
0362: String key = getInventoryKey(asset);
0363:
0364: inv = (Inventory) inventoryHash.get(key);
0365:
0366: if (inv == null) {
0367:
0368: Collection invs = blackboard
0369: .query(new InventoryForAssetPredicate(asset));
0370: if (invs.size() < 1) {
0371: logger.error("Couldn't find inventory matching - "
0372: + asset);
0373: return null;
0374: } else if (invs.size() > 1) {
0375: logger.error("Found more than one inventory for "
0376: + asset);
0377: }
0378:
0379: inv = ((Inventory) invs.iterator().next());
0380: inventoryHash.put(key, inv);
0381: }
0382:
0383: return inv;
0384:
0385: }
0386:
0387: private class InventoryForAssetPredicate implements UnaryPredicate {
0388: private Asset asset;
0389: private String item;
0390:
0391: public InventoryForAssetPredicate(Asset anAsset) {
0392: super ();
0393: asset = anAsset;
0394: item = getInventoryKey(anAsset);
0395: }
0396:
0397: public boolean execute(Object o) {
0398: if (o instanceof Inventory) {
0399: Inventory inv = (Inventory) o;
0400: String inventoryItem = getInventoryType(inv);
0401: if (item.equals(inventoryItem)) {
0402: return true;
0403: }
0404: }
0405: return false;
0406: }
0407:
0408: }
0409:
0410: protected String getInventoryKey(Asset anAsset) {
0411: return anAsset.getTypeIdentificationPG()
0412: .getTypeIdentification();
0413: }
0414:
0415: public String getInventoryType(Inventory inventory) {
0416: ScheduledContentPG scp = inventory.getScheduledContentPG();
0417: Asset proto = scp.getAsset();
0418: if (proto == null) {
0419: if (logger.isErrorEnabled()) {
0420: logger
0421: .error("getInventoryType failed to get asset for "
0422: + inventory.getScheduledContentPG()
0423: .getAsset()
0424: .getTypeIdentificationPG());
0425: }
0426: return "";
0427: }
0428: return proto.getTypeIdentificationPG().getTypeIdentification();
0429: }
0430:
0431: // get the first day in theater
0432: public long getLogOPlanStartTime() {
0433: return logOPlan.getStartTime();
0434: }
0435:
0436: // get the last day in theater
0437: public long getLogOPlanEndTime() {
0438: return logOPlan.getEndTime();
0439: }
0440:
0441: public TaskUtils getTaskUtils() {
0442: return taskUtils;
0443: }
0444:
0445: public TimeUtils getTimeUtils() {
0446: return timeUtils;
0447: }
0448:
0449: public AssetUtils getAssetUtils() {
0450: return AssetUtils;
0451: }
0452:
0453: public ScheduleUtils getScheduleUtils() {
0454: return scheduleUtils;
0455: }
0456:
0457: public String getSupplyType() {
0458: return supplyType;
0459: }
0460:
0461: private Organization getMyOrganization(Enumeration orgs) {
0462: Organization myOrg = null;
0463: // look for this organization
0464: if (orgs.hasMoreElements()) {
0465: myOrg = (Organization) orgs.nextElement();
0466: }
0467: return myOrg;
0468: }
0469:
0470: public Organization getMyOrganization() {
0471: return myOrganization;
0472: }
0473:
0474: public String getOrgName() {
0475: if ((myOrgName == null) && (getMyOrganization() != null)) {
0476: myOrgName = getMyOrganization().getItemIdentificationPG()
0477: .getItemIdentification();
0478: }
0479: return myOrgName;
0480: }
0481:
0482: public long getCurrentTimeMillis() {
0483: return currentTimeMillis();
0484: }
0485:
0486: public boolean publishAdd(Object o) {
0487: getBlackboardService().publishAdd(o);
0488: return true;
0489: }
0490:
0491: public boolean publishChange(Object o) {
0492: getBlackboardService().publishChange(o);
0493: return true;
0494: }
0495:
0496: public boolean publishRemove(Object o) {
0497: getBlackboardService().publishRemove(o);
0498: return true;
0499: }
0500:
0501: public PlanningFactory getPlanningFactory() {
0502: PlanningFactory rootFactory = null;
0503: if (domainService != null) {
0504: rootFactory = (PlanningFactory) domainService
0505: .getFactory("planning");
0506: }
0507: return rootFactory;
0508: }
0509:
0510: public LoggingService getLoggingService(Object requestor) {
0511: return (LoggingService) getServiceBroker().getService(
0512: requestor, LoggingService.class, null);
0513: }
0514:
0515: public BlackboardService getBlackboardService() {
0516: return blackboard;
0517: }
0518:
0519: protected void execute() {
0520: if (myOrganization == null) {
0521: myOrganization = getMyOrganization(selfOrganizations
0522: .elements());
0523: if (myOrganization != null) {
0524: if (blackboard.didRehydrate()) {
0525: checkDateOfBlackboard();
0526: }
0527: projectionTaskSubscription = (IncrementalSubscription) blackboard
0528: .subscribe(new LocalTaskPredicate(supplyType,
0529: getOrgName(),
0530: Constants.Verb.ProjectSupply, taskUtils));
0531:
0532: genSupplyTaskSubscription = (IncrementalSubscription) blackboard
0533: .subscribe(new LocalTaskPredicate(supplyType,
0534: getOrgName(), Constants.Verb.Supply,
0535: taskUtils));
0536:
0537: }
0538: // the didRehydrate flag will be reset after the first transaction, if org is still null
0539: // this is a problem
0540: if (blackboard.didRehydrate() && myOrganization == null) {
0541: if (logger.isErrorEnabled()) {
0542: logger
0543: .error("Blackboard was rehydrated with null self organization, checkDateOfBlackboard"
0544: + " will not be called ");
0545: }
0546: }
0547: }
0548:
0549: // get the Logistics OPlan (our homegrown version with specific dates).
0550: if ((logOPlan == null)
0551: || logisticsOPlanSubscription.hasChanged()) {
0552: Iterator opIt = logisticsOPlanSubscription.iterator();
0553: if (opIt.hasNext()) {
0554: //we only expect to have one
0555: logOPlan = (LogisticsOPlan) opIt.next();
0556: }
0557: }
0558:
0559: if (myOrganization == null) {
0560: if (logger.isInfoEnabled()) {
0561: logger.info("\n DemandGeneratorPlugin " + supplyType
0562: + " not ready to process tasks yet."
0563: + " my org is: " + myOrganization);
0564: }
0565: return;
0566: }
0567:
0568: if ((projectionTaskSubscription == null)
0569: || (projectionTaskSubscription.isEmpty())
0570: || (logOPlan == null)) {
0571: if (logger.isInfoEnabled()) {
0572: logger.info("\n DemandGeneratorPlugin " + supplyType
0573: + " not ready to process tasks yet."
0574: + " my org is: " + myOrganization);
0575: }
0576: return;
0577: }
0578:
0579: boolean generateDemand = false;
0580: long planTime = getStartOfPeriod(getCurrentTimeMillis());
0581:
0582: if (periodInDemandPeriod(projectionTaskSubscription, planTime,
0583: planTime + period)) {
0584: generateDemand = ((timer == null) || (timerExpired()));
0585: } else {
0586: long nextDemandPeriod = nextDemandPeriod(
0587: projectionTaskSubscription, planTime + period);
0588: setTimerToTopOfPeriod(nextDemandPeriod);
0589: return;
0590: }
0591:
0592: //if its time to generate demand do so.
0593: if (generateDemand) {
0594:
0595: if (logger.isInfoEnabled()) {
0596: logger
0597: .info("Timer has gone off. Planning for the next "
0598: + ((int) (period / getTimeUtils().MSEC_PER_HOUR))
0599: + "hours from " + new Date(planTime));
0600: }
0601: for (long time = planTime; time < planTime + period; time += stepPeriod) {
0602:
0603: //filter and create task from time to time plus step period inclusive
0604: //(stepPeriod -1)
0605: Collection relevantProjs = filterProjectionsOnTime(
0606: projectionTaskSubscription, time, time
0607: + (stepPeriod - 1));
0608:
0609: Collection relevantSupplys = filterSupplyTasksOnTime(
0610: genSupplyTaskSubscription, time, time
0611: + (stepPeriod));
0612:
0613: //TODO: MWD Remove debug statements:
0614: if ((getOrgName() != null)
0615: && (getOrgName().trim().equals("1-35-ARBN"))
0616: && (logger.isDebugEnabled())) {
0617: logger.debug("I'm waking up - new period starts "
0618: + new Date(planTime)
0619: + " and step (start,dur) is ("
0620: + new Date(time) + "," + stepPeriod + ")"
0621: + " and Num of projections for "
0622: + getOrgName() + " is: "
0623: + relevantProjs.size());
0624: }
0625:
0626: relevantProjs = class9Scheduler
0627: .filterProjectionsToMaxSpareParts(relevantProjs);
0628: //filter and create task from time to time plus step period inclusive
0629: //(stepPeriod -1)
0630: List demandTasks = demandGenerator.generateDemandTasks(
0631: time, (stepPeriod - 1), relevantProjs,
0632: relevantSupplys);
0633:
0634: if (demandOutputModule != null) {
0635: demandOutputModule
0636: .writeDemandOutputToFile(demandTasks);
0637: }
0638: }
0639:
0640: resetTimer();
0641: }
0642: }
0643:
0644: /**
0645: * Filter the passed in collection of projection tasks to those overlapping the period
0646: * between the start and end time.
0647: *
0648: * @param projections - whole collection of projection tasks
0649: * @param startGen - start time for generating supply tasks
0650: * @param endGen - end time for generating supply tasks
0651: * @return Collection of projection tasks filtered by start and end time.
0652: */
0653: protected Collection filterProjectionsOnTime(
0654: Collection projections, long startGen, long endGen) {
0655: ArrayList filteredProjs = new ArrayList();
0656: Iterator projectionIt = projections.iterator();
0657: while (projectionIt.hasNext()) {
0658: Task proj = (Task) projectionIt.next();
0659: if ((TaskUtils.getStartTime(proj) < endGen)
0660: && (TaskUtils.getEndTime(proj) > startGen)) {
0661: filteredProjs.add(proj);
0662: }
0663: }
0664: return filteredProjs;
0665: }
0666:
0667: /**
0668: * Filter the passed in collection of projection tasks to those overlapping the period
0669: * between the start and end time.
0670: *
0671: * @param projections - whole collection of projection tasks
0672: * @param startGen - start time for generating supply tasks
0673: * @param endGen - end time for generating supply tasks
0674: * @return Collection of projection tasks filtered by start and end time.
0675: */
0676: protected Collection filterSupplyTasksOnTime(
0677: Collection supplyTasks, long startGen, long endGen) {
0678: ArrayList filteredSupplys = new ArrayList();
0679: Iterator supplyTaskIt = supplyTasks.iterator();
0680: while (supplyTaskIt.hasNext()) {
0681: Task actual = (Task) supplyTaskIt.next();
0682: if ((TaskUtils.getEndTime(actual) < endGen)
0683: && (TaskUtils.getEndTime(actual) >= startGen)) {
0684: filteredSupplys.add(actual);
0685: }
0686: }
0687: return filteredSupplys;
0688: }
0689:
0690: /**
0691: * Find out if passed in time is in a demand period
0692: *
0693: * @param projections - whole collection of projection tasks
0694: * @param startGen - time concerned with to find whether in a demand period
0695: * @param endGen - time concerned with to find whether in a demand period
0696: * @return Collection of projection tasks filtered by start and end time.
0697: */
0698: protected boolean periodInDemandPeriod(Collection projections,
0699: long startGen, long endGen) {
0700: Iterator projectionIt = projections.iterator();
0701: while (projectionIt.hasNext()) {
0702: Task proj = (Task) projectionIt.next();
0703: if ((TaskUtils.getStartTime(proj) < endGen)
0704: && (TaskUtils.getEndTime(proj) > startGen)) {
0705: return true;
0706: }
0707: }
0708: return false;
0709: }
0710:
0711: /**
0712: * Find the earliest projection after the time passed in.
0713: *
0714: * @param projections - whole collection of projection tasks
0715: * @param aTime - time concerned with to find whether in a demand period
0716: * @return Collection of projection tasks filtered by start and end time.
0717: */
0718: protected long nextDemandPeriod(Collection projections, long aTime) {
0719: long earliestNext = Long.MAX_VALUE;
0720: Iterator projectionIt = projections.iterator();
0721: while (projectionIt.hasNext()) {
0722: Task proj = (Task) projectionIt.next();
0723: long startTime = TaskUtils.getStartTime(proj);
0724: if (startTime > aTime) {
0725: earliestNext = Math.min(earliestNext, startTime);
0726: }
0727: }
0728: return earliestNext;
0729: }
0730:
0731: /**
0732: * Creates an instance of an DemandTaskGeneratorIfc by
0733: * searching plugin parameters for DEMAND_GENERATOR argument.
0734: * In the absence of an REQ_EXPANDER argument, a default is used:
0735: * org.cougaar.logistics.plugin.demand.DemandTaskGenerator
0736: *
0737: * @return {@link DemandTaskGeneratorIfc}
0738: */
0739: protected DemandTaskGeneratorIfc getDemandTaskGeneratorModule() {
0740: String demGenClass = (String) pluginParams
0741: .get(DEMAND_GENERATOR);
0742: if (demGenClass != null) {
0743: try {
0744: Class[] paramTypes = { this .getClass() };
0745: Object[] initArgs = { this };
0746: Class cls = Class.forName(demGenClass);
0747: Constructor constructor = cls
0748: .getConstructor(paramTypes);
0749: DemandTaskGeneratorIfc demandGen = (DemandTaskGeneratorIfc) constructor
0750: .newInstance(initArgs);
0751: if (logger.isInfoEnabled()) {
0752: logger.info("Using RequirementsExpander "
0753: + demGenClass);
0754: }
0755: return demandGen;
0756: } catch (Exception e) {
0757: if (logger.isErrorEnabled()) {
0758: logger
0759: .error(e
0760: + " Unable to create demandTaskGeneratorModule instance of "
0761: + demGenClass
0762: + ". "
0763: + "Loading default org.cougaar.logistics.plugin.demand.DemandTaskGenerator");
0764: }
0765: }
0766: }
0767:
0768: return new DemandTaskGenerator(this );
0769: }
0770:
0771: private DGClass9Scheduler getClass9SchedulerModule() {
0772: return new DGClass9Scheduler(this );
0773: }
0774:
0775: public boolean getPoissonOn() {
0776: return poissonOn;
0777: }
0778:
0779: public long getPeriod() {
0780: return period;
0781: }
0782:
0783: private boolean isLegalPeriod(long periodInMSEC) {
0784: long remainder = -1;
0785: if (periodInMSEC >= getTimeUtils().MSEC_PER_DAY) {
0786: remainder = periodInMSEC % getTimeUtils().MSEC_PER_DAY;
0787: } else if (periodInMSEC >= getTimeUtils().MSEC_PER_HOUR) {
0788: remainder = periodInMSEC % getTimeUtils().MSEC_PER_HOUR;
0789: }
0790: return ((periodInMSEC > 0) && (remainder == 0));
0791: }
0792:
0793: public boolean periodInDays() {
0794: return (getPeriodUnit() == getTimeUtils().MSEC_PER_DAY);
0795: }
0796:
0797: public long getPeriodUnit() {
0798: if (period >= getTimeUtils().MSEC_PER_DAY) {
0799: return getTimeUtils().MSEC_PER_DAY;
0800: } else {
0801: return getTimeUtils().MSEC_PER_HOUR;
0802: }
0803: }
0804:
0805: private int getPeriodMultiplier() {
0806: return (int) ((int) period / getPeriodUnit());
0807: }
0808:
0809: /**
0810: * Read the Plugin parameters(Accepts key/value pairs)
0811: * Initializes supplyType and inventoryFile
0812: */
0813: private HashMap readParameters() {
0814: final String errorString = "DemandGeneratorPlugin requires 2 parameters, Supply Type and Gemerate Period (secs). Generate Period must be in whole days or whole hours (< 24). There is also a optional parameter RANDOM_DEVIATION_ON=<true,false> which enables whole number POISSON random deviation around the supply task quanity.";
0815: Collection p = getParameters();
0816:
0817: if (p.isEmpty()) {
0818: if (logger.isErrorEnabled()) {
0819: logger.error(errorString);
0820: }
0821: return null;
0822: }
0823: HashMap map = new HashMap();
0824: int idx;
0825:
0826: for (Iterator i = p.iterator(); i.hasNext();) {
0827: String s = (String) i.next();
0828: if ((idx = s.indexOf('=')) != -1) {
0829: String key = new String(s.substring(0, idx));
0830: String value = new String(s.substring(idx + 1, s
0831: .length()));
0832: map.put(key.trim(), value.trim());
0833: }
0834: }
0835: supplyType = (String) map.get(SUPPLY_TYPE);
0836:
0837: String periodString = (String) map.get(GENERATE_PERIOD);
0838:
0839: if ((periodString != null)
0840: && (!(periodString.trim().equals("")))) {
0841: try {
0842: period = (new Long(periodString)).longValue();
0843: } catch (Exception e) {
0844: period = -1;
0845: }
0846: } else {
0847: //Default is 24 hours
0848: period = 24 * 60 * 60;
0849: period = period * 1000;
0850: }
0851:
0852: if (!isLegalPeriod(period)) {
0853: if (logger.isErrorEnabled()) {
0854: logger.error("Illegal Period - not in days or hours");
0855: }
0856: period = -1;
0857: }
0858:
0859: String stepPeriodString = (String) map.get(STEP_PERIOD);
0860: if ((stepPeriodString != null)
0861: && (!(stepPeriodString.trim().equals("")))) {
0862: try {
0863: stepPeriod = (new Long(stepPeriodString)).longValue();
0864: } catch (Exception e) {
0865: stepPeriod = -1;
0866: }
0867: } else {
0868: //Default is 24 hours
0869: stepPeriod = 24 * 60 * 60;
0870: stepPeriod = stepPeriod * 1000;
0871: }
0872:
0873: if (!isLegalPeriod(stepPeriod)) {
0874: if (logger.isErrorEnabled()) {
0875: logger
0876: .error("Illegal Step Period - not in days or hours");
0877: }
0878: stepPeriod = -1;
0879: }
0880:
0881: String poissonOnString = (String) map.get(RANDOM_DEVIATION_ON);
0882:
0883: if (poissonOnString != null) {
0884: poissonOnString = poissonOnString.trim().toLowerCase();
0885: poissonOn = (poissonOnString.equals("true"));
0886: //if(logger.isShoutEnabled()) {
0887: //logger.shout("RANDOM_DEVIATION_ON=" + poissonOn);
0888: //}
0889: }
0890:
0891: if (((supplyType == null) || (period <= 0)
0892: && logger.isErrorEnabled())) {
0893: logger.error(errorString);
0894: }
0895: return map;
0896: }
0897:
0898: /**
0899: * Get the time in milliseconds that would be midnight of the day
0900: * before or first thing in the morning today.
0901: *
0902: * @return - the time in milliseconds that represents first thing in the
0903: * morning today
0904: */
0905: protected long getStartOfPeriod(long timeIn) {
0906: //long timeIn = getCurrentTimeMillis();
0907: //truncate to the whole number that represents the period num since the start of time.
0908: long periods = (long) (timeIn / period);
0909: //Multiply it back to which gives the start of the period.
0910: long timeOut = periods * period;
0911: if (timeIn == timeOut) {
0912: if (logger.isDebugEnabled()) {
0913: logger
0914: .debug("GetStartOfToday - unexpected timeIn==timeOut=="
0915: + new Date(timeOut));
0916: }
0917: }
0918: return timeOut;
0919: }
0920:
0921: protected void setTimerToTopOfPeriod(long goOffAt) {
0922: long expiration = getStartOfPeriod(goOffAt);
0923: resetTimer(expiration);
0924: }
0925:
0926: /**
0927: * Schedule a timer for midnight tonight.
0928: */
0929:
0930: protected void resetTimer() {
0931: long expiration = getStartOfPeriod(getCurrentTimeMillis())
0932: + period;
0933: resetTimer(expiration);
0934: }
0935:
0936: /**
0937: * Schedule a update wakeup after some interval of time
0938: *
0939: * @param delay how long to delay before the timer expires.
0940: */
0941: protected void resetTimerWDelay(long delay) {
0942: resetTimer(getCurrentTimeMillis() + delay);
0943: }
0944:
0945: /**
0946: * Schedule a update wakeup after some interval of time
0947: *
0948: * @param expiration The date-time you wish this alarm to expire at
0949: */
0950: protected void resetTimer(long expiration) {
0951: synchronized (timerLock) {
0952: Alarm old = timer; // keep any old one around
0953: if (old != null) {
0954: old.cancel(); // cancel the old one
0955: }
0956: if (getBlackboardService() == null && logger != null
0957: && logger.isWarnEnabled()) {
0958: logger
0959: .warn("Started service alarm before the blackboard service"
0960: + " is available");
0961: }
0962:
0963: /**
0964: * TODO: MWD Remove
0965: *
0966: if ((getOrgName() != null) &&
0967: (getOrgName().trim().equals("1-35-ARBN"))) {
0968: System.out.println("Setting new timer to go at: " + new Date(expiration));
0969: }
0970: */
0971:
0972: timer = new CougTimeAlarm(expiration);
0973: getAlarmService().addAlarm(timer);
0974: }
0975: }
0976:
0977: /**
0978: * Cancel the timer.
0979: */
0980: protected void cancelTimer() {
0981: synchronized (timerLock) {
0982: if (timer == null)
0983: return;
0984: // if (logger.isDebugEnabled()) logger.debug("Cancelling timer");
0985: timer.cancel();
0986: timer = null;
0987: }
0988: }
0989:
0990: /**
0991: * access the timer itself (if any) *
0992: */
0993: protected Alarm getTimer() {
0994: synchronized (timerLock) {
0995: return timer;
0996: }
0997: }
0998:
0999: /**
1000: * When will (has) the timer expire *
1001: */
1002: protected long getTimerExpirationTime() {
1003: synchronized (timerLock) {
1004: if (timer != null) {
1005: return timer.getExpirationTime();
1006: } else {
1007: return 0;
1008: }
1009: }
1010: }
1011:
1012: /**
1013: * Returns true IFF there is an unexpired timer.
1014: */
1015: protected boolean hasUnexpiredTimer() {
1016: synchronized (timerLock) {
1017: if (timer != null) {
1018: return !timer.hasExpired();
1019: } else {
1020: return false;
1021: }
1022: }
1023: }
1024:
1025: /**
1026: * Test if the timer has expired.
1027: *
1028: * @return false if the timer is not running or has not yet expired
1029: * else return true.
1030: */
1031: protected boolean timerExpired() {
1032: synchronized (timerLock) {
1033: return timer != null && timer.hasExpired();
1034: }
1035: }
1036:
1037: private final class CougTimeAlarm implements Alarm {
1038: private long expirationTime;
1039: private boolean expired = false;
1040:
1041: public CougTimeAlarm(long expiration) {
1042: this .expirationTime = expiration;
1043: }
1044:
1045: public long getExpirationTime() {
1046: return expirationTime;
1047: }
1048:
1049: public synchronized void expire() {
1050: if (!expired) {
1051: expired = true;
1052: BlackboardService bb = getBlackboardService();
1053: if (bb != null) {
1054: bb.signalClientActivity();
1055: } else {
1056: if (logger != null && logger.isWarnEnabled()) {
1057: logger
1058: .warn("Alarm to trigger at "
1059: + (new Date(expirationTime))
1060: + " has expired,"
1061: + " but the blackboard service is null. Plugin "
1062: + " model state is "
1063: + getModelState());
1064: }
1065: }
1066: }
1067: }
1068:
1069: public synchronized boolean hasExpired() {
1070: return expired;
1071: }
1072:
1073: public synchronized boolean cancel() {
1074: boolean was = expired;
1075: expired = true;
1076: return was;
1077: }
1078: }
1079:
1080: private long findLastSupplyTaskTime(Collection tasks) {
1081: MaxEndThunk thunk = new MaxEndThunk();
1082: Collectors.apply(thunk, tasks);
1083: return thunk.getMaxEndTime();
1084: }
1085:
1086: private class MaxEndThunk implements Thunk {
1087: long maxEnd = Long.MIN_VALUE;
1088:
1089: public MaxEndThunk() {
1090: }
1091:
1092: public void apply(Object o) {
1093: long endTime = taskUtils.getEndTime((Task) o);
1094: if (endTime > maxEnd) {
1095: maxEnd = endTime;
1096: }
1097: }
1098:
1099: public long getMaxEndTime() {
1100: if (logger.isDebugEnabled()) {
1101: logger.debug(" Last task time found "
1102: + new Date(maxEnd));
1103: }
1104: return maxEnd;
1105: }
1106: }
1107: }
|