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.logistics.plugin.demand;
028:
029: import org.cougaar.glm.ldm.Constants;
030: import org.cougaar.glm.ldm.asset.SupplyClassPG;
031: import org.cougaar.glm.ldm.plan.GeolocLocationImpl;
032: import org.cougaar.logistics.plugin.inventory.MaintainedItem;
033: import org.cougaar.planning.ldm.asset.AggregateAsset;
034: import org.cougaar.planning.ldm.asset.Asset;
035: import org.cougaar.planning.ldm.measure.Latitude;
036: import org.cougaar.planning.ldm.measure.Longitude;
037: import org.cougaar.planning.ldm.plan.NewTask;
038: import org.cougaar.planning.ldm.plan.PrepositionalPhrase;
039: import org.cougaar.planning.ldm.plan.PrepositionalPhraseImpl;
040: import org.cougaar.planning.ldm.plan.Task;
041: import org.cougaar.planning.ldm.plan.Verb;
042: import org.cougaar.util.UnaryPredicate;
043:
044: import java.io.BufferedReader;
045: import java.io.File;
046: import java.io.FileReader;
047: import java.io.IOException;
048: import java.util.*;
049:
050: /**
051: * The DemandGeneratorInputModule generates demand from a data file input
052: * Expected Input File Format is comma seperated value with the following
053: * fields in the following order:
054: * timestamp(long), org(String), maintained asset id (String),
055: * item id (String), quantity (double)
056: *
057: * note: Any String field that contains a comma will be expected in quotes (")
058: *
059: * @see DemandGeneratorPlugin
060: * @see DemandGeneratorModule
061: * @see DemandGeneratorOutputModule
062: **/
063: public class DemandGeneratorInputModule extends DemandTaskGenerator {
064:
065: /**
066: * This predicate will gather GenerateProjection tasks matching a specific
067: * item/supply type
068: */
069: private static class GenerateProjectionsPredicate implements
070: UnaryPredicate {
071: String supplyType;
072: MaintainedItem maintainedItem;
073:
074: /**
075: * Predicate Constructor
076: * @param type supply type of item
077: * @param item item for which generate projections task is desired
078: */
079: public GenerateProjectionsPredicate(String type,
080: MaintainedItem item) {
081: supplyType = type;
082: maintainedItem = item;
083: }
084:
085: public boolean execute(Object o) {
086: if (o instanceof Task) {
087: Task task = (Task) o;
088: if (task.getVerb().equals(
089: Constants.Verb.GENERATEPROJECTIONS)) {
090: // Got the right verb...
091: PrepositionalPhrase pp = task
092: .getPrepositionalPhrase(Constants.Preposition.OFTYPE);
093: if (pp != null
094: && pp.getIndirectObject()
095: .equals(supplyType)) {
096: // Got the right supply type...
097: Asset asset = task.getDirectObject();
098: if (asset instanceof AggregateAsset) {
099: asset = ((AggregateAsset) asset).getAsset();
100: } else {
101: // If this is NOT an AggregateAsset we'll want to ensure the
102: // item id's match (assuming both are non-null)
103: if (maintainedItem.getItemIdentification() != null
104: && asset.getItemIdentificationPG() != null
105: && asset.getItemIdentificationPG()
106: .getItemIdentification() != null
107: && !asset
108: .getItemIdentificationPG()
109: .getItemIdentification()
110: .equals(
111: maintainedItem
112: .getItemIdentification())) {
113: return false;
114: }
115: }
116: // Finally, check type ids
117: String typeId = asset.getTypeIdentificationPG()
118: .getTypeIdentification();
119: return (typeId.equals(maintainedItem
120: .getTypeIdentification()));
121: }
122: }
123: }
124: return false;
125: }
126:
127: }
128:
129: private BufferedReader reader;
130: private int maxLineLength = 256;
131:
132: /**
133: * Constructor defers to parent class
134: * @param demandGeneratorPlugin DemandGeneratorPlugin for which this module is
135: * created
136: */
137: public DemandGeneratorInputModule(
138: DemandGeneratorPlugin demandGeneratorPlugin) {
139: super (demandGeneratorPlugin);
140: }
141:
142: /**
143: * Initialize the file reader
144: */
145: private void initReader() {
146: if (reader != null) {
147: // Already initialized
148: return;
149: }
150:
151: String dirPath = System.getProperty("org.cougaar.workspace",
152: ".")
153: + File.separator
154: + DemandGeneratorOutputModule.OUTPUT_SUBDIR;
155:
156: // Open file for input of demand data
157: File file = new File(dirPath, "ExecutionDemand."
158: + dgPlugin.getOrgName() + "."
159: + dgPlugin.getSupplyType());
160: try {
161: reader = new BufferedReader(new FileReader(file));
162: } catch (IOException ioe) {
163: if (logger.isWarnEnabled()) {
164: logger.warn("Unable to open demand input file: "
165: + file.toString());
166: }
167: }
168: }
169:
170: /**
171: * Generate demand tasks from file demand over the given time period
172: * @param start start time of period over which to collect data and create demand
173: * @param duration duration of period over which to collect data and create demand
174: * @param relevantProjectSupplys NOT USED
175: * @param relevantSupplys
176: */
177: public List generateDemandTasks(long start, long duration,
178: Collection relevantProjectSupplys,
179: Collection relevantSupplys) {
180: ArrayList demandTasks = new ArrayList();
181:
182: regenerateSupplyHash(relevantSupplys);
183:
184: // Make sure the file reader is initialized
185: initReader();
186: if (reader == null) {
187: return demandTasks;
188: }
189:
190: HashMap subtaskMap = new HashMap();
191: String line = null;
192:
193: try {
194: // Mark current position in file
195: reader.mark(maxLineLength);
196:
197: // Reader lines until we exit our defined period (ignore entries earlier)
198: for (line = reader.readLine(); line != null; line = reader
199: .readLine()) {
200: line = line.trim();
201:
202: // skip empty lines
203: if (line.length() == 0)
204: continue;
205:
206: StringTokenizer tok = new StringTokenizer(line, ",");
207:
208: long timeStamp = (new Long(tok.nextToken()))
209: .longValue();
210: if (timeStamp < start) {
211: // Ignore entries prior to start
212: continue;
213: }
214:
215: if (timeStamp >= start + duration) {
216: // Done. Reset file marker to beginning of this line
217: reader.reset();
218: break;
219: }
220:
221: // Extract The Org Name
222: String org = tok.nextToken();
223:
224: // Extract the Item Id of the item being maintained
225: String maintainedItemId = tok.nextToken();
226: if (maintainedItemId.equalsIgnoreCase("null")) {
227: maintainedItemId = null;
228: }
229:
230: // Extract the Type Id of the item being maintained
231: String maintainedTypeId = tok.nextToken();
232:
233: // Extract the Nomenclature of the item being maintained
234: String maintainedNomen = tok.nextToken();
235: if (maintainedNomen.equalsIgnoreCase("null")) {
236: maintainedNomen = null;
237: }
238:
239: // Extract the Id of the consumed item
240: String consumedItem = tok.nextToken();
241:
242: // Extract the qty demanded
243: double qty = Double.parseDouble(tok.nextToken());
244:
245: // Extract the location (lat, lon, name) for delivery
246: double lat = Double.parseDouble(tok.nextToken());
247: double lon = Double.parseDouble(tok.nextToken());
248: String geoLocName = tok.nextToken();
249:
250: // Create an instance of the consumed item to determine supply type
251: Asset consumed = getPlanningFactory().createInstance(
252: consumedItem);
253: SupplyClassPG supplyPG = (SupplyClassPG) consumed
254: .searchForPropertyGroup(org.cougaar.glm.ldm.asset.SupplyClassPG.class);
255: if (supplyPG == null) {
256: if (logger.isErrorEnabled()) {
257: logger
258: .error("Unable to retrieve SupplyClassPG for "
259: + consumedItem);
260: }
261: continue;
262: }
263: String type = supplyPG.getSupplyType();
264: if (!type.equals(dgPlugin.getSupplyType())) {
265: // This plugin/module does not handle this particular supply type
266: continue;
267: }
268:
269: // Create an instance of the Maintained Item and find the associated
270: // GenerateProjections task
271: MaintainedItem item = new MaintainedItem(type,
272: maintainedTypeId, maintainedItemId,
273: maintainedNomen, this .dgPlugin);
274: Task gpTask = getGenerateProjectionsTask(item, type);
275: if (gpTask == null) {
276: if (logger.isErrorEnabled()) {
277: logger
278: .error("Unable to find GenerateProjections task for item type id = '"
279: + item.getTypeIdentification()
280: + "' and type = '" + type + "'");
281: }
282: continue;
283: }
284:
285: HashMap supplyAssetMap = (HashMap) supplyHash
286: .get(gpTask);
287: Collection issuedSupplyTasks = null;
288: if (supplyAssetMap != null) {
289: issuedSupplyTasks = (Collection) supplyAssetMap
290: .get(consumed);
291: }
292: //If a supply task hasn't already been created for this day,asset
293: //then generate the demand task
294: if ((issuedSupplyTasks != null)
295: && (!issuedSupplyTasks.isEmpty())) {
296: if (logger.isWarnEnabled()) {
297: logger
298: .warn("Supply task already issued on this day for "
299: + consumed + " not re-issuing.");
300: }
301: continue;
302:
303: }
304:
305: // Create the geoloc for delivery
306: GeolocLocationImpl geoLoc = new GeolocLocationImpl(
307: Latitude.newLatitude(lat), Longitude
308: .newLongitude(lon), geoLocName);
309:
310: // Create the new demand task for the entry and add to list of new subtasks
311: Task demandTask = createNewDemandTask(gpTask, consumed,
312: timeStamp, timeStamp + duration, qty, geoLoc,
313: org, type, item);
314: demandTasks.add(demandTask);
315:
316: ArrayList subtasks = (ArrayList) subtaskMap.get(gpTask);
317: if (subtasks == null) {
318: subtasks = new ArrayList();
319: subtaskMap.put(gpTask, subtasks);
320: }
321: subtasks.add(demandTask);
322:
323: // Mark the beginning of the next line before reading
324: reader.mark(maxLineLength);
325: }
326: } catch (IOException ioe) {
327: if (logger.isErrorEnabled()) {
328: logger.error("Unable to parse demand input file: '"
329: + line + "'");
330: }
331: ioe.printStackTrace();
332: return demandTasks;
333: }
334:
335: // Go through each of the new demand tasks and publish as subtasks
336: // of the appropriate GenerateProjections task
337: Iterator gpTasks = subtaskMap.keySet().iterator();
338: while (gpTasks.hasNext()) {
339: Task gpTask = (Task) gpTasks.next();
340: Collection subtasks = (Collection) subtaskMap.get(gpTask);
341: addToAndPublishExpansion(gpTask, subtasks);
342: }
343:
344: // Return list of created demand tasks
345: return demandTasks;
346: }
347:
348: /**
349: * Retreive the GenerateProjections task for a given (maintained) item
350: * and supply type
351: * @param item item being maintained
352: * @param type supply type
353: * @return The GenerateProjections task for the given item/supply type
354: */
355: protected Task getGenerateProjectionsTask(MaintainedItem item,
356: String type) {
357: Task gpTask = null;
358: // Query blackboard...
359: Collection gpTasks = dgPlugin.getBlackboardService().query(
360: new GenerateProjectionsPredicate(type, item));
361: if (!gpTasks.isEmpty()) {
362: // There should only ever be one!
363: gpTask = (Task) gpTasks.iterator().next();
364: }
365: return gpTask;
366: }
367:
368: /**
369: * Create new demand task based on demand file entries
370: * @param parentTask Parent of task to be created
371: * @param consumed The asset consumed
372: * @param start The start preference
373: * @param end The end preference
374: * @param qty The qty preference
375: * @param loc The GeolocLocation for delivery
376: * @param org The requesting org
377: * @param type The supply type
378: * @param item The maintained item
379: * @return The newly created SUPPLY task
380: */
381: protected NewTask createNewDemandTask(Task parentTask,
382: Asset consumed, long start, long end, double qty,
383: GeolocLocationImpl loc, String org, String type,
384: MaintainedItem item) {
385:
386: Vector prefs = createDemandPreferences(start, end, qty);
387:
388: NewTask newTask = getPlanningFactory().newTask();
389:
390: newTask.setParentTask(parentTask);
391: newTask.setPlan(parentTask.getPlan());
392:
393: // Build Prepositional Phrases and add to task
394: Vector pps = new Vector();
395: PrepositionalPhraseImpl pp = new PrepositionalPhraseImpl();
396: pp.setPreposition(Constants.Preposition.FOR);
397: pp.setIndirectObject(org);
398: pps.add(pp);
399: pp = new PrepositionalPhraseImpl();
400: pp.setPreposition(Constants.Preposition.TO);
401: pp.setIndirectObject(loc);
402: pps.add(pp);
403: pp = new PrepositionalPhraseImpl();
404: pp.setPreposition(Constants.Preposition.MAINTAINING);
405: pp.setIndirectObject(item);
406: pps.add(pp);
407: pp = new PrepositionalPhraseImpl();
408: pp.setPreposition(Constants.Preposition.OFTYPE);
409: pp.setIndirectObject(type);
410: pps.add(pp);
411:
412: newTask.setPrepositionalPhrases(pps.elements());
413: newTask.setDirectObject(consumed);
414: newTask.setVerb(Verb.get(Constants.Verb.SUPPLY));
415: newTask.setPreferences(prefs.elements());
416: newTask.setContext(parentTask.getContext());
417: newTask.setCommitmentDate(new Date(end));
418:
419: return newTask;
420: }
421: }
|