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.ldm;
028:
029: import org.cougaar.core.component.ServiceBroker;
030: import org.cougaar.core.service.LoggingService;
031: import org.cougaar.planning.ldm.LatePropertyProvider;
032: import org.cougaar.util.UnaryPredicate;
033: import org.cougaar.planning.ldm.asset.Asset;
034: import org.cougaar.planning.ldm.asset.NewPropertyGroup;
035: import org.cougaar.planning.ldm.asset.PropertyGroup;
036: import org.cougaar.planning.ldm.measure.Area;
037: import org.cougaar.planning.ldm.measure.Distance;
038: import org.cougaar.planning.ldm.measure.Mass;
039: import org.cougaar.planning.ldm.measure.Volume;
040: import org.cougaar.glm.ldm.asset.HumanitarianDailyRation;
041: import org.cougaar.glm.ldm.asset.ClassISubsistence;
042: import org.cougaar.glm.ldm.asset.NewMovabilityPG;
043: import org.cougaar.glm.ldm.asset.NewCostPG;
044: import org.cougaar.glm.ldm.asset.CostPGImpl;
045: import org.cougaar.glm.ldm.asset.NewPackagePG;
046: import org.cougaar.glm.ldm.asset.NewPhysicalPG;
047: import org.cougaar.glm.ldm.asset.PropertyGroupFactory;
048: import org.cougaar.glm.ldm.asset.NewSupplyClassPG;
049: import org.cougaar.glm.ldm.QueryLDMPlugin;
050:
051: import org.cougaar.logistics.ldm.asset.RationPG;
052: import org.cougaar.logistics.ldm.asset.NewRationPG;
053:
054: import java.math.BigDecimal;
055: import java.sql.*;
056: import java.util.Enumeration;
057: import java.util.Hashtable;
058: import java.util.Vector;
059: import java.util.Map;
060: import java.util.HashMap;
061:
062: /**
063: * Creates and rototype and their property groups for Subsistence
064: **/
065: public class ClassIPartsPrototypeProvider extends QueryLDMPlugin {
066:
067: private static Hashtable otherAssetNomenclatures;
068: private Hashtable propertyGroupTable_ = new Hashtable();
069: private static HashMap emptyHashMap = new HashMap(0);
070: private static Vector emptyVector = new Vector(0);
071: private LoggingService logger;
072:
073: //
074: // NOTE that the static declarations here do decrease the queries overall within
075: // a single JVM. However, under certain circumstances, it may not be appropriate
076: // to have all clusters sharing a single Map. -- LLG
077: //
078: private static Map supplementQueryResult = new HashMap();
079:
080: // Builds a hash table of nsn
081: static {
082: otherAssetNomenclatures = new Hashtable(1);
083: otherAssetNomenclatures.put("NSN/8970013750516",
084: "HumanitarianDailyRation");
085: } // static
086:
087: public void setLoggingService(LoggingService logger) {
088: this .logger = logger;
089: }
090:
091: /**
092: * Method to determine if this class can handle an item typeid of type class_hint
093: * @param typeid identifier for item (an NSN)
094: * @param class_hint hint as to class of item being requested
095: * @return boolean representing whether this prototype provider can handle
096: * this item
097: **/
098: public boolean canHandle(String typeid, Class class_hint) {
099: if (logger.isDebugEnabled()) {
100: logger.debug("canHandle (typeid:" + typeid + ")");
101: }
102:
103: Boolean protoProvider = (Boolean) myParams_
104: .get("PrototypeProvider");
105: if ((protoProvider == null) || (protoProvider.booleanValue())) {
106: if (class_hint == null) {
107: if (typeid.startsWith("NSN/"))
108: return true;
109: } else {
110: String class_name = class_hint.getName();
111: if (typeid.startsWith("NSN/")
112: && (class_name.equals("ClassISubsistence") || class_name
113: .equals("HumanitarianDailyRation"))) {
114: return true;
115: } // if
116: } // if
117: } // if
118: if (logger.isDebugEnabled()) {
119: logger.debug("canHandle() could not handle <" + class_hint
120: + "> for " + typeid);
121: }
122: return false;
123: } // canHandle
124:
125: /**
126: * Makes a prototype for as Asset of an item of type class_hint
127: * @param type_name identifier for item e.g a
128: * @param class_hint hint as to class of item being requested
129: * @return Asset Prtotype that's created. Note that Asset is
130: * actually a prototype here
131: **/
132: public Asset makePrototype(String type_name, Class class_hint) {
133: String class_name = null;
134: if (class_hint != null) {
135: class_name = class_hint.getName();
136: if (!(class_name.equals("ClassISubsistence") || class_name
137: .equals("HumanitarianDailyRation"))) {
138: if (logger.isDebugEnabled()) {
139: logger
140: .debug("makePrototype() could not make prototype for<"
141: + type_name);
142: }
143: return null;
144: } // if
145: } //end (class_hint != null)
146: if (class_name == null) {
147: if (type_name.startsWith("NSN/89")) {
148: if (otherAssetNomenclatures.containsKey(type_name)) {
149: class_name = (String) otherAssetNomenclatures
150: .get(type_name);
151: } else {
152: class_name = "ClassISubsistence";
153: } // if
154: } else {
155: if (logger.isDebugEnabled()) {
156: logger
157: .debug("makePrototype() could not make prototype for<"
158: + type_name);
159: }
160: return null;
161: } // if
162: } // if
163: String nomenclature = getNomenclature(type_name, class_name);
164: if (nomenclature == null) {
165: //If the nomenclature can't be found, we can't handle this item after all.
166: return null;
167: } // if
168: // Create the Asset prototype
169: if (logger.isDebugEnabled()) {
170: logger.debug("makePrototype() making prototype for<"
171: + type_name);
172: }
173: return newAsset(type_name, class_name, nomenclature);
174: } // makePrototype
175:
176: /**
177: * Convenience method to read the query statement from a file
178: * and execute the query.
179: * @param query_name String refers to the specific query statement
180: * @param a String for first query variable
181: * @param b String for second query varaible
182: * @return Vector containing the query result
183: **/
184: protected Vector doQuery(String query_name, String a, String b) {
185: String query = substituteList((String) fileParameters_
186: .get(query_name), a, b);
187: if (query == null) {
188: if (logger.isErrorEnabled()) {
189: logger
190: .error("doQuery(), query string from file is null");
191: }
192: return null;
193: } // if
194: Vector holdsQueryResult;
195: try {
196: holdsQueryResult = executeQuery(query);
197: } catch (Exception ee) {
198: if (logger.isErrorEnabled()) {
199: logger.error("doQuery(), DB query failed. query= "
200: + query + "\n" + ee.toString());
201: }
202: return null;
203: } // try
204: return holdsQueryResult;
205: } // doQuery
206:
207: /**
208: * Gets a list of supplement NSNs for a specific meal_type and specific alternate_name
209: * @param meal_type type of meals: BREAKFAST, LUNCH/DINNER
210: * @return HashMap of NSNs and their rates
211: **/
212: protected HashMap getSupplementalList(String meal_type,
213: String alternate_name) {
214: QueryHashKey key = new QueryHashKey(meal_type, alternate_name);
215: HashMap result;
216: synchronized (supplementQueryResult) {
217: result = (HashMap) supplementQueryResult.get(key);
218: if (result == null) {
219: Vector holdsQueryResult = doQuery(
220: "ClassISupplementList", meal_type,
221: alternate_name);
222: if (holdsQueryResult.isEmpty()) {
223: supplementQueryResult.put(key, emptyHashMap);
224: return emptyHashMap;
225: } else {
226: // parse results
227: String typeIDPrefix = "NSN/";
228: result = new HashMap(5);
229: for (int i = 0; i < holdsQueryResult.size(); i++) {
230: Object[] row = ((Object[]) holdsQueryResult
231: .elementAt(i));
232: result.put(typeIDPrefix + (String) row[0],
233: (BigDecimal) row[1]);
234: } // for
235: supplementQueryResult.put(key, result);
236: } // if
237: } // if
238: return result;
239: } // synch
240: } // getSupplementalList
241:
242: /**
243: * Method to retrieve the nomenclature for the item in question
244: * @param type_id identifier for item e.g a nsn
245: * @param type class type of item being requested
246: * @return Nomenclature
247: */
248: protected String getNomenclature(String type_id, String type) {
249: String item_id = type_id.substring(type_id.indexOf("/") + 1); // The NSN
250: String query = substituteNSN((String) fileParameters_
251: .get("ClassIData"), item_id, ":nsns");
252: if (query == null) {
253: if (logger.isErrorEnabled()) {
254: logger
255: .error("doQuery(), query string from file is null");
256: }
257: return null;
258: }
259: Vector result;
260: try {
261: result = executeQuery(query);
262: } catch (Exception ee) {
263: if (logger.isErrorEnabled()) {
264: logger.error("doQuery(), DB query failed. query= "
265: + query + "\n" + ee.toString());
266: }
267: return null;
268: }
269: if (result.isEmpty()) {
270: return null;
271: } // if
272: // parse results
273: Object row[] = (Object[]) result.firstElement();
274: String nomen = (String) row[0];
275: if (nomen == null) {
276: return null;
277: } // if
278: String meal_type = (String) row[1];
279: int rotation_day = intValue(row[3]);
280:
281: // Optimize this later.
282: if (meal_type == null) {
283: meal_type = "";
284: } // if
285: nomen = nomen + " " + meal_type + " ";
286: if (rotation_day > 0) {
287: nomen += rotation_day;
288: } // if
289: Vector pgs = null;
290: pgs = parseSubsistence(row, type_id, type);
291: if (pgs != null) {
292: propertyGroupTable_.put(type_id, pgs);
293: } // if
294: if (logger.isDebugEnabled()) {
295: logger.debug("getNomenclature() returning " + nomen);
296: }
297: return nomen;
298: } // getNomenclature
299:
300: /**
301: * Return int value else -1 if it is null
302: * @param x Object whose int value will be returned
303: * @return int value of the object
304: **/
305: private int intValue(Object x) {
306: return (x == null) ? -1 : (((BigDecimal) x).intValue());
307: } // intValue
308:
309: /**
310: * Return double value else -1 if it is null
311: * @param x Object whose double value will be returned
312: * @return double value of the object
313: **/
314: private double doubleValue(Object x) {
315: return (x == null) ? -1.0 : (((BigDecimal) x).doubleValue());
316: } // doubleValue
317:
318: /**
319: * Return long value else -1 if it is null
320: * @param x Object whose long value will be returned
321: * @return long value of the object
322: **/
323: private long longValue(Object x) {
324: return (x == null) ? -1 : ((long) ((BigDecimal) x).longValue());
325: } // longValue
326:
327: // Method to parse the results of the query
328: private Vector parseSubsistence(Object row[], String typeID,
329: String type) {
330: String nomenclature = (String) row[0];
331: String meal_type = (String) row[1];
332: String ui = (String) row[2];
333: int rotation_day = intValue(row[3]);
334: double weight = doubleValue(row[4]);
335: String alternate_name = (String) row[5];
336: long count_per_ui = longValue(row[6]);
337: String unit_of_pack = (String) row[7];
338: double vol_cubic_feet = doubleValue(row[8]);
339: double cost = doubleValue(row[9]);
340: if (ui == null) {
341: if (logger.isDebugEnabled()) {
342: logger
343: .debug("Unit of Issue was null, seting to EA !!!!!!!!!!!!!");
344: }
345: ui = "EA";
346: } // if
347: Vector pgs = createPackagePGs(nomenclature, alternate_name, ui,
348: weight, count_per_ui, vol_cubic_feet);
349: PropertyGroup physicalPG = createPhysicalPGs(weight,
350: vol_cubic_feet);
351: PropertyGroup movabilityPG = createMovabilityPGs();
352: PropertyGroup rationPG = createRationPG(nomenclature,
353: alternate_name, meal_type, ui, rotation_day,
354: unit_of_pack, typeID, type);
355: if (rationPG != null) {
356: pgs.add(rationPG);
357: } // if
358: if (physicalPG != null) {
359: pgs.add(physicalPG);
360: } // if
361: if (movabilityPG != null) {
362: pgs.add(movabilityPG);
363: } // if
364: NewSupplyClassPG supply_pg = (NewSupplyClassPG) org.cougaar.glm.ldm.asset.PropertyGroupFactory
365: .newSupplyClassPG();
366: supply_pg.setSupplyClass("ClassISubsistence");
367: supply_pg.setSupplyType("Subsistence");
368: pgs.add(supply_pg);
369: NewCostPG pg = new CostPGImpl();
370: pg.setBreakOutCost(cost);
371: pgs.add(pg);
372: return pgs;
373: } // parseSubsistence
374:
375: /**Creates a MovabilityPG for a given assset*/
376: private PropertyGroup createMovabilityPGs() {
377: NewMovabilityPG pg2 = PropertyGroupFactory.newMovabilityPG();
378: pg2.setCargoCategoryCode("J3A");
379: pg2.setMoveable(true);
380: return pg2;
381: } // createMovabilityPGs
382:
383: /**Creates a RationPG for a given assset*/
384: private PropertyGroup createRationPG(String nomenclature,
385: String alternate_name, String meal_type, String ui,
386: int rotationDay, String unitOfPack, String typeID,
387: String type) {
388:
389: NewRationPG pg = (NewRationPG) getLDM().getFactory()
390: .createPropertyGroup(RationPG.class);
391: pg.setMealType(meal_type); //null for MRES
392: pg.setRationType(alternate_name);
393: pg.setUnitOfPack(unitOfPack);
394: if (meal_type != null) {
395: pg.setMandatorySupplement(getSupplementalList(meal_type,
396: alternate_name));
397: } else {
398: pg.setMandatorySupplement(emptyHashMap);
399: } // if
400: return pg;
401: } // createRationPG
402:
403: /**Creates a PackagePG for a given assset*/
404: private Vector createPackagePGs(String nomenclature,
405: String alternate_name, String unitOfIssue, double weight,
406: long countPerUI, double volCubicFeet) {
407: Vector pgs = new Vector(1);
408: if (unitOfIssue == null) {
409: return null;
410: } // if
411: NewPackagePG pg2 = PropertyGroupFactory.newPackagePG();
412: pg2.setCountPerPack(countPerUI);
413: pg2.setPackVolume(new Volume(volCubicFeet, Volume.CUBIC_FEET));
414: pg2.setUnitOfIssue(unitOfIssue);
415: pg2.setPackMass(new Mass(weight, Mass.POUNDS));
416: pg2
417: .setPackFootprintArea(new Area((1000.0),
418: Area.SQUARE_INCHES));//BOGUS
419: pg2.setPackHeight(new Distance(1000.0, Distance.INCHES));//BOGUS
420: pgs.add(pg2);
421: return pgs;
422: } // createPagckagePGs
423:
424: /**Creates a PhysicalPG for a given assset*/
425: private PropertyGroup createPhysicalPGs(double weight,
426: double volCubicFeet) {
427: NewPhysicalPG pg2 = PropertyGroupFactory.newPhysicalPG();
428: pg2.setFootprintArea(new Area((1000.0), Area.SQUARE_INCHES));//BOGUS
429: pg2.setHeight(new Distance(1000.0, Distance.INCHES));//BOGUS
430: pg2.setVolume(new Volume(volCubicFeet, Volume.CUBIC_FEET));
431: pg2.setMass(new Mass(weight, Mass.POUNDS));
432: pg2.setLength(new Distance(100.0, Distance.INCHES));//BOGUS
433: pg2.setWidth(new Distance(500.0, Distance.INCHES));//BOGUS;
434: return pg2;
435: } // createPhysicalPGs
436:
437: // CDW - looks like it's looking for consumed
438: public void fillProperties(Asset anAsset) {
439: if (logger.isDebugEnabled()) {
440: logger.debug("fillProperties for " + anAsset);
441: }
442: Vector pgs = null;
443: if ((anAsset instanceof ClassISubsistence)
444: || (anAsset instanceof HumanitarianDailyRation)) {
445: String typeID = anAsset.getTypeIdentificationPG()
446: .getTypeIdentification();
447: pgs = (Vector) propertyGroupTable_.get(typeID);
448: } // if
449: if ((pgs != null) && !pgs.isEmpty()) {
450: Enumeration pgs_enum = pgs.elements();
451: while (pgs_enum.hasMoreElements()) {
452: NewPropertyGroup pg = (NewPropertyGroup) pgs_enum
453: .nextElement();
454: anAsset.setPropertyGroup(pg);
455: if (logger.isDebugEnabled()) {
456: logger.debug("setting PGs for " + anAsset);
457: }
458: } // while
459: } // if
460: } // fillProperties
461:
462: /**
463: * Replaces the ":nsns" in the query with the actual NSN.
464: * @param q query string
465: * @param nsn actual NSN
466: * @param nsnStr String in the database
467: * @return new query
468: **/
469: public String substituteNSN(String q, String nsn, String nsnStr) {
470: String query = null;
471: if (q != null) {
472: int indx = q.indexOf(nsnStr);
473: if (indx != -1) {
474: query = q.substring(0, indx) + "'" + nsn + "'";
475: if (q.length() > indx + 5) {
476: query += q.substring(indx + 5);
477: } // if
478: } // if
479: } // if
480: return query;
481: } // subsituteNSN
482:
483: /**
484: * Replaces the ":nsn" in the query with the actual NSN.
485: * @param q query string
486: * @param nomenclature
487: * @return new query
488: **/
489: public String substituteList(String q, String meal_type,
490: String nomenclature) {
491: String query = null;
492: String query1 = null;
493: if (q != null) {
494: query = substituteNSN(q, meal_type, ":meal");
495: query1 = substituteNSN(query, nomenclature, ":nomn");
496: } // if
497: return query1;
498: } // substituteList
499:
500: /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
501:
502: /**
503: * Class to avoid concantenating Strings as keys.
504: **/
505: private class QueryHashKey {
506: private String a;
507: private String b;
508:
509: public QueryHashKey(String n, String s) {
510: a = n;
511: b = s;
512: } // constructor
513:
514: public int hashCode() {
515: int val = 0;
516:
517: if (a != null)
518: val += a.hashCode();
519: if (b != null)
520: val += b.hashCode();
521: return val;
522: } // hashCode
523:
524: public boolean equals(Object o) {
525: if (o instanceof QueryHashKey) {
526: QueryHashKey thekey = (QueryHashKey) o;
527: if (this .a != thekey.a) {
528: if (this .a == null) {
529: return false;
530: } // if
531: if (!this .a.equals(thekey.a)) {
532: return false;
533: } // if
534: } // if
535: if (this .b != thekey.b) {
536: if (this .b == null) {
537: return false;
538: } // if
539: if (!this .b.equals(thekey.b)) {
540: return false;
541: } // if
542: } // if
543: return true;
544: } // if
545: return false;
546: } // equals
547: } // QueryHashKey
548:
549: } // ClassIPartsPrototypeProvider
|