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.glm.util;
0028:
0029: import java.util.ArrayList;
0030: import java.util.Collection;
0031: import java.util.Date;
0032: import java.util.Enumeration;
0033: import java.util.HashMap;
0034: import java.util.HashSet;
0035: import java.util.Iterator;
0036: import java.util.List;
0037: import java.util.Set;
0038: import java.util.Vector;
0039:
0040: import org.cougaar.glm.GLMConst;
0041: import org.cougaar.glm.ldm.Constants;
0042: import org.cougaar.glm.ldm.asset.Ammunition;
0043: import org.cougaar.glm.ldm.asset.CargoShip;
0044: import org.cougaar.glm.ldm.asset.Consumable;
0045: import org.cougaar.glm.ldm.asset.Container;
0046: import org.cougaar.glm.ldm.asset.Convoy;
0047: import org.cougaar.glm.ldm.asset.GLMAsset;
0048: import org.cougaar.glm.ldm.asset.MovabilityPG;
0049: import org.cougaar.glm.ldm.asset.Organization;
0050: import org.cougaar.glm.ldm.asset.Person;
0051: import org.cougaar.glm.ldm.asset.PhysicalPG;
0052: import org.cougaar.glm.ldm.asset.Repairable;
0053: import org.cougaar.glm.ldm.asset.TransportationNode;
0054: import org.cougaar.glm.ldm.asset.TransportationRoute;
0055: import org.cougaar.glm.ldm.plan.GeolocLocation;
0056: import org.cougaar.lib.util.UTILAsset;
0057: import org.cougaar.lib.util.UTILPluginException;
0058: import org.cougaar.lib.util.UTILRuntimeException;
0059: import org.cougaar.planning.ldm.PlanningFactory;
0060: import org.cougaar.planning.ldm.asset.AggregateAsset;
0061: import org.cougaar.planning.ldm.asset.Asset;
0062: import org.cougaar.planning.ldm.asset.AssetGroup;
0063: import org.cougaar.planning.ldm.asset.NewItemIdentificationPG;
0064: import org.cougaar.planning.ldm.asset.NewTypeIdentificationPG;
0065: import org.cougaar.planning.ldm.asset.PropertyGroup;
0066: import org.cougaar.planning.ldm.asset.TypeIdentificationPG;
0067: import org.cougaar.planning.ldm.measure.Area;
0068: import org.cougaar.planning.ldm.measure.Distance;
0069: import org.cougaar.planning.ldm.measure.Mass;
0070: import org.cougaar.planning.ldm.measure.Volume;
0071: import org.cougaar.planning.ldm.plan.Relationship;
0072: import org.cougaar.planning.ldm.plan.RelationshipSchedule;
0073: import org.cougaar.planning.ldm.plan.Role;
0074: import org.cougaar.planning.ldm.plan.RoleSchedule;
0075: import org.cougaar.planning.ldm.plan.ScheduleElement;
0076: import org.cougaar.planning.ldm.plan.Task;
0077: import org.cougaar.util.TimeSpan;
0078: import org.cougaar.util.log.Logger;
0079:
0080: /**
0081: * This class contains utility functions for getting
0082: * Assets.
0083: */
0084:
0085: public class AssetUtil extends UTILAsset {
0086: private static String myName = "AssetUtil";
0087: private static final long BTWN_AVAIL_TOLERANCE = 3600000l;
0088: private static double MAX_CUBIC_FT = 1.0d;
0089: private static double MAX_SQ_FT = 1.0d;
0090: public static final Role CARGO_PORT_ROLE = GLMConst.GENERIC_SEA_PORT;
0091: public static final Role AMMO_PORT_ROLE = GLMConst.AMMUNITION_SEA_PORT;
0092: public static final Role AMMO_PORT_ROLE_ALT = GLMConst.AMMO_SEA_PORT;
0093:
0094: public AssetUtil(Logger logger) {
0095: super (logger);
0096: glmPrepHelper = new GLMPrepPhrase(logger);
0097: glmPrefHelper = new GLMPreference(logger);
0098: measureHelper = new GLMMeasure(logger);
0099: }
0100:
0101: public final Convoy makeConvoy(PlanningFactory root, String uniqueID) {
0102: Convoy convoy = null;
0103: try {
0104: NewTypeIdentificationPG p1 = null;
0105:
0106: convoy = (Convoy) root.createAsset(Class
0107: .forName("org.cougaar.glm.ldm.asset.Convoy"));
0108: p1 = (NewTypeIdentificationPG) convoy
0109: .getTypeIdentificationPG();
0110: p1.setTypeIdentification("TOPS_CONVOY");
0111: p1.setNomenclature("Convoy");
0112: ((NewItemIdentificationPG) convoy.getItemIdentificationPG())
0113: .setItemIdentification(uniqueID);
0114: } catch (Exception e) {
0115: throw new UTILRuntimeException(e.getMessage());
0116: }
0117: return (convoy);
0118: }
0119:
0120: /**
0121: * These control how big something must be before it is made into
0122: * distinct assets instead of remaining within an aggregate asset.
0123: */
0124:
0125: public void setMaxCubicFt(double max) {
0126: MAX_CUBIC_FT = max;
0127: }
0128:
0129: public void setMaxSqFt(double max) {
0130: MAX_SQ_FT = max;
0131: }
0132:
0133: /**
0134: * Utility method for finding organization/cluster assets.
0135: * @param assets the Enumeration of assets received from the asset container
0136: * @param desiredRole a string describing the capable role of an organization
0137: * the string is defined in the mycluster-prototype-ini.dat file in
0138: * the topsconfig directory.
0139: * @return Organization that has the role described in desiredRole
0140: */
0141: public Organization getOrgAsst(Iterator assets, String desiredRole) {
0142: while (assets.hasNext()) {
0143: Asset resource = (Asset) assets.next();
0144: if (resource instanceof Organization) {
0145: Organization org = (Organization) resource;
0146: if (org.isSelf()) {
0147: RelationshipSchedule schedule = org
0148: .getRelationshipSchedule();
0149:
0150: Collection orgCollection = schedule
0151: .getMatchingRelationships(Role
0152: .getRole(desiredRole));
0153: if (!orgCollection.isEmpty()) {
0154: Relationship rel = (Relationship) orgCollection
0155: .iterator().next();
0156: Organization o = (Organization) schedule
0157: .getOther(rel);
0158: return o;
0159: }
0160: }
0161: }
0162: }
0163: return null;
0164: }
0165:
0166: /**
0167: * Utility method for finding organization/cluster assets.
0168: * @param assets the Enumeration of assets received from the asset container
0169: * @param desiredRole a string describing the capable role of an organization
0170: * the string is defined in the mycluster-prototype-ini.dat file in
0171: * the topsconfig directory.
0172: * @return Organization that has the role described in desiredRole
0173: */
0174: public List getOrgAssts(Iterator assets, String desiredRole) {
0175: ArrayList orgs = new ArrayList();
0176: while (assets.hasNext()) {
0177: Asset resource = (Asset) assets.next();
0178: if (resource instanceof Organization) {
0179: Organization org = (Organization) resource;
0180: if (org.isSelf()) {
0181: RelationshipSchedule schedule = org
0182: .getRelationshipSchedule();
0183:
0184: Collection orgCollection = schedule
0185: .getMatchingRelationships(Role
0186: .getRole(desiredRole));
0187: if (!orgCollection.isEmpty()) {
0188: for (Iterator i = orgCollection.iterator(); i
0189: .hasNext();) {
0190: Relationship rel = (Relationship) i.next();
0191: Organization o = (Organization) schedule
0192: .getOther(rel);
0193: orgs.add(o);
0194:
0195: }
0196: return orgs;
0197: }
0198: }
0199: }
0200: }
0201: return null;
0202: }
0203:
0204: /**
0205: * get the GeolocoLocation of an organization
0206: * @param o the organization
0207: */
0208: public GeolocLocation getOrgLocation(Organization o) {
0209: GeolocLocation geoloc;
0210:
0211: try {
0212: geoloc = (GeolocLocation) o.getMilitaryOrgPG()
0213: .getHomeLocation();
0214: } catch (NullPointerException e) {
0215: throw new UTILPluginException(
0216: "no military org property for organization" + " ("
0217: + o + ")");
0218: }
0219:
0220: return geoloc;
0221: }
0222:
0223: /**
0224: * creates a HashMap of organizations with their geolocCodes as keys.
0225: * @param organizations the en of organizations to be put in the hashmap
0226: * @return HashMap the newly constructed table with geolocCodes as keys,
0227: * and the corresponding organization as object.
0228: */
0229:
0230: public HashMap orgAssetLocation(List organizations) {
0231: HashMap orgAssetTable = new HashMap();
0232: // while (organizations.hasMoreElements()){
0233: for (Iterator iterator = organizations.iterator(); iterator
0234: .hasNext();) {
0235: Organization org = (Organization) iterator.next();
0236: String geolocCode = getOrgLocation(org).getGeolocCode();
0237: List orgsAtGeoLoc;
0238: if ((orgsAtGeoLoc = (List) orgAssetTable.get(geolocCode)) == null) {
0239: orgsAtGeoLoc = new ArrayList();
0240: orgAssetTable.put(geolocCode, orgsAtGeoLoc);
0241: }
0242: orgsAtGeoLoc.add(org);
0243: }
0244: return orgAssetTable;
0245: }
0246:
0247: /**
0248: * Finds the organization with the given geolocCode in the given table.
0249: * @param table the table to search
0250: * @param geolocCode the string to search for
0251: * @return Organization the organization with the geolocCode.
0252: */
0253:
0254: public Organization getOrg(HashMap table, String geolocCode) {
0255: return ((Organization) ((List) table.get(geolocCode)).get(0));
0256: }
0257:
0258: public List getOrgList(HashMap table, String geolocCode) {
0259: return ((List) table.get(geolocCode));
0260: }
0261:
0262: public boolean hasOrg(HashMap table, String geolocCode) {
0263: return (getOrgList(table, geolocCode) != null);
0264: }
0265:
0266: /**
0267: * This call gets oneself as an organization asset.
0268: * @param clusterAssets the En of assets received from the asset container
0269: * @return Organization which represents current cluster
0270: */
0271: public Organization getSelf(Enumeration clusterAssets) {
0272: Organization myself = null;
0273: while (clusterAssets.hasMoreElements()) {
0274: Asset a = (Asset) clusterAssets.nextElement();
0275: if ((a instanceof Organization)
0276: && (((Organization) a).isSelf())) {
0277: myself = (Organization) a;
0278: break;
0279: }
0280: }
0281: if (myself == null) {
0282: throw new UTILPluginException(
0283: "can't find myself as clusterAsset");
0284: }
0285: return myself;
0286: }
0287:
0288: /**
0289: * check to see if an asset represents a consumable
0290: * @param asset the asset to check
0291: * @return boolean
0292: */
0293: public boolean isConsumable(Asset asset) {
0294: if (asset instanceof AggregateAsset) {
0295: return isConsumable(((AggregateAsset) asset).getAsset());
0296: }
0297: return (asset instanceof Consumable);
0298: }
0299:
0300: /**
0301: * check to see if an asset represents a repairable
0302: * @param asset the asset to check
0303: * @return boolean
0304: */
0305: public boolean isRepairable(Asset asset) {
0306: if (asset instanceof AggregateAsset) {
0307: return isRepairable(((AggregateAsset) asset).getAsset());
0308: }
0309: return (asset instanceof Repairable);
0310: }
0311:
0312: /**
0313: * check to see if an asset represents a passenger
0314: * @param asset the asset to check
0315: * @return boolean
0316: */
0317: public boolean isPassenger(Asset asset) {
0318: if (asset instanceof AggregateAsset) {
0319: return isPassenger(((AggregateAsset) asset).getAsset());
0320: } else if (asset instanceof Person) {
0321: return true;
0322: }
0323:
0324: TypeIdentificationPG typeofasset = null;
0325: typeofasset = asset.getTypeIdentificationPG();
0326: if (typeofasset == null) {
0327: throw new UTILPluginException(
0328: "bad type identification property: \"" + asset
0329: + "\"");
0330: }
0331: String nom = typeofasset.getTypeIdentification();
0332: if (nom == null) {
0333: throw new UTILPluginException("bad type identification: \""
0334: + asset + "\"");
0335: }
0336: return (nom.equals("OTHER/Passenger")
0337: || nom.equals("OTHER/People") || nom
0338: .equals("OTHER/person"));
0339: }
0340:
0341: /**
0342: * check to see if an asset represents a Pallet
0343: * @param asset the asset to check
0344: * @return boolean
0345: */
0346: public boolean isPallet(Asset asset) {
0347: if (asset instanceof AggregateAsset) {
0348: return isPallet(((AggregateAsset) asset).getAsset());
0349: }
0350:
0351: if ((asset instanceof Container)
0352: || (asset instanceof org.cougaar.glm.ldm.asset.Package)) {
0353: TypeIdentificationPG typeofasset = null;
0354: typeofasset = asset.getTypeIdentificationPG();
0355: if (typeofasset == null) {
0356: throw new UTILPluginException(
0357: "bad type identification property: \"" + asset
0358: + "\"");
0359: }
0360: String nom = typeofasset.getTypeIdentification();
0361: if (nom == null) {
0362: throw new UTILPluginException(
0363: "bad type identification: \"" + asset + "\"");
0364: }
0365: if (nom.equals("TOPS_PALLET"))
0366: throw new UTILPluginException(
0367: "AssetUtil.isPallet - found TOPS_PALLET. "
0368: + "Please use PALLET from Container protos instead!");
0369: //!!!Hack for AEF...until we figure out the TypeIdentification/Nomenclature problem on AEF's end.
0370: if ((nom.indexOf("463L") != -1))
0371: return true;
0372: return (nom.equals("OTHER/Air_Pallet")
0373: || nom.equals("PALLET") || nom.equals("463L PLT"));
0374: }
0375: return false;
0376: }
0377:
0378: /**
0379: * check to see if an asset represents ammo
0380: *
0381: * works with an aggregate asset too.
0382: *
0383: * Something is ammo it's an instance of org.cougaar.glm.ldm.asset.Ammunition OR
0384: * The type identification PG's nomenclature is Ammunition
0385: *
0386: * @see org.cougaar.glm.ldm.asset.Ammunition
0387: * @param asset the asset to check
0388: * @return boolean
0389: */
0390: public boolean isAmmo(Asset asset) {
0391:
0392: if (asset instanceof AssetGroup) {
0393: Vector assetVector = ((AssetGroup) asset).getAssets();
0394: boolean ammo = false;
0395: for (int i = 0; i < assetVector.size(); i++) {
0396: boolean currentAsset = isAmmo((Asset) assetVector
0397: .elementAt(i));
0398: if (((ammo == true) && (currentAsset == false))
0399: || ((ammo == false && i > 0) && (currentAsset == true))) {
0400: throw new UTILRuntimeException(
0401: "Couldn't handle AssetGroup containing Ammo and non-Ammo!");
0402: }
0403: ammo = currentAsset;
0404: }
0405: }
0406: boolean ammo = false;
0407:
0408: if (asset instanceof AggregateAsset)
0409: return isAmmo(((AggregateAsset) asset).getAsset());
0410:
0411: if (asset instanceof Ammunition)
0412: return true;
0413:
0414: if (asset instanceof AssetGroup) {
0415: Vector vector = (Vector) ((AssetGroup) asset).getAssets();
0416: return isAmmo((Asset) vector.elementAt(0));
0417: }
0418:
0419: MovabilityPG mpg = (MovabilityPG) ((GLMAsset) asset)
0420: .getMovabilityPG();
0421: if (mpg != null) {
0422: String code = mpg.getCargoCategoryCode();
0423: if (code != null && CargoCategoryDecoder.isAmmo(code))
0424: return true;
0425: }
0426:
0427: TypeIdentificationPG typeofasset = null;
0428: typeofasset = asset.getTypeIdentificationPG();
0429: if (typeofasset == null) {
0430: throw new UTILPluginException(
0431: "bad type identification property: \"" + asset
0432: + "\"");
0433: }
0434: String nom = typeofasset.getTypeIdentification();
0435: if (nom == null) {
0436: throw new UTILPluginException("bad type identification: \""
0437: + asset + "\"");
0438: }
0439: return (nom.equals("Ammunition"));
0440: }
0441:
0442: /**
0443: * <pre>
0444: * See if a task is a prepo task (i.e.
0445: * already packed in a ship hanging arround
0446: * in the middle of the ocean somewhere).
0447: *
0448: * The check is made to see if the task has a WITH
0449: * preposition.
0450: * We look up the ship referred to by the String (Ship ID)
0451: * in GlobalSea, where the ships are owned.
0452: *
0453: * </pre>
0454: * @param t task to check
0455: * @return boolean
0456: */
0457: public boolean isPrepoTask(Task t) {
0458: if (glmPrepHelper.hasPrepNamed(t, Constants.Preposition.WITH)) {
0459: Object o = glmPrepHelper.getIndirectObject(t,
0460: Constants.Preposition.WITH);
0461: return o instanceof CargoShip || o instanceof String;
0462: }
0463: return false;
0464: }
0465:
0466: /**
0467: * <pre>
0468: * convert an AssetGroup/AggregateAsset into it's component assets,
0469: * recursing through any contained AssetGroup/AggregateAssets as
0470: * needed.
0471: *
0472: * Note : Convoys are AssetGroups, so the contents of the convoy
0473: * will also appear on the result list.
0474: *
0475: * Will take an aggregate asset and create new instances that are
0476: * copies of the asset of the aggregation. These will have
0477: * item id's like "xxx-7_of_9_from_yyy", where xxx is the original id,
0478: * the quantity of the aggregate asset is 9, and yyy is the number of times
0479: * this method has been called. Yes, you might ask, why not use the
0480: * aggregate's UID? Well this seems to be null. Why not the agg's asset?
0481: * Well, this is just a prototype, so two different aggregations will
0482: * have the same asset, giving us the same UID.
0483: *
0484: * This allows the receipt of two aggregates of the same type of object
0485: * creating distinct subobjects. Otherwise a M1A1-7_of_9 from one aggregate
0486: * would be equals() and hashcode() equal to a M1A1-7_of_9 from another.
0487: * This is needed since now Assets are equal on the basis of type and item
0488: * PG equality. (01/23/99 GWFV)
0489: *
0490: * Will not break up aggregate
0491: * assets where the items are smaller than one cubic foot.
0492: *
0493: * </pre>
0494: * @param asset AssetGroup/AggreateAsset to divide
0495: * @return Vector of sub-objects
0496: */
0497: public Vector ExpandAsset(PlanningFactory theFactory, Asset asset) {
0498: Vector retval = new Vector();
0499:
0500: if (asset instanceof AssetGroup) {
0501: AssetGroup group = (AssetGroup) asset;
0502: Vector subobjects = group.getAssets();
0503:
0504: for (int i = 0; i < subobjects.size(); i++) {
0505: Object subobject = subobjects.elementAt(i);
0506: if (subobject instanceof AssetGroup
0507: || subobject instanceof AggregateAsset) {
0508: Vector moreboxes = ExpandAsset(theFactory,
0509: (Asset) subobject);
0510: for (int j = 0; j < moreboxes.size(); j++)
0511: retval.addElement(moreboxes.elementAt(j));
0512: } else {
0513: retval.addElement(subobject);
0514: }
0515: }
0516: } else if (asset instanceof AggregateAsset) {
0517: AggregateAsset aggregate = (AggregateAsset) asset;
0518:
0519: long count = aggregate.getQuantity();
0520: Asset subobject = (Asset) aggregate.getAsset();
0521: if (subobject instanceof AggregateAsset
0522: || subobject instanceof AssetGroup) {
0523: for (long i = 0; i < count; i++) {
0524: Vector evenmoreboxes = ExpandAsset(theFactory,
0525: (Asset) subobject);
0526: for (int j = 0; j < evenmoreboxes.size(); j++)
0527: retval.addElement(evenmoreboxes.elementAt(j));
0528: }
0529: } else if (subobject instanceof Asset) {
0530: boolean tooBig = false;
0531:
0532: PhysicalPG ppg = (PhysicalPG) ((GLMAsset) subobject)
0533: .getPhysicalPG();
0534: if (ppg != null) {
0535: try {
0536: Volume vol = ppg.getVolume();
0537: Area area = ppg.getFootprintArea();
0538:
0539: if ((vol.getCubicFeet() > MAX_CUBIC_FT)
0540: || (area.getSquareFeet() > MAX_SQ_FT))
0541: tooBig = true;
0542: } catch (Exception e) {
0543: logger.warn("AssetUtil.ExpandAsset - ERROR : "
0544: + "aggregate asset\n\t" + aggregate
0545: + "\n\thas asset\n\t" + subobject
0546: + "\n\tthat has no physicalPG.");
0547: }
0548: }
0549: if (tooBig) {
0550: synchronized (this ) {
0551: for (long i = 0; i < count; i++) {
0552: String name = getTypeName(subobject);
0553: if (name.length() > 10)
0554: name = name.substring(0, 9) + "...";
0555:
0556: name = name + "-" + (i + 1) + "_of_"
0557: + count + "(" + getLatestUID()
0558: + ")";
0559: Asset particle = theFactory.createInstance(
0560: subobject, name);
0561: Enumeration otherProps = asset
0562: .getOtherProperties();
0563: while (otherProps.hasMoreElements()) {
0564: particle
0565: .addOtherPropertyGroup((PropertyGroup) otherProps
0566: .nextElement());
0567: }
0568: retval.addElement(particle);
0569: }
0570: }
0571: } else
0572: retval.addElement(asset);
0573: } else {
0574: logger.error("AssetUtil.ExpandAsset - ERROR : "
0575: + "aggregate asset\n\t" + aggregate
0576: + "\n\thas asset\n\t" + subobject
0577: + "\n\tthat is not an Asset.");
0578: retval.addElement(asset);
0579: }
0580: } else {
0581: retval.addElement(asset);
0582: }
0583:
0584: return retval;
0585: }
0586:
0587: protected int latestUID = 0;
0588:
0589: protected synchronized int getLatestUID() {
0590: if (latestUID == Integer.MAX_VALUE)
0591: latestUID = 0;
0592: return ++latestUID;
0593: }
0594:
0595: /**
0596: * get the total Area of an asset regardless of whether it's
0597: * an Asset, AssetGroup, AggregateAsset, or whatever
0598: * @param asset the asset
0599: * @return Area the total area of the asset
0600: */
0601: public Area totalArea(Asset asset) {
0602: return totalArea(asset, false);
0603: }
0604:
0605: /**
0606: * get the total Area of an asset regardless of whether it's
0607: * an Asset, AssetGroup, AggregateAsset, or whatever
0608: * BUT adjusted for the peculiar semantics of asset handling in GlobalSea
0609: * >Vehicles only have footprint area
0610: * >Containers only have volume
0611: *
0612: * @param asset the asset
0613: * @return Area the total area of the asset
0614: */
0615: public Area totalAdjustedArea(Asset asset) {
0616: return totalArea(asset, true);
0617: }
0618:
0619: public Area totalArea(Asset asset, boolean ignoreContainers) {
0620: if (asset instanceof AggregateAsset) {
0621: AggregateAsset aggAsset = (AggregateAsset) asset;
0622: double qty = aggAsset.getQuantity();
0623:
0624: if (qty <= 0)
0625: throw new UTILPluginException(
0626: "got bad qty for Aggregate Asset: \"" + asset
0627: + "\"");
0628:
0629: asset = aggAsset.getAsset();
0630:
0631: if (asset == null)
0632: throw new UTILPluginException(
0633: "Got null asset in Aggregate Asset");
0634:
0635: double area = getArea(asset).getSquareFeet();
0636: return Area.newSquareFeet(qty * area);
0637: } else if (asset instanceof AssetGroup) {
0638: double d = 0.0d;
0639: Vector subassets = ((AssetGroup) asset).getAssets();
0640: for (int i = 0; i < subassets.size(); i++)
0641: d += totalArea((Asset) subassets.elementAt(i))
0642: .getSquareFeet();
0643:
0644: return Area.newSquareFeet(d);
0645: }
0646:
0647: if (ignoreContainers)
0648: return isVehicleOrAircraft(asset) ? getArea(asset) : Area
0649: .newSquareFeet(0.0d);
0650:
0651: return getArea(asset);
0652: }
0653:
0654: private Area getArea(Asset asset) {
0655: PhysicalPG prop = null;
0656: try {
0657: prop = (PhysicalPG) ((GLMAsset) asset).getPhysicalPG();
0658: } catch (Exception e) {
0659: throw new UTILPluginException(
0660: "error getting physical property for asset :\""
0661: + asset + "\"");
0662: }
0663: Area area;
0664: try {
0665: area = prop.getFootprintArea();
0666: } catch (Exception e) {
0667: throw new UTILPluginException(
0668: "No Physical property set for asset: \"" + asset
0669: + "\"");
0670: }
0671: if (area == null) {
0672: throw new UTILPluginException(
0673: "Got null footprint area in asset: \"" + asset
0674: + "\"");
0675: }
0676: return area;
0677: }
0678:
0679: /**
0680: * get the total Volume of an asset
0681: * ( regardless of whether it's
0682: * an Asset, AssetGroup, AggregateAsset, or whatever)
0683: * @param asset the asset
0684: * @return Volume the total volume of the asset
0685: */
0686: public Volume totalVolume(Asset asset) {
0687: return totalVolume(asset, false);
0688: }
0689:
0690: /**
0691: * get the total Volume of an asset
0692: * ( regardless of whether it's
0693: * an Asset, AssetGroup, AggregateAsset, or whatever)
0694: * @param asset the asset
0695: * @return Volume the total volume of the asset
0696: */
0697: public Volume totalAdjustedVolume(Asset asset) {
0698: return totalVolume(asset, true);
0699: }
0700:
0701: public Volume totalVolume(Asset asset,
0702: boolean ignoreVehiclesAndContainers) {
0703: if (asset instanceof AggregateAsset) {
0704: AggregateAsset aggAsset = (AggregateAsset) asset;
0705: double qty = aggAsset.getQuantity();
0706:
0707: if (qty <= 0)
0708: throw new UTILPluginException(
0709: "got bad qty for Aggregate Asset: \"" + asset
0710: + "\"");
0711:
0712: asset = aggAsset.getAsset();
0713:
0714: if (asset == null)
0715: throw new UTILPluginException(
0716: "Got null asset in Aggregate Asset");
0717:
0718: double m3perasset = totalVolume(asset,
0719: ignoreVehiclesAndContainers).getCubicMeters();
0720: return Volume.newCubicMeters(qty * m3perasset);
0721: } else if (asset instanceof AssetGroup) {
0722: double d = 0.0d;
0723: Vector subassets = ((AssetGroup) asset).getAssets();
0724: for (int i = 0; i < subassets.size(); i++)
0725: d += totalVolume((Asset) subassets.elementAt(i),
0726: ignoreVehiclesAndContainers).getCubicMeters();
0727:
0728: return Volume.newCubicMeters(d);
0729: }
0730:
0731: if (ignoreVehiclesAndContainers)
0732: return (!isVehicleOrAircraft(asset) && !isStandardContainer(asset)) ? getVolume(asset)
0733: : Volume.newCubicMeters(0.0d);
0734:
0735: return getVolume(asset);
0736: }
0737:
0738: private Volume getVolume(Asset asset) {
0739: PhysicalPG prop = null;
0740: try {
0741: prop = (PhysicalPG) ((GLMAsset) asset).getPhysicalPG();
0742: } catch (Exception e) {
0743: throw new UTILPluginException(
0744: "error getting physical property for asset :\""
0745: + asset + "\"");
0746: }
0747:
0748: Volume vol;
0749: try {
0750: vol = prop.getVolume();
0751: } catch (Exception e) {
0752: throw new UTILPluginException(
0753: "No Physical property set for asset: \"" + asset
0754: + "\"");
0755: }
0756: if (vol == null) {
0757: throw new UTILPluginException(
0758: "Got null volume in asset: \"" + asset + "\"");
0759: }
0760: return vol;
0761: }
0762:
0763: /**
0764: * get the total Mass of an asset
0765: * ( regardless of whether it's
0766: * an Asset, AssetGroup, AggregateAsset, or whatever)
0767: * @param asset the asset
0768: * @return Mass the total mass of the asset
0769: */
0770:
0771: public Mass totalMass(Asset asset) {
0772: if (asset instanceof AggregateAsset) {
0773: AggregateAsset aggAsset = (AggregateAsset) asset;
0774: double qty = aggAsset.getQuantity();
0775:
0776: if (qty <= 0)
0777: throw new UTILPluginException(
0778: "got bad qty for Aggregate Asset: \"" + asset
0779: + "\"");
0780:
0781: asset = aggAsset.getAsset();
0782:
0783: if (asset == null)
0784: throw new UTILPluginException(
0785: "Got null asset in Aggregate Asset");
0786:
0787: double tonsperasset = totalMass(asset).getTons();
0788: return Mass.newTons(qty * tonsperasset);
0789: } else if (asset instanceof AssetGroup) {
0790: double d = 0.0d;
0791: Vector subassets = ((AssetGroup) asset).getAssets();
0792: for (int i = 0; i < subassets.size(); i++)
0793: d += totalMass((Asset) subassets.elementAt(i))
0794: .getTons();
0795:
0796: return Mass.newTons(d);
0797: }
0798:
0799: return getMass(asset);
0800: }
0801:
0802: private Mass getMass(Asset asset) {
0803: PhysicalPG prop = null;
0804: try {
0805: prop = (PhysicalPG) ((GLMAsset) asset).getPhysicalPG();
0806: } catch (Exception e) {
0807: throw new UTILPluginException(
0808: "error getting physical property for asset :\""
0809: + asset + "\"");
0810: }
0811:
0812: Mass mass;
0813: try {
0814: mass = prop.getMass();
0815: } catch (Exception e) {
0816: throw new UTILPluginException(
0817: "No Physical property set for asset: \"" + asset
0818: + "\"");
0819: }
0820: if (mass == null) {
0821: throw new UTILPluginException("Got null mass in asset: \""
0822: + asset + "\"");
0823: }
0824: return mass;
0825: }
0826:
0827: public long totalContainers(Asset asset) {
0828: if (asset instanceof AggregateAsset) {
0829: AggregateAsset aggAsset = (AggregateAsset) asset;
0830: double qty = aggAsset.getQuantity();
0831:
0832: if (qty <= 0)
0833: throw new UTILPluginException(
0834: "got bad qty for Aggregate Asset: \"" + asset
0835: + "\"");
0836:
0837: asset = aggAsset.getAsset();
0838:
0839: if (asset == null)
0840: throw new UTILPluginException(
0841: "Got null asset in Aggregate Asset");
0842:
0843: if (isStandardContainer(asset))
0844: return (long) qty;
0845: else
0846: return 0l;
0847: } else if (asset instanceof AssetGroup) {
0848: long d = 0l;
0849: Vector subassets = ((AssetGroup) asset).getAssets();
0850: for (int i = 0; i < subassets.size(); i++)
0851: if (isStandardContainer((Asset) subassets.elementAt(i)))
0852: d++;
0853: return d;
0854: }
0855: return isStandardContainer(asset) ? 1 : 0;
0856: }
0857:
0858: /**
0859: * helper function, gets the total square feet footprint of an asset
0860: * ( regardless of whether it's
0861: * an Asset, AssetGroup, AggregateAsset, or whatever)
0862: * @param asset the asset
0863: * @return double the area of the asset in sqr. ft.
0864: */
0865: public double totalSquareFeet(Asset asset) {
0866: double area = totalArea(asset).getSquareFeet();
0867: if (area < 0) {
0868: throw new UTILPluginException("Got bad area in asset: \""
0869: + asset + "\"");
0870: }
0871: return area;
0872: }
0873:
0874: /**
0875: * helper function, gets the total volume of an asset
0876: * ( regardless of whether it's
0877: * an Asset, AssetGroup, AggregateAsset, or whatever)
0878: * @param asset the asset
0879: * @return double the volume of the asset in cubic meters
0880: */
0881: public double totalCubicMeters(Asset asset) {
0882: double vol = totalVolume(asset).getCubicMeters();
0883: if (vol < 0) {
0884: throw new UTILPluginException("Got bad volume in asset: \""
0885: + asset + "\"");
0886: }
0887: return vol;
0888: }
0889:
0890: /**
0891: * helper function, gets the total mass of an asset
0892: * ( regardless of whether it's
0893: * an Asset, AssetGroup, AggregateAsset, or whatever)
0894: * @param asset the asset
0895: * @return double the mass of the asset in cubic meters
0896: */
0897: public double totalTons(Asset asset) {
0898: double mass = totalMass(asset).getTons();
0899: if (mass < 0) {
0900: throw new UTILPluginException("Got bad weight in asset: \""
0901: + asset + "\"");
0902: }
0903: return mass;
0904: }
0905:
0906: /**
0907: * Necessary for accurate ship location computation.
0908: * NOTE that travel isn't taken into account in that if the time specified
0909: * is in the middle of the time when the asset is traveling between tasks,
0910: * the position reported will be the end of the last task. This is as intended.
0911: *
0912: * If the time specified is in the middle of a task, we interpolate. (!!FIXIT!!)
0913: *
0914: * @return GeolocLocation representing the current position of the asset
0915: * at the time specified. returns null if none found
0916: */
0917: public GeolocLocation getMostRecentKnownPosition(Asset a, Date time) {
0918: RoleSchedule rs = a.getRoleSchedule();
0919:
0920: // The task immediately previous (possibly including) now
0921: Task most_recent_task = findClosestRoleScheduleTask(rs, time,
0922: true/*previous tasks*/);
0923:
0924: if (most_recent_task == null) {
0925:
0926: // System.err.println("AssetUtil.getCurrentPosition for asset " +
0927: // a.getUID() + " at time " + time +
0928: // " found no previous tasks");
0929: return null;
0930: }
0931:
0932: if (prefHelper.getLateDate(most_recent_task).after(time))
0933: return glmPrepHelper.getFromLocation(most_recent_task);
0934: /*
0935: {
0936: // If the last one overlaps the time, we need to interpolate
0937: GeolocLocation start = glmPrepHelper.getFromLocation(most_recent_task);
0938: GeolocLocation end = glmPrepHelper.getToLocation(most_recent_task);
0939: }
0940: */
0941:
0942: return glmPrepHelper.getToLocation(most_recent_task);
0943: }
0944:
0945: /**
0946: * Check to see if the task fits in the role schedule of the asset.
0947: * DON'T perform any allocation, assignment, etc. just check for
0948: * enough space.
0949: * FOR NOW, (!!FIXIT!!) we're assuming the ship is EMPTY unless
0950: * fully allocated, i.e. you have to manage the loading yourself
0951: * without actually adding something on the ship until you add
0952: * everything in one big block. You can actually get into the guts
0953: * of the asset and check the role schedule for yourself if you really
0954: * want to, but it's kind of ugly.
0955: *
0956: * There are two possible legal cases (i.e. no nulls or other errors) in
0957: * which this method will return false: the role schedule doesn't have
0958: * availability for a task, or the role schedule already has plan elements
0959: * in the time window where we want the task to fit that make the schedule
0960: * unfeasible.
0961: */
0962: public boolean checkTaskAgainstRoleSchedule(Asset a, Task t) {
0963: boolean taskOK = false;
0964:
0965: GeolocLocation t_start_loc = (GeolocLocation) t
0966: .getPrepositionalPhrase(Constants.Preposition.FROM)
0967: .getIndirectObject();
0968: // We assume the VIA is irrelevant
0969: GeolocLocation t_end_loc = (GeolocLocation) t
0970: .getPrepositionalPhrase(Constants.Preposition.TO)
0971: .getIndirectObject();
0972:
0973: Date t_start_time = prefHelper.getReadyAt(t);
0974: Date t_end_time = prefHelper.getLateDate(t);
0975:
0976: // We need to make sure a) the asset is available in this time window
0977: // b) the asset can get to the start location by the start time and
0978: // c) the asset can get to its next commitment after the end time
0979: RoleSchedule a_rs = a.getRoleSchedule();
0980:
0981: // Note that these aren't really the start and end of the travel of the
0982: // asset, they're the tasks that the asset can start travel at the EARLIEST
0983: // and the date by which the asset must at the LATEST be somewhere else.
0984: Task t_start_trvl_task = findClosestRoleScheduleTask(a_rs,
0985: t_start_time, true); // Check earlier
0986: Task t_end_trvl_task = findClosestRoleScheduleTask(a_rs,
0987: t_end_time, false); // Check later
0988:
0989: // First check is to make sure the transport asset for this mission can
0990: // get where it needs to be on time (NOTE - this prefers the status quo,
0991: // i.e. tasks already allocated get preference. is that ok?)
0992: // Should we be robust for nulls here?
0993: Distance start_d = measureHelper.distanceBetween(
0994: (GeolocLocation) t_start_trvl_task
0995: .getPrepositionalPhrase(
0996: Constants.Preposition.TO)
0997: .getIndirectObject(), t_start_loc);
0998: // Date t_start_trvl = new Date(t_start_time.getTime() -
0999: // travelTimeUsingAsset(start_d,a));
1000:
1001: long t_start_trvl = (t_start_time.getTime() - travelTimeUsingAsset(
1002: start_d, a));
1003:
1004: // if (t_start_trvl.before(prefHelper.getLateDate(t_start_trvl_task))) {
1005: if (t_start_trvl < (prefHelper.getLateDate(t_start_trvl_task)
1006: .getTime())) {
1007: //System.err.println("Could not get to start in time using this mission");
1008: taskOK = false;
1009: return taskOK;
1010: }
1011:
1012: Distance end_d = measureHelper.distanceBetween(t_end_loc,
1013: (GeolocLocation) t_end_trvl_task
1014: .getPrepositionalPhrase(
1015: Constants.Preposition.FROM)
1016: .getIndirectObject());
1017: // Date t_end_trvl = new Date(t_end_time.getTime() +
1018: // travelTimeUsingAsset(end_d,a));
1019: long t_end_trvl = (t_end_time.getTime() + travelTimeUsingAsset(
1020: end_d, a));
1021:
1022: // if (prefHelper.getReadyAt(t_end_trvl_task).before(t_end_trvl)) {
1023: if (prefHelper.getReadyAt(t_end_trvl_task).getTime() < (t_end_trvl)) {
1024: //System.err.println("Could not get to next task in time using this mission");
1025: taskOK = false;
1026: return taskOK;
1027: }
1028:
1029: // get a container of plan elements that have dates in the
1030: // given range
1031: Collection rs_avail_elts = a_rs.getOverlappingRoleSchedule(
1032: t_start_trvl, t_end_trvl);
1033:
1034: // if the above query returns anything, that means that we can't insert
1035: // the task because it would overlap an already-existing block
1036: if (rs_avail_elts.size() != 0) {
1037: taskOK = false;
1038: return taskOK;
1039: }
1040:
1041: // make sure we have availability throughout the time range of the task
1042: Collection avail_s = a_rs.getAvailableSchedule()
1043: .getOverlappingScheduleElements(t_start_trvl,
1044: t_end_trvl);
1045:
1046: Iterator avail_iter = avail_s.iterator();
1047:
1048: // Date last_date_checked = t_start_trvl;
1049: long last_date_checked = t_start_trvl;
1050: while (avail_iter.hasNext()) {
1051: ScheduleElement next_se = (ScheduleElement) avail_iter
1052: .next();
1053:
1054: if (!(next_se.included(last_date_checked))) {
1055: taskOK = false;
1056: return taskOK;
1057: }
1058: if (next_se.included(t_end_trvl)) {
1059: taskOK = true;
1060: return taskOK;
1061: } else {
1062: // last_date_checked = new Date(next_se.getEndDate().getTime() +
1063: // BTWN_AVAIL_TOLERANCE);
1064: last_date_checked = next_se.getEndDate().getTime()
1065: + BTWN_AVAIL_TOLERANCE;
1066: }
1067: }
1068:
1069: return taskOK;
1070: }
1071:
1072: // !!FIXIT!! Hack!
1073: /**
1074: * Utility method to return the approximate time the given asset requires
1075: * to go Distance d
1076: */
1077: private long travelTimeUsingAsset(Distance d, Asset a) {
1078: // 100 thousand seconds, or a little over a day (27.77... hours)
1079: return 100000000l;
1080: }
1081:
1082: /**
1083: * Looks for Allocation (is this correct?) plan element that contains
1084: * a task immediately previous (check_backwards is true) or after (false)
1085: * the time given in the RoleSchedule.
1086: * Do we need to check the role in this allocation as well?
1087: * @return null if no task found
1088: */
1089: /**
1090: * Inefficient...
1091: * @return string that lists the nodes in the route
1092: */
1093: public String getNodeNames(TransportationRoute route) {
1094: String nodes = "";
1095: for (Iterator i = route.getNodes().iterator(); i.hasNext();) {
1096: nodes = nodes + " "
1097: + ((TransportationNode) i.next()).getDescription();
1098: }
1099: return nodes;
1100: }
1101:
1102: /**
1103: * Determines if the asset passed in is a standard container or not
1104: */
1105: public boolean isStandardContainer(Asset a) {
1106: return (a instanceof Container);
1107: }
1108:
1109: /**
1110: * Determines if the asset passed in is a vehicle (for purposes of ship
1111: * loading) or not.
1112: **/
1113: public boolean isVehicle(Asset a) {
1114: MovabilityPG mpg = (MovabilityPG) ((GLMAsset) a)
1115: .getMovabilityPG();
1116: if (mpg == null)
1117: return false;
1118: String code = mpg.getCargoCategoryCode();
1119:
1120: boolean retval = false;
1121:
1122: try {
1123: retval = CargoCategoryDecoder.isRORO(code);
1124: } catch (NullPointerException npe) {
1125: throw new UTILRuntimeException(
1126: "GMLAsset.isVehicle - asset has movability PG but "
1127: + "cargo category code is NOT set.\nMovability PG was :"
1128: + mpg + "\nAsset was " + a);
1129: }
1130:
1131: return retval;
1132: }
1133:
1134: /**
1135: * Determines if the asset passed in is a vehicle (for purposes of ship
1136: * loading) or not OR is a crated aircraft.
1137: *
1138: * These items are packed on ship by area.
1139: **/
1140: public boolean isVehicleOrAircraft(Asset a) {
1141: MovabilityPG mpg = (MovabilityPG) ((GLMAsset) a)
1142: .getMovabilityPG();
1143: if (mpg == null)
1144: return false;
1145: String code = mpg.getCargoCategoryCode();
1146: boolean isAircraft = (code.toUpperCase().charAt(0) == 'B');
1147: return (isAircraft || CargoCategoryDecoder.isRORO(code));
1148: }
1149:
1150: /**
1151: * Utility method - find the organization corresponding to the port at
1152: * the given location
1153: * @param loc he location
1154: * @param ports_en a list of ports to search: probably obtained by a call to
1155: * getOrganizationAssets()
1156: * @param myClusterName used for logger.isDebugEnabled()()ging purposes.
1157: * @return the port that matches the location.
1158: */
1159: public Organization findPortOrg(GeolocLocation loc,
1160: Enumeration ports_en, String myClusterName) {
1161: Set ports = new HashSet();
1162: while (ports_en.hasMoreElements()) {
1163: Organization org = (Organization) ports_en.nextElement();
1164: RelationshipSchedule sched = org.getRelationshipSchedule();
1165:
1166: Collection portRelationships;
1167:
1168: //BOZO - Should be looking at self org for providers. Don't have self org so
1169: //will look to see if org has any port customers.
1170: if (!((portRelationships = sched.getMatchingRelationships(
1171: GLMConst.THEATER_SEA_PROVIDER.getConverse(),
1172: TimeSpan.MIN_VALUE, TimeSpan.MAX_VALUE)).isEmpty())
1173: || !((portRelationships = sched
1174: .getMatchingRelationships(
1175: GLMConst.GENERIC_SEA_PORT
1176: .getConverse(),
1177: TimeSpan.MIN_VALUE,
1178: TimeSpan.MAX_VALUE)).isEmpty())
1179: || !((portRelationships = sched
1180: .getMatchingRelationships(
1181: GLMConst.AMMUNITION_SEA_PORT
1182: .getConverse(),
1183: TimeSpan.MIN_VALUE,
1184: TimeSpan.MAX_VALUE)).isEmpty())) {
1185: for (Iterator iterator = portRelationships.iterator(); iterator
1186: .hasNext();) {
1187: Relationship relationship = (Relationship) iterator
1188: .next();
1189: ports.add(sched.getOther(relationship));
1190: }
1191: }
1192: }
1193:
1194: Organization foundOrg = measureHelper.bestOrg(loc, ports,
1195: myClusterName);
1196: return foundOrg;
1197: }
1198:
1199: /**
1200: * test if port is an ammo port
1201: * @param p Organization to be tested
1202: * @return true if is an ammo port
1203: */
1204: public boolean isAmmoPort(Asset p) {
1205: if (p instanceof Organization) {
1206: RelationshipSchedule schedule = ((Organization) p)
1207: .getRelationshipSchedule();
1208: // return (!(schedule.getMatchingRelationships(AMMO_PORT_ROLE).isEmpty())) ||
1209: // (!(schedule.getMatchingRelationships(AMMO_PORT_ROLE_ALT).isEmpty()));
1210: return (!(schedule.getMatchingRelationships(AMMO_PORT_ROLE
1211: .getConverse()).isEmpty()) || (!(schedule
1212: .getMatchingRelationships(AMMO_PORT_ROLE_ALT
1213: .getConverse()).isEmpty())));
1214: } else {
1215: return false;
1216: }
1217: }
1218:
1219: /**
1220: * test if organization is a non-ammo port
1221: * @param p Organization to be tested
1222: * @return true if it is a generic port
1223: */
1224: public boolean isCargoPort(Asset p) {
1225: if (p instanceof Organization) {
1226: RelationshipSchedule schedule = ((Organization) p)
1227: .getRelationshipSchedule();
1228: //return (schedule.getMatchingRelationships(CARGO_PORT_ROLE).size() > 0);
1229: return (!schedule.getMatchingRelationships(
1230: CARGO_PORT_ROLE.getConverse()).isEmpty());
1231: }
1232: return false;
1233: }
1234:
1235: public String getUniqueTag(Asset a) {
1236: return new String(a.getTypeIdentificationPG()
1237: .getTypeIdentification()
1238: + a.getItemIdentificationPG().getItemIdentification());
1239: }
1240:
1241: GLMPrepPhrase glmPrepHelper;
1242: GLMPreference glmPrefHelper;
1243: GLMMeasure measureHelper;
1244: }
|