001: /*
002: * <copyright>
003: *
004: * Copyright 1999-2004 Honeywell Inc
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.glm.packer;
028:
029: import java.util.ArrayList;
030: import java.util.Enumeration;
031: import java.util.Iterator;
032: import java.util.Vector;
033:
034: import org.cougaar.glm.ldm.asset.GLMAsset;
035: import org.cougaar.planning.ldm.PlanningFactory;
036: import org.cougaar.planning.ldm.measure.Mass;
037: import org.cougaar.planning.ldm.plan.AspectType;
038: import org.cougaar.planning.ldm.plan.AspectValue;
039: import org.cougaar.planning.ldm.plan.NewPrepositionalPhrase;
040: import org.cougaar.planning.ldm.plan.NewTask;
041: import org.cougaar.planning.ldm.plan.Preference;
042: import org.cougaar.planning.ldm.plan.PrepositionalPhrase;
043: import org.cougaar.planning.ldm.plan.ScoringFunction;
044: import org.cougaar.planning.ldm.plan.Task;
045: import org.cougaar.util.log.Logger;
046: import org.cougaar.util.log.Logging;
047:
048: /**
049: * This class provides one of two "wheels" that drive the packing process.
050: * This class provides a Generator that yields a stream of Tasks that
051: * are components of the input tasks and that are sized per the
052: * requirements that are generated by the Filler.
053: * @see Filler
054: */
055: class Sizer {
056: static public final String TRUE = "True";
057:
058: /**
059: * Unit for task quantity preference
060: */
061: static public final int TONS = 0;
062: static public final int EACHES = 1;
063: static public final int MIN_UNIT = 0;
064: static public final int MAX_UNIT = 1;
065:
066: private static Logger logger = Logging.getLogger(Sizer.class);
067:
068: /**
069: * How much of the quantity remains in the current task
070: */
071: private double _remainder;
072:
073: /**
074: * The tasks we are packing from
075: */
076: private ArrayList _tasks;
077:
078: /**
079: * As we break the current task, of the tasks to be packed,
080: * into right-sized bits, we accumulate component tasks for
081: * a subsidiary workflow in this SList.
082: */
083: private ArrayList _expansionQueue;
084:
085: /**
086: * The task we are currently processing.
087: */
088: private Task _curTask;
089:
090: private GenericPlugin _gp;
091:
092: private int _quantityType;
093:
094: Sizer(ArrayList _packus, GenericPlugin gp, int quantityType) {
095: _tasks = new ArrayList(_packus);
096: _gp = gp;
097: _remainder = 0.0;
098:
099: if ((quantityType < MIN_UNIT) || (quantityType > MAX_UNIT)) {
100: logger.error("Sizer: invalid quantity unit specified - "
101: + quantityType + " - assuming TONS.");
102: _quantityType = TONS;
103: } else {
104: _quantityType = quantityType;
105: }
106: }
107:
108: /**
109: * The Filler will request some amount of quantity from the
110: * Sizer.
111: * This method will return a Task whose quantity is <= to requestedAmt,
112: * or null if there are no more tasks to be packed.
113: */
114: Task provide(double requestedAmt) {
115: Task ret = null;
116:
117: // first, if we've gotten a request, we need to check
118: // to see if the _curTask has anything left in it...
119: if (_remainder == 0.0) {
120: if ((_curTask = getNextTask()) != null) {
121: Mass taskMass = getTaskMass(_curTask, _quantityType);
122: _remainder = taskMass.getShortTons();
123:
124: if (_expansionQueue != null) {
125: logger
126: .error("Sizer.provide : ERROR - Expansion queue is not null - we will drop tasks :");
127: for (Iterator iter = _expansionQueue.iterator(); iter
128: .hasNext();)
129: logger.error("\t"
130: + ((Task) iter.next()).getUID());
131: }
132: _expansionQueue = new ArrayList();
133: } else {
134: return null;
135: }
136: }
137: // precondition: _curTask is bound to a Task and remainder >= 0.0
138: // remainder can be == 0.0 because some Plugin developers make such
139: // tasks instead of rescinding requests.
140:
141: if (_remainder <= requestedAmt) {
142: // we are going to use up the entire _curTask and need to
143: // take care of the expansion
144: ret = sizedTask(_curTask, _remainder);
145: _expansionQueue.add(0, ret);
146: makeExpansion(_curTask, _expansionQueue);
147: _expansionQueue = null; // it has been used - we shouldn't try to use it again
148: _remainder = 0.0;
149: } else {
150: ret = sizedTask(_curTask, requestedAmt);
151: _expansionQueue.add(0, ret);
152: _remainder = _remainder - requestedAmt;
153: if (_remainder == 0.0)
154: logger
155: .error("Sizer.provide : ERROR - We will drop task "
156: + ret.getUID());
157: }
158: return ret;
159: }
160:
161: /**
162: * This method should only be called after areMoreTasks
163: * has returned true; it does no safety checking itself.
164: * @see #areMoreTasks
165: */
166: private Task getNextTask() {
167: if (!_tasks.isEmpty()) {
168: Task t = (Task) _tasks.remove(0);
169: return t;
170: } else {
171: return null;
172: }
173: }
174:
175: public int sizedMade = 0;
176:
177: /**
178: * Returns a copy of the input task that is identical in every way,
179: * but whose quantity has been set to size.
180: * This task will <em>not</em> be published yet.
181: */
182: private Task sizedTask(Task t, double size) {
183: PlanningFactory factory = _gp.getGPFactory();
184: NewTask nt = factory.newTask();
185:
186: sizedMade++;
187:
188: nt.setVerb(t.getVerb());
189: nt.setParentTask(t);
190: nt.setDirectObject(factory.createInstance(t.getDirectObject()));
191:
192: // copy the PPs
193: ArrayList preps = new ArrayList();
194: Enumeration e = t.getPrepositionalPhrases();
195: NewPrepositionalPhrase npp;
196: while (e.hasMoreElements()) {
197: npp = factory.newPrepositionalPhrase();
198: PrepositionalPhrase pp = (PrepositionalPhrase) e
199: .nextElement();
200: npp.setPreposition(pp.getPreposition());
201: npp.setIndirectObject(pp.getIndirectObject());
202: preps.add(npp);
203: }
204:
205: npp = factory.newPrepositionalPhrase();
206: // Mark as INTERNAL so we recognize it as an expansion task.
207: npp.setPreposition(GenericPlugin.INTERNAL);
208: npp.setIndirectObject(TRUE);
209: preps.add(npp);
210:
211: //BOZO
212: nt.setPrepositionalPhrases(new Vector(preps).elements());
213:
214: // now copy the preferences, with the exception of quantity...
215: ArrayList prefs = new ArrayList();
216: e = t.getPreferences();
217: while (e.hasMoreElements()) {
218: Preference p = (Preference) e.nextElement();
219: if (p.getAspectType() != AspectType.QUANTITY) {
220: Preference np = factory.newPreference(
221: p.getAspectType(), p.getScoringFunction(), p
222: .getWeight());
223: prefs.add(np);
224: }
225: }
226:
227: AspectValue av = AspectValue.newAspectValue(
228: AspectType.QUANTITY, size);
229: ScoringFunction sf = ScoringFunction.createNearOrBelow(av, 0.1);
230: Preference pref = factory
231: .newPreference(AspectType.QUANTITY, sf);
232: prefs.add(0, pref);
233:
234: //BOZO
235: nt.setPreferences(new Vector(prefs).elements());
236:
237: return nt;
238: }
239:
240: /**
241: * Make an expansion by putting all the tasks in subtasks into a new
242: * workflow and making them the workflow of expandme. This can probably
243: * be done using a method on the GenericPlugin.
244: * @see GenericPlugin#createExpansion
245: */
246: private void makeExpansion(Task expandme, ArrayList subtasks) {
247:
248: _gp.createExpansion(subtasks.iterator(), expandme);
249: }
250:
251: /**
252: * Compute the mass associated with the task
253: *
254: */
255: public static Mass getTaskMass(Task task, int quantityUnit) {
256: switch (quantityUnit) {
257: case (EACHES):
258: GLMAsset assetToBePacked = (GLMAsset) task
259: .getDirectObject();
260: if (assetToBePacked.hasPhysicalPG()) {
261: Mass massPerEach = assetToBePacked.getPhysicalPG()
262: .getMass();
263: double taskWeight = task
264: .getPreferredValue(AspectType.QUANTITY)
265: * massPerEach.getShortTons();
266: return new Mass(taskWeight, Mass.SHORT_TONS);
267: } else {
268: if (logger.isDebugEnabled()) {
269: logger
270: .debug("Sizer.getTaskMass: asset - "
271: + assetToBePacked
272: + " - does not have a PhysicalPG. "
273: + "Assuming QUANTITY preference is in stort tons.");
274: }
275: return new Mass(task
276: .getPreferredValue(AspectType.QUANTITY),
277: Mass.SHORT_TONS);
278: }
279:
280: case (TONS):
281: return new Mass(
282: task.getPreferredValue(AspectType.QUANTITY),
283: Mass.SHORT_TONS);
284:
285: default:
286: logger.error("Sizer: invalid quantity unit specified - "
287: + quantityUnit + " - assuming TONS.");
288: return new Mass(
289: task.getPreferredValue(AspectType.QUANTITY),
290: Mass.SHORT_TONS);
291: }
292: }
293: }
|