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.logistics.ldm.asset.Level2Ammunition;
030: import org.cougaar.logistics.ldm.asset.Level2AmmoConsumerBG;
031: import org.cougaar.logistics.ldm.asset.Level2FuelConsumerBG;
032:
033: import org.cougaar.core.service.LoggingService;
034: import org.cougaar.planning.ldm.asset.Asset;
035: import org.cougaar.planning.ldm.asset.NewPropertyGroup;
036: import org.cougaar.planning.ldm.asset.PropertyGroup;
037: import org.cougaar.planning.ldm.measure.Area;
038: import org.cougaar.planning.ldm.measure.Distance;
039: import org.cougaar.planning.ldm.measure.Mass;
040: import org.cougaar.planning.ldm.measure.Volume;
041: import org.cougaar.glm.ldm.asset.Ammunition;
042: import org.cougaar.glm.ldm.asset.BulkPOL;
043: import org.cougaar.glm.ldm.asset.PackagedPOL;
044: import org.cougaar.glm.ldm.asset.Consumable;
045: import org.cougaar.glm.ldm.asset.NewCostPG;
046: import org.cougaar.glm.ldm.asset.NewMovabilityPG;
047: import org.cougaar.glm.ldm.asset.NewPackagePG;
048: import org.cougaar.glm.ldm.asset.NewPhysicalPG;
049: import org.cougaar.glm.ldm.asset.PropertyGroupFactory;
050: import org.cougaar.glm.ldm.asset.NewSupplyClassPG;
051: import org.cougaar.glm.ldm.QueryLDMPlugin;
052:
053: import java.math.BigDecimal;
054: import java.util.Enumeration;
055: import java.util.Hashtable;
056: import java.util.Vector;
057:
058: public class PartsPrototypeProvider extends QueryLDMPlugin {
059:
060: private static Hashtable fuelsNomenclature = initFuelsNomenclature();
061: private Hashtable propertyGroupTable = new Hashtable();
062: private LoggingService logger;
063:
064: public void setLoggingService(LoggingService logger) {
065: this .logger = logger;
066: }
067:
068: public boolean canHandle(String typeid, Class class_hint) {
069: Boolean protoProvider = (Boolean) myParams_
070: .get("PrototypeProvider");
071: if ((protoProvider == null) || (protoProvider.booleanValue())) {
072: if (class_hint == null) {
073: if (typeid.startsWith("NSN/")
074: || typeid.startsWith("DODIC/")
075: || typeid
076: .startsWith(MEIPrototypeProvider.LEVEL2)) {
077: return true;
078: } // if
079: } else {
080: String class_name = class_hint.getName();
081: if (typeid.startsWith("DODIC/")
082: && class_name.equals("Ammunition")) {
083: return true;
084: } else if (typeid.startsWith("NSN/")
085: && (class_name.equals("BulkPOL")
086: || class_name.equals("Consumable") || class_name
087: .equals("PackagedPOL"))) {
088: return true;
089: } else if (typeid
090: .startsWith(MEIPrototypeProvider.LEVEL2)
091: && (class_name
092: .equals(Level2AmmoConsumerBG.LEVEL2AMMUNITION) || class_name
093: .equals(Level2FuelConsumerBG.LEVEL2BULKPOL))) {
094: return true;
095: }
096: }// if
097: } // if
098: if (logger.isDebugEnabled()) {
099: logger.debug("CanHandle(), Unable to provider Prototype."
100: + " ProtoProvider = " + protoProvider
101: + ", typeid= " + typeid);
102: }
103: return false;
104: } // canHandle
105:
106: public Asset makePrototype(String type_name, Class class_hint) {
107: if (logger.isDebugEnabled()) {
108: logger.debug("makePrototype() for type " + type_name);
109: }
110: String class_name = null;
111: if (class_hint != null) {
112: class_name = class_hint.getName();
113: if (class_name.equals(MEIPrototypeProvider.MEI_STRING)) {
114: return null;
115: }
116: if (!(class_name.equals("Ammunition")
117: || class_name
118: .equals(Level2AmmoConsumerBG.LEVEL2AMMUNITION)
119: || class_name
120: .equals(Level2FuelConsumerBG.LEVEL2BULKPOL)
121: || class_name.equals("BulkPOL")
122: || class_name.equals("Consumable") || class_name
123: .equals("PackagedPOL"))) {
124: if (logger.isErrorEnabled()) {
125: logger
126: .error("make prototype How did we get this far?? "
127: + class_hint);
128: }
129: return null;
130: } // if
131: } // if
132:
133: // Determine the type of the prototype
134: if (class_name == null) {
135: // Check for consumable -- most common case
136: if (type_name.startsWith("NSN/")) {
137: if (fuelsNomenclature.containsKey(type_name)) {
138: class_name = "BulkPOL";
139: } else {
140: if (getPackagedPOLNSN(type_name) != null) {
141: class_name = "PackagedPOL";
142: } else {
143: class_name = "Consumable";
144: if (logger.isDebugEnabled()) {
145: logger.debug("This is a consumable");
146: }
147: } // if
148: } // if
149: } else if (type_name.startsWith("DODIC/")) {
150: class_name = "Ammunition";
151: } else if (type_name
152: .startsWith(MEIPrototypeProvider.LEVEL2)) {
153: class_name = type_name;
154: } else {
155: if (logger.isErrorEnabled()) {
156: logger
157: .error("make prototype How did we get this far?? "
158: + class_hint);
159: }
160: return null;
161: } // if
162: } // if
163:
164: String nomenclature = getNomenclature(type_name, class_name);
165: if (nomenclature == null) {
166: if (logger.isDebugEnabled()) {
167: logger
168: .debug("makePrototype() getNomenclature() FAILED to make nomenclature");
169: }
170: return null;
171: } // if
172: Asset theAsset = newAsset(type_name, class_name, nomenclature);
173: if (logger.isDebugEnabled()) {
174: logger.debug("makePrototype() made for " + theAsset);
175: }
176: return theAsset;
177: } // makePrototype
178:
179: private static Hashtable initFuelsNomenclature() {
180: Hashtable h = new Hashtable();
181: h.put("NSN/9130001601818", "MUG");
182: h.put("NSN/9130002732379", "JP5");
183: h.put("NSN/9130010315816", "JP8");
184: h.put("NSN/9140002732377", "DFM");
185: h.put("NSN/9140002865294", "DF2");
186: return h;
187: } // initFuelsNomenclature
188:
189: /**
190: * Check whether this NSN is a Packaged POL NSN,
191: * @return null if it isn't
192: **/
193: protected String getPackagedPOLNSN(String type_id) {
194:
195: String query = (String) fileParameters_.get("packagedPOLQuery");
196: String consumer_id = type_id
197: .substring(type_id.indexOf("/") + 1);
198: Vector result = null;
199: String nomen = null;
200: if (query != null) {
201: int i = query.indexOf(":nsn");
202: String q1 = query.substring(0, i) + "'" + consumer_id + "'";
203: String q2 = query.substring(i + 4, query.length());
204: query = q1 + q2;
205: try {
206: result = executeQuery(query);
207: if (result.isEmpty()) {
208: // this is fine - means the type_id is not a Packaged POL MEI
209: return null;
210: } else {
211: Object row[] = (Object[]) result.firstElement();
212: nomen = (String) row[0];
213: } // if
214: } catch (Exception ee) {
215: if (logger.isErrorEnabled()) {
216: logger
217: .error(" retrieveFromDB(), DB query failed. query= "
218: + query + "\n ERROR " + ee);
219: }
220: return null;
221: } // try
222: } // if
223: return nomen;
224: } // getPackagedPOLNSN
225:
226: protected String getNomenclature(String type_id, String type) {
227: String nomen = null;
228: if (logger.isDebugEnabled()) {
229: logger.debug("getNomenclature() for type " + type_id);
230: }
231: Vector pgs = null;
232: // skip whole query process
233: if (type.equals("BulkPOL")) {
234: NewSupplyClassPG pg = PropertyGroupFactory
235: .newSupplyClassPG();
236: pg.setSupplyClass("ClassIIIPOL");
237: pg.setSupplyType("BulkPOL");
238: pgs = new Vector();
239: pgs.add(pg);
240: propertyGroupTable.put(type_id, pgs);
241: return (String) fuelsNomenclature.get(type_id);
242: }
243:
244: String consumer_id = type_id
245: .substring(type_id.indexOf("/") + 1);
246: // create query
247: String query = null;
248: if (type.equals("Ammunition")) {
249: query = substituteNSN((String) fileParameters_
250: .get("classVData"), consumer_id);
251: if (logger.isDebugEnabled()) {
252: logger.debug("For ammo, use query " + query);
253: }
254: } else if (type.equals("Consumable")) {
255: // query = substituteNSN ((String) fileParameters_.get ("classIXData"), consumer_id);
256:
257: //// query = substituteNSN ((String) fileParameters_.get ("ConsumableArmyNSN"), consumer_id);
258:
259: // CDW: NSN for Hydraulic Fluid
260: //String my_consumer_id = "9150009857236";
261:
262: // CDW: Original query and substitute
263: query = substituteNSN((String) fileParameters_
264: .get("classIXData"), consumer_id);
265:
266: // CDW: Uses NSN for Hydraulic Fluid
267: //query = "select nomenclature, ui, price, cube, weight from header where nsn='"+my_consumer_id+"'";
268:
269: // CDW: Uses current NSN with the info for Hydraulic Fluid
270: //query = "select " + consumer_id + ", nomenclature from header where nsn='"+my_consumer_id+"'";
271:
272: if (logger.isDebugEnabled()) {
273: logger.debug("For consumable, use query " + query);
274: }
275: } else if (type.startsWith(MEIPrototypeProvider.LEVEL2)) {
276: pgs = addLevel2Pgs(type);
277: nomen = type + " asset";
278: if (pgs != null) {
279: propertyGroupTable.put(type_id, pgs);
280: }
281: return nomen;
282: } else if (type.equals("PackagedPOL")) {
283: query = substituteNSN((String) fileParameters_
284: .get("classIIIPackagedData"), consumer_id);
285: if (logger.isDebugEnabled()) {
286: logger.debug("For pack pol, use query " + query);
287: }
288: } else {
289: if (logger.isErrorEnabled()) {
290: logger.error("getNomenclature(), unrecognized type "
291: + type + " for " + consumer_id);
292: }
293: return null;
294: } // if
295:
296: // if query not found, return null
297: if (query == null) {
298: if (logger.isErrorEnabled()) {
299: logger
300: .error("getConsumableNomenclature() Query not found for "
301: + consumer_id);
302: }
303: return null;
304: } // if
305:
306: // execute query
307: Vector result;
308: try {
309: result = executeQuery(query);
310: } catch (Exception ee) {
311: if (logger.isErrorEnabled()) {
312: logger
313: .error("getConsumableNomenclature(), DB query failed. query= "
314: + query + "\n ERROR " + ee);
315: }
316: return null;
317: } // try
318: if (result.isEmpty()) {
319: // PAS not sure why, but this seems to be normal
320: if (logger.isDebugEnabled()) {
321: logger
322: .debug("getConsumableNomenclature() no result for "
323: + type_id + " using " + query);
324: }
325: return null;
326: } else {
327: if (logger.isDebugEnabled()) {
328: logger.debug("Got a result:" + result);
329: }
330: } // if
331:
332: // parse results
333: Object row[] = (Object[]) result.firstElement();
334: nomen = (String) row[0];
335:
336: if (type.equals("Ammunition")) {
337: pgs = parseAmmunitionRow(row);
338: if (logger.isDebugEnabled()) {
339: logger.debug("adding pgs for ammo");
340: }
341: } else if (type.equals("Consumable")) {
342: pgs = parseConsumableRow(row);
343: if (logger.isDebugEnabled()) {
344: logger.debug("adding pgs for consumable");
345: }
346: } else if (type.equals("PackagedPOL")) {
347: pgs = parsePackagedPOLRow(row);
348: if (logger.isDebugEnabled()) {
349: logger.debug("adding pgs for pack pol");
350: }
351: } // if
352:
353: if (pgs != null) {
354: propertyGroupTable.put(type_id, pgs);
355: } // if
356:
357: if (logger.isDebugEnabled()) {
358: logger.debug("returning nomen " + nomen);
359: }
360: return nomen;
361: } // getNomenclature
362:
363: private Vector parseConsumableRow(Object row[]) {
364: if (logger.isDebugEnabled()) {
365: logger.debug("parseConsumableRow()");
366: }
367: String unit_of_issue = (String) row[1];
368: double cost = ((BigDecimal) row[2]).doubleValue();
369: double volume = ((BigDecimal) row[3]).doubleValue();
370: double weight = ((BigDecimal) row[4]).doubleValue();
371:
372: Vector pgs = createPhysicalPGs(weight, volume, unit_of_issue);
373: PropertyGroup costpg = createCostPG(cost);
374: if (costpg != null) {
375: pgs.add(costpg);
376: } // if
377: NewSupplyClassPG supply_pg = PropertyGroupFactory
378: .newSupplyClassPG();
379: supply_pg.setSupplyClass("ClassIXRepairPart");
380: supply_pg.setSupplyType("Consumable");
381: pgs.add(supply_pg);
382: return pgs;
383: } // parseConsumableRow
384:
385: private Vector parsePackagedPOLRow(Object row[]) {
386: String unit_of_issue = (String) row[1];
387: double cost = ((BigDecimal) row[2]).doubleValue();
388: double volume = ((BigDecimal) row[3]).doubleValue();
389: double weight = ((BigDecimal) row[4]).doubleValue();
390:
391: Vector pgs = createPhysicalPGs(weight, volume, unit_of_issue);
392: PropertyGroup costpg = createCostPG(cost);
393: if (costpg != null) {
394: pgs.add(costpg);
395: }
396: NewSupplyClassPG supply_pg = PropertyGroupFactory
397: .newSupplyClassPG();
398: supply_pg.setSupplyClass("ClassIIIPOL");
399: supply_pg.setSupplyType("PackagedPOL");
400: pgs.add(supply_pg);
401: return pgs;
402: } // parsePackagedPOLRow
403:
404: private Vector addLevel2Pgs(String type) {
405: Vector pgs = new Vector();
406: NewSupplyClassPG supply_pg = PropertyGroupFactory
407: .newSupplyClassPG();
408:
409: if (type.equals(Level2AmmoConsumerBG.LEVEL2AMMUNITION)) {
410: supply_pg.setSupplyClass("ClassVAmmunition");
411: supply_pg.setSupplyType("Ammunition");
412: } else if (type.equals(Level2FuelConsumerBG.LEVEL2BULKPOL)) {
413: supply_pg.setSupplyClass("ClassIIIPOL");
414: supply_pg.setSupplyType("BulkPOL");
415: } else
416: throw new IllegalArgumentException(
417: "Don't know anything about this type :" + type);
418: pgs.add(supply_pg);
419: return pgs;
420: }
421:
422: private Vector parseAmmunitionRow(Object row[]) {
423: double weight;
424: if ((row[1]) instanceof BigDecimal) {
425: weight = ((BigDecimal) row[1]).doubleValue();
426: } else {
427: weight = ((Double) row[1]).doubleValue();
428: }
429: String cargo_cat_code = (String) row[2];
430: Vector pgs = new Vector();
431:
432: NewPhysicalPG pg = PropertyGroupFactory.newPhysicalPG();
433: pg.setMass(new Mass(weight, Mass.POUNDS));
434: pgs.add(pg);
435:
436: NewPackagePG pg2 = PropertyGroupFactory.newPackagePG();
437: pg2.setPackMass(new Mass(weight, Mass.POUNDS));
438: pgs.add(pg2);
439:
440: if (cargo_cat_code != null) {
441: NewMovabilityPG pg3 = PropertyGroupFactory
442: .newMovabilityPG();
443: pg3.setMoveable(true);
444: pg3.setCargoCategoryCode(cargo_cat_code);
445: pgs.add(pg3);
446: } // if
447: NewSupplyClassPG supply_pg = PropertyGroupFactory
448: .newSupplyClassPG();
449: supply_pg.setSupplyClass("ClassVAmmunition");
450: supply_pg.setSupplyType("Ammunition");
451: pgs.add(supply_pg);
452:
453: return pgs;
454: } // parseAmmunitionRow
455:
456: private PropertyGroup createCostPG(double cost) {
457: NewCostPG pg = PropertyGroupFactory.newCostPG();
458: // Unit Price in the header table has 2 implied decimal places
459: pg.setBreakOutCost(cost / 100.);
460:
461: return pg;
462: } // createCostPG
463:
464: private Vector createPhysicalPGs(double weight, double volume,
465: String unit_of_issue) {
466: Vector pgs = new Vector();
467: double length;
468: // Temporary fix for TOPS so that all parts have a PhysicalPG
469: if (volume == 0) {
470: volume = (double) 1;
471: } // if
472: if (weight == 0) {
473: weight = (double) 1;
474: } // if
475:
476: // Weight in the header table has 3 implied decimal places
477: weight = weight / 1000.;
478: // Volume in the header table has 4 implied decimal places
479: volume = volume / 10000.;
480: // Assuming a perfect cube until we get better data
481: length = Math.pow(volume, 1.0 / 3.0);
482: NewPhysicalPG pg = PropertyGroupFactory.newPhysicalPG();
483: pg.setFootprintArea(new Area((length * length),
484: Area.SQUARE_FEET));
485: pg.setHeight(new Distance(length, Distance.FEET));
486: pg.setLength(new Distance(length, Distance.FEET));
487: pg.setWidth(new Distance(length, Distance.FEET));
488: pg.setVolume(new Volume(volume, Volume.CUBIC_FEET));
489: pg.setMass(new Mass(weight, Mass.POUNDS));
490: pgs.add(pg);
491:
492: if (unit_of_issue != null) {
493: NewPackagePG pg2 = PropertyGroupFactory.newPackagePG();
494: pg2.setPackFootprintArea(new Area((length * length),
495: Area.SQUARE_FEET));
496: pg2.setPackHeight(new Distance(length, Distance.FEET));
497: pg2.setPackLength(new Distance(length, Distance.FEET));
498: pg2.setPackWidth(new Distance(length, Distance.FEET));
499: pg2.setPackVolume(new Volume(volume, Volume.CUBIC_FEET));
500: pg2.setPackMass(new Mass(weight, Mass.POUNDS));
501: pg2.setUnitOfIssue(new String(unit_of_issue));
502: pgs.add(pg2);
503: } // if
504:
505: return pgs;
506: } // createPhysicalPGs
507:
508: public void fillProperties(Asset anAsset) {
509: if (logger.isDebugEnabled()) {
510: logger.debug("fillProperties() for " + anAsset);
511: }
512: Vector pgs = null;
513: if ((anAsset instanceof Ammunition)
514: || (anAsset instanceof Level2Ammunition)
515: || (anAsset instanceof BulkPOL)
516: || (anAsset instanceof PackagedPOL)
517: || (anAsset instanceof Consumable)) {
518: String typeID = anAsset.getTypeIdentificationPG()
519: .getTypeIdentification();
520: pgs = (Vector) propertyGroupTable.get(typeID);
521: if (logger.isDebugEnabled()) {
522: logger.debug("typeID " + typeID);
523: }
524: } // if
525: if ((pgs != null) && !pgs.isEmpty()) {
526: if (logger.isDebugEnabled()) {
527: logger.debug("ready");
528: }
529: Enumeration pgs_enum = pgs.elements();
530: while (pgs_enum.hasMoreElements()) {
531: NewPropertyGroup pg = (NewPropertyGroup) pgs_enum
532: .nextElement();
533: anAsset.setPropertyGroup(pg);
534: if (logger.isDebugEnabled()) {
535: logger.debug("setting PG " + pg);
536: }
537: } // while
538: } // if
539: } // fillProperties
540:
541: /** Replaces the ":nsn" in the query with the actual NSN.
542: * @param q query string
543: * @param nsn actual NSN
544: * @return new query
545: **/
546: public String substituteNSN(String q, String nsn) {
547: String query = null;
548: if (q != null) {
549: int indx = q.indexOf(":nsn");
550: if (indx != -1) {
551: query = q.substring(0, indx) + "'" + nsn + "'";
552: if (q.length() > indx + 4) {
553: query += q.substring(indx + 4);
554: } // if
555: } // if
556: } // if
557: return query;
558: } // substituteNSN
559:
560: } // PartsPrototypeProvider
|