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.mlm.plugin.organization;
028:
029: import java.util.Collection;
030: import java.util.Enumeration;
031: import java.util.HashMap;
032: import java.util.HashSet;
033: import java.util.Iterator;
034: import java.util.Vector;
035:
036: import org.cougaar.core.blackboard.IncrementalSubscription;
037: import org.cougaar.core.logging.LoggingServiceWithPrefix;
038: import org.cougaar.core.service.LoggingService;
039: import org.cougaar.glm.ldm.asset.Organization;
040: import org.cougaar.planning.ldm.asset.Asset;
041: import org.cougaar.planning.ldm.plan.Allocation;
042: import org.cougaar.planning.ldm.plan.AllocationResult;
043: import org.cougaar.planning.ldm.plan.Expansion;
044: import org.cougaar.planning.ldm.plan.HasRelationships;
045: import org.cougaar.planning.ldm.plan.NewPrepositionalPhrase;
046: import org.cougaar.planning.ldm.plan.NewTask;
047: import org.cougaar.planning.ldm.plan.NewWorkflow;
048: import org.cougaar.planning.ldm.plan.PrepositionalPhrase;
049: import org.cougaar.planning.ldm.plan.Relationship;
050: import org.cougaar.planning.ldm.plan.RelationshipSchedule;
051: import org.cougaar.planning.ldm.plan.Role;
052: import org.cougaar.planning.ldm.plan.Task;
053: import org.cougaar.planning.ldm.plan.Workflow;
054: import org.cougaar.planning.plugin.legacy.SimplePlugin;
055: import org.cougaar.planning.plugin.util.PluginHelper;
056: import org.cougaar.util.TimeSpan;
057: import org.cougaar.util.UnaryPredicate;
058:
059: /**
060: * Handles GLS for subordinates tasks. We expand such tasks into
061: * subtasks, one per subordinate. As our subordinates changes we
062: * revise the expansion to follow.
063: **/
064: public class GLSAllocatorPlugin extends SimplePlugin implements
065: GLSConstants {
066:
067: private IncrementalSubscription myAllocatableTasks = null;
068: private IncrementalSubscription myOrgAssets;
069: private IncrementalSubscription myAllocations;
070: private IncrementalSubscription myExpansions;
071: private HashMap mySubs = new HashMap();
072: private LoggingService myLogger;
073:
074: public void setLoggingService(LoggingService ls) {
075: myLogger = ls;
076: }
077:
078: //Override the setupSubscriptions() in the SimplePlugin.
079: protected void setupSubscriptions() {
080: myLogger = LoggingServiceWithPrefix.add(myLogger,
081: getMessageAddress().getAddress() + ": ");
082:
083: // subscribe for GLS tasks for subordinates
084: myAllocatableTasks = (IncrementalSubscription) subscribe(myAllocatableTaskPredicate);
085:
086: //subscribe for assets to allocate against
087: myOrgAssets = (IncrementalSubscription) subscribe(myOrgPred);
088:
089: // subscribe to my allocations and expansions in order to catch changes in the
090: // allocationresults from the notification process
091: myAllocations = (IncrementalSubscription) subscribe(myAllocsPred);
092: myExpansions = (IncrementalSubscription) subscribe(myExpsPred);
093:
094: if (didRehydrate()) {
095: Collection subs = retrieveSubOrgs(myOrgAssets
096: .getCollection());
097: for (Iterator iterator = subs.iterator(); iterator
098: .hasNext();) {
099: Organization org = (Organization) iterator.next();
100: mySubs.put(org.getUID(), org);
101: }
102: }
103: }
104:
105: /**
106: * Process new tasks and subordinates as follows: New tasks are
107: * expanded to subtasks for each known subordinate. New
108: * subordinates have tasks appended to known expansions.
109: * Duplication is avoided when new tasks and new subordinates arrive
110: * together because the expansions for the new tasks don't yet
111: * exist.
112: **/
113: public synchronized void execute() {
114: if (myAllocatableTasks.hasChanged()) {
115: Collection tasks = myAllocatableTasks.getAddedCollection();
116:
117: if (!tasks.isEmpty()) {
118: if (myLogger.isDebugEnabled()) {
119: myLogger.debug("Expanding " + tasks.size()
120: + " added tasks");
121: }
122:
123: Collection subs = retrieveSubOrgs(myOrgAssets
124: .getCollection());
125: for (Iterator iterator = tasks.iterator(); iterator
126: .hasNext();) {
127: Task task = (Task) iterator.next();
128: expand(task, subs);
129: }
130: }
131:
132: // Should never get changed GLS tasks so don't even try to handle them.
133: // Last attempt to process changes led to months of debugging.
134: tasks = myAllocatableTasks.getChangedCollection();
135: if (!tasks.isEmpty()) {
136: for (Iterator iterator = tasks.iterator(); iterator
137: .hasNext();) {
138: myLogger.error(getAgentIdentifier()
139: + " ignoring a changed task "
140: + (Task) iterator.next());
141: }
142: }
143: }
144:
145: // check the asset container for new Subordinates
146: if (myOrgAssets.hasChanged()) {
147: /**
148: * When a new subordinate appears we must modify the existing
149: * expansions to include the new subordinate.
150: **/
151: Collection newSubs = retrieveSubOrgs(myOrgAssets
152: .getCollection());
153:
154: for (Iterator iterator = newSubs.iterator(); iterator
155: .hasNext();) {
156: Organization org = (Organization) iterator.next();
157:
158: // Remove from set if we already know about it
159: if (mySubs.get(org.getUID()) != null) {
160: iterator.remove();
161: } else {
162: mySubs.put(org.getUID(), org);
163: }
164: }
165:
166: for (Enumeration expansions = myExpansions.elements(); expansions
167: .hasMoreElements();) {
168: // It's an error if subs show up after we've sent GLS (bug 2990)
169: if (newSubs.size() > 0) {
170: myLogger.error(getAgentIdentifier()
171: + " adding subordinates - " + newSubs
172: + " after initial GLS");
173: }
174:
175: Expansion exp = (Expansion) expansions.nextElement();
176:
177: augmentExpansion(exp, newSubs);
178: }
179: /** Should handle removed assets, too **/
180: }
181:
182: if (myAllocations.hasChanged()) {
183: if (myLogger.isDebugEnabled()) {
184: myLogger.debug(getAgentIdentifier()
185: + " updating allocations");
186: }
187: PluginHelper.updateAllocationResult(myAllocations);
188: }
189:
190: if (myExpansions.hasChanged()) {
191: if (myLogger.isDebugEnabled()) {
192: myLogger.debug(getAgentIdentifier()
193: + " updating allocations");
194: }
195:
196: PluginHelper.updateAllocationResult(myExpansions);
197: }
198: } // end of execute
199:
200: /**
201: * Allocate the unallocated subtasks of a workflow
202: **/
203: private void allocate(Workflow wf) {
204: Enumeration tasks = wf.getTasks();
205: while (tasks.hasMoreElements()) {
206: Task t = (Task) tasks.nextElement();
207: if (t.getPlanElement() != null)
208: continue; // Already allocated
209: Enumeration pp = t.getPrepositionalPhrases();
210: while (pp.hasMoreElements()) {
211: PrepositionalPhrase p = (PrepositionalPhrase) pp
212: .nextElement();
213: if (p.getPreposition().equals(FOR_ORGANIZATION)) {
214: if (p.getIndirectObject() instanceof Organization) {
215: Asset a = (Asset) p.getIndirectObject();
216: AllocationResult estimatedresult = PluginHelper
217: .createEstimatedAllocationResult(t,
218: theLDMF, 0.0, true);
219: Allocation alloc = theLDMF.createAllocation(
220: theLDMF.getRealityPlan(), t, a,
221: estimatedresult, Role.BOGUS);
222: publishAdd(alloc);
223: break; // Terminate processing of prep phrases
224: }
225: }
226: }
227: }
228: }
229:
230: /**
231: * Expand a new task to include the given subordinates.
232: **/
233: private void expand(Task t, Collection subs) {
234: NewWorkflow wf = theLDMF.newWorkflow();
235: //wf.setIsPropagatingToSubtasks();
236: wf.setParentTask(t);
237:
238: // Add tasks to workflow but do not publish them. Done later in the call
239: // to PluginHelper.publishAddExpansion();
240: augmentWorkflow(wf, subs, false);
241: // package up the workflow in an expansion
242:
243: double confidence = 0.0;
244: if (subs.size() == 0) {
245: confidence = 1.0;
246: }
247:
248: AllocationResult estAR = PluginHelper
249: .createEstimatedAllocationResult(t, theLDMF,
250: confidence, true);
251: Expansion exp = theLDMF.createExpansion(theLDMF
252: .getRealityPlan(), t, wf, estAR);
253: //publish the Expansion and the workflow tasks all in one
254: PluginHelper.publishAddExpansion(getSubscriber(), exp);
255: //now allocate the tasks in the new workflow
256: allocate(wf);
257: }
258:
259: private void augmentWorkflow(NewWorkflow wf, Collection subs,
260: boolean publishInPlace) {
261: for (Iterator iterator = subs.iterator(); iterator.hasNext();) {
262: Asset orga = (Asset) iterator.next();
263: NewTask newTask = createSubTask(wf.getParentTask(), orga);
264: newTask.setWorkflow(wf);
265: wf.addTask(newTask);
266: if (publishInPlace) {
267: publishAdd(newTask);
268: }
269: }
270: }
271:
272: private synchronized void augmentExpansion(Expansion exp,
273: Collection subs) {
274: if (subs.size() > 0) {
275:
276: NewWorkflow wf = (NewWorkflow) exp.getWorkflow();
277:
278: // Add tasks to workflow and publish new tasks
279: augmentWorkflow(wf, subs, true);
280:
281: publishChange(wf);
282: allocate(wf);
283: }
284: }
285:
286: /**
287: * Create a subtask that matches the given Task plus a FOR
288: * Organization phrase.
289: **/
290: private NewTask createSubTask(Task t, Asset subasset) {
291: Vector prepphrases = new Vector(3);
292:
293: NewTask subtask = theLDMF.newTask();
294:
295: // Create copy of parent Task
296: subtask.setParentTask(t);
297: if (t.getDirectObject() != null) {
298: subtask.setDirectObject(theLDMF.cloneInstance(t
299: .getDirectObject()));
300: } else {
301: subtask.setDirectObject(null);
302: }
303:
304: // Code removed because oplan is in context
305: // pull out the "with OPlan" prep phrase and store for later
306: Enumeration origpp = t.getPrepositionalPhrases();
307: while (origpp.hasMoreElements()) {
308: PrepositionalPhrase theorigpp = (PrepositionalPhrase) origpp
309: .nextElement();
310: if ((theorigpp.getPreposition().equals(WITH_C0))
311: || (theorigpp.getPreposition()
312: .equals(FOR_OPLAN_STAGES))) {
313: prepphrases.addElement(theorigpp);
314: }
315: }
316:
317: NewPrepositionalPhrase newpp = theLDMF.newPrepositionalPhrase();
318: newpp.setPreposition(FOR_ORGANIZATION);
319: newpp.setIndirectObject(theLDMF.cloneInstance(subasset));
320: prepphrases.addElement(newpp);
321: subtask.setPrepositionalPhrases(prepphrases.elements());
322:
323: subtask.setVerb(t.getVerb());
324: subtask.setPlan(t.getPlan());
325: // for now set the preferences the same as the parent task's
326: // in a real expander you would want to distribute the parents preferences
327: // across the subtasks.
328: subtask.setPreferences(t.getPreferences());
329: subtask.setSource(this .getMessageAddress());
330:
331: return subtask;
332:
333: }
334:
335: private static UnaryPredicate myAllocatableTaskPredicate = new UnaryPredicate() {
336: public boolean execute(Object o) {
337: if (o instanceof Task) {
338: Task t = (Task) o;
339:
340: for (int index = 0; index < GLSInitVerbs.length; index++) {
341: if (t.getVerb().equals(GLSInitVerbs[index])) {
342: PrepositionalPhrase app = t
343: .getPrepositionalPhrase(FOR_ORGANIZATION);
344:
345: if (app != null) {
346: Object indObject = app.getIndirectObject();
347: if (indObject instanceof Asset) {
348: Asset asset = (Asset) indObject;
349: try {
350: return asset
351: .getTypeIdentificationPG()
352: .getTypeIdentification()
353: .equals("Subordinates");
354: } catch (Exception e) {
355: System.out
356: .println("GLSAlloc error while trying to get the TypeIdentification of an asset");
357: e.printStackTrace();
358: }
359: }
360: }
361: }
362: }
363: }
364: return false;
365: }
366: };
367:
368: /**
369: * Select all Organization assets
370: **/
371: private static UnaryPredicate myOrgPred = new UnaryPredicate() {
372: public boolean execute(Object o) {
373: if (o instanceof Organization) {
374: return true;
375: } else {
376: return false;
377: }
378: }
379: };
380:
381: public static Collection retrieveSubOrgs(Collection orgs) {
382: HashSet subs = new HashSet(3);
383:
384: Iterator iterator = orgs.iterator();
385: while (iterator.hasNext()) {
386: Organization org = (Organization) iterator.next();
387:
388: if (org.isSelf()) {
389: RelationshipSchedule schedule = org
390: .getRelationshipSchedule();
391: Collection orgCollection = org.getSubordinates(
392: TimeSpan.MIN_VALUE, TimeSpan.MAX_VALUE);
393:
394: if (orgCollection.size() > 0) {
395: for (Iterator relIterator = orgCollection
396: .iterator(); relIterator.hasNext();) {
397: Relationship relationship = (Relationship) relIterator
398: .next();
399: HasRelationships sub = schedule
400: .getOther(relationship);
401:
402: if (!subs.contains(sub)) {
403: subs.add(sub);
404: }
405: }
406: }
407: }
408: }
409: return subs;
410: }
411:
412: /**
413: * Select all the allocations we create. These are allocations of
414: * tasks whose parent task is selected by myAllocatableTaskPred
415: **/
416: private static UnaryPredicate myAllocsPred = new UnaryPredicate() {
417: public boolean execute(Object o) {
418: if (o instanceof Allocation) {
419: Task t = ((Allocation) o).getTask();
420:
421: for (int index = 0; index < GLSInitVerbs.length; index++) {
422: if (t.getVerb().equals(GLSInitVerbs[index])) {
423: return true;
424: }
425: }
426: }
427: return false;
428: }
429: };
430:
431: /**
432: * Select the expansions we create. These are expansions of the
433: * tasks selected by myAllocableTaskPred
434: **/
435: private static UnaryPredicate myExpsPred = new UnaryPredicate() {
436: public boolean execute(Object o) {
437: if (o instanceof Expansion) {
438: return myAllocatableTaskPredicate
439: .execute(((Expansion) o).getTask());
440: }
441: return false;
442: }
443: };
444: }
|