001: /*
002: * <copyright>
003: * Copyright 2002-2003 BBNT Solutions, LLC
004: * under sponsorship of the Defense Advanced Research Projects Agency (DARPA).
005: *
006: * This program is free software; you can redistribute it and/or modify
007: * it under the terms of the Cougaar Open Source License as published by
008: * DARPA on the Cougaar Open Source Website (www.cougaar.org).
009: *
010: * THE COUGAAR SOFTWARE AND ANY DERIVATIVE SUPPLIED BY LICENSOR IS
011: * PROVIDED 'AS IS' WITHOUT WARRANTIES OF ANY KIND, WHETHER EXPRESS OR
012: * IMPLIED, INCLUDING (BUT NOT LIMITED TO) ALL IMPLIED WARRANTIES OF
013: * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, AND WITHOUT
014: * ANY WARRANTIES AS TO NON-INFRINGEMENT. IN NO EVENT SHALL COPYRIGHT
015: * HOLDER BE LIABLE FOR ANY DIRECT, SPECIAL, INDIRECT OR CONSEQUENTIAL
016: * DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE OF DATA OR PROFITS,
017: * TORTIOUS CONDUCT, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
018: * PERFORMANCE OF THE COUGAAR SOFTWARE.
019: * </copyright>
020: */
021:
022: package org.cougaar.logistics.plugin.inventory;
023:
024: import org.cougaar.core.util.UniqueObject;
025: import org.cougaar.core.blackboard.Publishable;
026: import org.cougaar.core.util.UID;
027: import org.cougaar.core.util.OwnedUniqueObject;
028: import org.cougaar.core.util.SimpleUniqueObject;
029: import org.cougaar.planning.servlet.data.xml.XMLWriter;
030: import org.cougaar.planning.servlet.data.xml.XMLable;
031:
032: import java.util.ArrayList;
033: import java.util.HashSet;
034: import java.util.HashMap;
035: import java.util.Collection;
036: import java.util.Iterator;
037:
038: /**
039: * ShortfallSummary is an object that summarizizes which inventories of
040: * a particular inventory have shortfall.
041: */
042:
043: public class ShortfallSummary implements UniqueObject,
044: java.io.Serializable, Publishable {
045:
046: private final static String HOURS = "Hours";
047: private final static String DAYS = "Days";
048:
049: private UID uid = null;
050: private String supplyType = "";
051: private long bucketSize;
052: private HashMap shortfallInventories;
053:
054: /**
055: * Constructor
056: *
057: * @param aSupplyType - the supply type this shortfall summary applys to
058: */
059:
060: public ShortfallSummary(String aSupplyType, UID aUID, long mSecs) {
061: supplyType = aSupplyType;
062: bucketSize = mSecs;
063: shortfallInventories = new HashMap();
064: this .uid = aUID;
065: }
066:
067: // UniqueObject interface Top level object on blackboard
068: public UID getUID() {
069: return uid;
070: }
071:
072: /**
073: * Set the UID (unique identifier) of this UniqueObject. Used only
074: * during initialization.
075: *
076: * @param uid the UID to be given to this
077: */
078: public void setUID(UID uid) {
079: if (this .uid != null)
080: throw new RuntimeException("Attempt to change UID: " + uid);
081: this .uid = uid;
082: }
083:
084: /**
085: * The number of milliseconds per bucket. Either an Hour (UA) or Days worth of milliseconds. This is the granularity
086: * at which the inventory counts tasks and qty's. If a day you add demand for all tasks that are for within a given day.
087: *
088: * @return long - the number of milliseconds per bucket in all the inventories at this agent for this supply type.
089: */
090:
091: public long getMsecPerBucket() {
092: return bucketSize;
093: }
094:
095: /**
096: * ShortfallSummaries are divided by supply type - 1 to 1 for each inventory plugin. All the inventories contained
097: * within are of that supply type.
098: *
099: * @return String the supply type "Ammunition", "BulkPOL", "PackagedPOL", "Subsistence", or "Cosumeable"
100: */
101: public String getSupplyType() {
102: return supplyType;
103: }
104:
105: protected boolean addShortfallInventory(ShortfallInventory inv) {
106: ShortfallInventory orig = (ShortfallInventory) shortfallInventories
107: .get(inv.getInvID());
108: if ((orig == null) || (!(orig.equals(inv)))) {
109: shortfallInventories.put(inv.getInvID(), inv);
110: return true;
111: }
112: return false;
113: }
114:
115: protected boolean removeShortfallInventory(ShortfallInventory inv) {
116: return removeShortfallInventory(inv.getInvID());
117: }
118:
119: protected boolean removeShortfallInventory(String invID) {
120: ShortfallInventory orig = (ShortfallInventory) shortfallInventories
121: .get(invID);
122: if (orig != null) {
123: shortfallInventories.remove(invID);
124: return true;
125: }
126: return false;
127: }
128:
129: /**
130: * Accessor for setting shortfall inventories.
131: *
132: * @param invs - Shortfall inventories to be added to the Summary
133: */
134: public void setShortfallInventories(Collection invs) {
135: shortfallInventories.clear();
136: Iterator it = invs.iterator();
137: while (it.hasNext()) {
138: ShortfallInventory si = (ShortfallInventory) it.next();
139: shortfallInventories.put(si.getInvID(), si);
140: }
141: }
142:
143: /**
144: * Add a collection of shortfall inventories. Before adding see if it already contains that shortfall inventory
145: * and if they are equal if not don't bother to update.
146: *
147: * @param invs - The collection of ShortfallInventories to add to the Summary.
148: * @return boolean true if there was a new ShortfallInventory added. false if nothing changed in the collection.
149: * Determines whether to republish this ShortfallSummary or not.
150: */
151: public boolean addShortfallInventories(Collection invs) {
152: Iterator it = invs.iterator();
153: boolean addedSomething = false;
154: while (it.hasNext()) {
155: ShortfallInventory si = (ShortfallInventory) it.next();
156: if (addShortfallInventory(si)) {
157: addedSomething = true;
158: }
159:
160: }
161: return addedSomething;
162: }
163:
164: /**
165: * Remove a collection of shortfall invetories by ID. Make sure they exist in the collection if none of them do
166: * return false else true.
167: *
168: * @param invIDs - The collection of inventory ID's to be removed
169: * @return true is a Shortfall Inventory was removed else false.
170: */
171: public boolean removeShortfallInventories(Collection invIDs) {
172: Iterator it = invIDs.iterator();
173: boolean removedSomething = false;
174: while (it.hasNext()) {
175: String invID = (String) it.next();
176: if (removeShortfallInventory(invID)) {
177: removedSomething = true;
178: }
179: }
180: return removedSomething;
181: }
182:
183: /**
184: * Return true if there is a percent shortfall above the threshold in the shortfall inventores
185: *
186: * @param thresholdPercent - percent shortfall threshold
187: * @return true if there is a shortfall period in any shortfall inventory above the threhold percent.
188: */
189: public boolean hasPercentShortfallAbove(int thresholdPercent) {
190: Iterator invIt = getShortfallInventories().iterator();
191: while (invIt.hasNext()) {
192: ShortfallInventory shortInv = (ShortfallInventory) invIt
193: .next();
194: if ((shortInv.getUnexpected() && (shortInv
195: .getMaxPercentShortfall() > thresholdPercent))) {
196: return true;
197: }
198: }
199: return false;
200: }
201:
202: /**
203: * Return the total number of unexpected shortfall period inventories
204: *
205: * @return int the total number of unexpected shortfall period inventories.
206: */
207: public int getNumShortfallPeriodInvs() {
208: int ctr = 0;
209: Iterator invIt = getShortfallInventories().iterator();
210: while (invIt.hasNext()) {
211: ShortfallInventory shortInv = (ShortfallInventory) invIt
212: .next();
213: if ((shortInv.getUnexpected())
214: && (shortInv.getShortfallPeriods().size() > 0)) {
215: ctr++;
216: }
217: }
218: return ctr;
219: }
220:
221: /**
222: * Get the shortfall Inventories contained in this summary
223: *
224: * @return - The shortfall Inventories
225: */
226: public Collection getShortfallInventories() {
227: return shortfallInventories.values();
228: }
229:
230: /**
231: * Get the bucket unit
232: *
233: * @return String "Hours" or "Days"
234: */
235: public String getUnit() {
236: return getUnit(getMsecPerBucket());
237: }
238:
239: public static String getUnit(long msecPerBucket) {
240: if (msecPerBucket == TimeUtils.MSEC_PER_DAY) {
241: return DAYS;
242: } else if (msecPerBucket == TimeUtils.MSEC_PER_HOUR) {
243: return HOURS;
244: } else {
245: return "UNKNOWN";
246: }
247: }
248:
249: public String toString() {
250: StringBuffer sb = new StringBuffer(getSupplyType());
251: sb.append(" ");
252: sb.append(" Inventories: ");
253: Iterator it = shortfallInventories.values().iterator();
254: while (it.hasNext()) {
255: ShortfallInventory si = (ShortfallInventory) it.next();
256: sb.append(si.toString() + "\n");
257: }
258: return sb.toString();
259: }
260:
261: public boolean isPersistable() {
262: return true;
263: }
264: }
|