1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28 package zeus.actors;
29
30 import java.util.*;
31 import zeus.util.*;
32 import zeus.concepts.*;
33 import zeus.actors.rtn.util.DelegationStruct;
34 import zeus.actors.rtn.Engine;
35 import zeus.actors.event.*;
36
37 /***
38 * This component implements the agent's Planning and Scheduling mechanism.
39 * Its role is to construct action sequences that will achieve desired input goals.
40 * Hence the Planner is under the control of the {@link Engine} component, which
41 * initiates planning and manages the contracting of any subgoals that the agent
42 * cannot achieve. <p>
43 *
44 * Planning operators (actions or tasks) are represented in the classical fashion
45 * as primitive or summary operators. Primitive operators are defined in terms
46 * of their preconditions, effects, cost, duration and constraints and precondition
47 * order, while summary operators are defined in terms of a graph of existing
48 * primitive tasks. <p>
49 *
50 * The Planner utilises classical partial order means end planning in its plan
51 * construction process. So when given a goal the Planner searches its {@link PlanDb}
52 * for an operator with a public effect that unifies (with unification bindings q)
53 * with the desired_effect of the goal. If multiple operators are found, they are
54 * ranked by cost, and then by duration. Next, the Planner selects the first
55 * ranked operator, constrains its preconditions and effects with q, and then
56 * attempts to schedule the operator into its diary. If the operator cannot be
57 * scheduled, the Planner backtracks and re-peats the process with the next
58 * applicable operator. <p>
59 *
60 * Details on how the Planner functions are provided in the Zeus Technical Manual.
61 */
62
63
64 public class Planner extends PlanDb
65 {
66 private HSet[] eventMonitor = new HSet[6];
67
68 public static final int START = 0;
69 public static final int FAIL = 1;
70 public static final int SUCCEED = 2;
71
72 public static final int CREATE = 3;
73 public static final int DISPOSE = 4;
74 public static final int STATE_CHANGE = 5;
75
76 public static final boolean EXPAND = true;
77 public static final int REPLAN = 0;
78 public static final int PLAN = 1;
79
80
81
82
83 /*** This object stores the Planner's diary as is a two-dimensional array, with
84 time on one dimension and processors on another. */
85 protected PlanRecord[][] table;
86
87 protected int plannerWidth;
88 protected int plannerLength;
89 protected int now;
90 protected Hashtable BindTable;
91
92 protected boolean user_responded = false;
93 protected long USER_TIME_OUT = 0;
94 protected AgentContext context = null;
95
96
97 public Planner () {
98 for(int i = 0; i < eventMonitor.length; i++ )
99 eventMonitor[i] = new HSet();
100 }
101
102
103 public Planner(AgentContext context, int plannerWidth,
104 int plannerLength )
105 {
106 Assert.notNull(context);
107 this.context = context;
108 context.set(this);
109
110 Core.ERROR(plannerLength > 0 && plannerWidth > 0, 1005, this);
111
112 table = new PlanRecord[plannerWidth][plannerLength];
113 this.plannerLength = plannerLength;
114 this.plannerWidth = plannerWidth;
115 now = (int) now();
116 BindTable = new Hashtable();
117
118 for(int i = 0; i < eventMonitor.length; i++ )
119 eventMonitor[i] = new HSet();
120
121 USER_TIME_OUT = (long)(0.5 * context.getClockStep());
122 }
123
124 public AgentContext getAgentContext() {
125 return context;
126 }
127
128
129 public int getPlannerWidth() {
130 return plannerWidth;
131 }
132 public int getPlannerLength() {
133 return plannerLength;
134 }
135
136
137 int anySideEffect(Fact desc, PlanRecord rec,
138 int position, int required) {
139 return anySideEffect(desc,rec,new Integer(position),required);
140 }
141
142
143
144 int anySideEffect(Fact desc, PlanRecord rec,
145 Object precond, int required)
146 {
147 if ( !context.getSharePlan() ) return required;
148 Core.DEBUG(2,"checking for serendipitous side-effects for " + desc);
149
150 int no = desc.getNumber();
151 PlanRecord crec;
152 int st = rec.getStartTime();
153 if ( desc.isa(OntologyDb.ENTITY) ) desc.setNumber(desc.newVar());
154 Enumeration enum = this.elements();
155 while( required > 0 && enum.hasMoreElements() ) {
156 crec = (PlanRecord)enum.nextElement();
157 if ( crec != rec && crec.getEndTime() <= st )
158 required = crec.anySideEffect(desc,rec,precond,required);
159 }
160 desc.setNumber(no);
161 return required;
162 }
163
164
165
166 public PlannerQueryStruct canAchieve(Vector goals, String key)
167 {
168 Core.DEBUG(3,"\nCanAchieve:\n" + goals + "\n");
169
170 Goal g;
171 PlannerQueryStruct struct = new PlannerQueryStruct(goals);
172
173 for(int i = 0; i < goals.size(); i++ ) {
174 g = (Goal)goals.elementAt(i);
175 notifyMonitors(g,START,PlanningEvent.PLANNING);
176 }
177
178 struct.timeout = context.getAcceptTimeout();
179
180
181
182 if ( loopFound(goals) ) {
183 Core.DEBUG(0,"CanAchieve loop found = " + struct);
184 index(struct);
185 return struct;
186 }
187
188
189 double ct = Double.MAX_VALUE;
190 double rt = Double.MAX_VALUE;
191 for(int i = 0; i < goals.size(); i++ ) {
192 g = (Goal)goals.elementAt(i);
193 ct = Math.min(ct,g.getConfirmTime().getTime());
194 if ( g.getReplyTime() != null )
195 rt = Math.min(rt,g.getReplyTime().getTime());
196 }
197 double now = now();
198 if ( now >= Math.min(ct,rt) ) {
199 Core.DEBUG(0,"CanAchieve rt/ct problem: " + now + "\n" + struct);
200 index(struct);
201 return struct;
202 }
203
204 struct.internal = schedule(key,null,new Vector(),goals,struct,EXPAND);
205 if ( struct.internal.isEmpty() ) {
206 Core.DEBUG(0,"CanAchieve = " + struct);
207 index(struct);
208 return struct;
209 }
210
211 double lct = (double) latestConfirmTime(goals);
212 if ( lct < ct ) {
213 Core.DEBUG(0,"CanAchieve lct < ct " + now + "\n" + struct);
214 reject(struct.goals,struct.internal);
215 struct.internal = new Vector();
216 index(struct);
217 return struct;
218 }
219
220 if ( !struct.internal.isEmpty() && !struct.external.isEmpty() ) {
221
222 double t;
223 t = Math.min(ct,rt);
224 t = t - now();
225 t = t/2*struct.external.size();
226 struct.timeout = t;
227 }
228 index(struct);
229 Core.DEBUG(0,"canAchieve = " + struct);
230 return struct;
231 }
232
233 protected boolean loopFound(Vector goals) {
234 Enumeration enum = BindTable.elements();
235 PlannerQueryStruct struct;
236 Vector stored;
237 Goal g1, g2;
238 Fact f1, f2;
239 String r1, r2;
240 Bindings b = new Bindings(context.whoami());
241
242 while( enum.hasMoreElements() ) {
243 struct = (PlannerQueryStruct) enum.nextElement();
244 stored = struct.goals;
245 for( int i = 0; i < goals.size(); i++ ) {
246 g1 = (Goal)goals.elementAt(i);
247 f1 = g1.getFact();
248 r1 = g1.getRootId();
249 for( int j = 0; j < stored.size(); j++, b.clear() ) {
250 g2 = (Goal)stored.elementAt(j);
251 if ( g2.getDesiredBy().equals(context.whoami()) ) {
252 f2 = g2.getFact();
253 r2 = g2.getRootId();
254 if ( r1.equals(r2) && f1.unifiesWith(f2,b) ) {
255 Core.DEBUG(0,"Loop found: " + g1 + "\n" + g2);
256 return true;
257 }
258 }
259 }
260 }
261 }
262 return false;
263 }
264
265 public PlannerQueryStruct clear_bind(Vector goals) {
266 if ( goals.isEmpty() ) return null;
267 Core.DEBUG(3,"Entering Clear Bind goals\n" + goals + "\n");
268
269 String index = makeIndex(goals);
270 return (PlannerQueryStruct) BindTable.remove(index);
271 }
272
273 public void reset_bind(Vector goals, PlannerQueryStruct data) {
274 Core.DEBUG(3,"Entering Reset Bind goals\n" + goals + "\n");
275
276 String index = makeIndex(goals);
277 Core.ERROR(BindTable.put(index,data) == null,1009,this);
278 }
279
280 public Vector bind(Vector goals) {
281 Core.DEBUG(3,"Entering Final Bind goals\n" + goals + "\n");
282
283 String index = makeIndex(goals);
284 PlannerQueryStruct struct = (PlannerQueryStruct) BindTable.get(index);
285 PlanRecord rec;
286 Bindings b;
287 Core.DEBUG(3,"Final Bind checking record" );
288 for(int i = 0; i < struct.internal.size(); i++ ) {
289 rec = (PlanRecord)struct.internal.elementAt(i);
290 b = rec.getBindings();
291 Core.ERROR(struct.bindings.add(b),1010,this);
292 }
293 Goal g;
294 Vector data = new Vector();
295 Core.DEBUG(3,"Final Bind checking costs" );
296 for(int i = 0; i < goals.size(); i++ ) {
297 g = new Goal( (Goal)goals.elementAt(i) );
298 g.constrain(struct.bindings);
299 rec = lookUp(g);
300 g.setCost(rec.getCost());
301 data.addElement(g);
302 }
303 Core.DEBUG(3,"Exiting Final Bind goals\n" + data + "\n" );
304 return data;
305 }
306
307
308
309 public synchronized void userResponded() {
310 this.user_responded = true;
311 }
312
313 public BindResults bind(Vector goals, Vector input, int mode) {
314 Core.DEBUG(3,"Entering bind...");
315 String index = makeIndex(goals);
316 PlannerQueryStruct struct = (PlannerQueryStruct) BindTable.get(index);
317
318 Goal g0, g1;
319 Fact f0, f1;
320 PlanRecord rec;
321 Vector[] reduced = new Vector[struct.external.size()];
322 Bindings bindings = new Bindings(context.whoami());
323 BindResults result = new BindResults();
324 boolean found = false;
325
326 Vector absent = new Vector();
327 Vector present = new Vector();
328
329 for(int i = 0; i < struct.external.size(); i++ ) {
330 g0 = (Goal)struct.external.elementAt(i);
331 reduced[i] = sortFeasible(g0.getId(),input);
332 if ( reduced[i].isEmpty() )
333 absent.addElement(g0);
334 else
335 present.addElement(g0);
336 }
337
338 if ( !absent.isEmpty() ) {
339 Core.DEBUG(3,"From bind...");
340 Core.DEBUG(3,"PlannerQueryStruct = " + struct);
341 Core.DEBUG(3,"absent = " + absent);
342 for( int x = 0; x < struct.internal.size(); x++ ) {
343 rec = (PlanRecord)struct.internal.elementAt(x);
344 Core.DEBUG(3,rec.getConsumedDb());
345 }
346
347 softFailParentOf(absent,struct,mode);
348 for(int j = 0; j < present.size(); j++ ) {
349 g1 = (Goal)present.elementAt(j);
350 found = false;
351 for(int i = 0; !found && i < struct.external.size(); i++ ) {
352 g0 = (Goal)struct.external.elementAt(i);
353 found = found || g0.getId().equals(g1.getId());
354 if ( found ) struct.external.removeElementAt(i--);
355 }
356 if ( !found ) present.removeElementAt(j--);
357 }
358 }
359
360 Core.DEBUG(3,"Present = " + present);
361 Core.DEBUG(3,"Struct = " + struct);
362
363 if ( present.isEmpty() ) {
364 result.rejection = input;
365 result.ok = !struct.internal.isEmpty() ||
366 !struct.decompositions.isEmpty();
367 result.external = Misc.copyVector(struct.external);
368 return result;
369 }
370
371
372 if ( present.size() != reduced.length ) {
373 reduced = new Vector[present.size()];
374 for(int i = 0; i < present.size(); i++ ) {
375 g0 = (Goal)present.elementAt(i);
376 reduced[i] = sortFeasible(g0.getId(),input);
377 }
378 }
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399 Object[] data;
400 DelegationStruct[] ds = new DelegationStruct[present.size()];
401 Selector selector = new Selector(reduced);
402 result.ok = false;
403 while( !result.ok && selector.hasMoreElements() ) {
404 data = (Object[]) selector.nextElement();
405 bindings.clear();
406 result.ok = true;
407 for(int i = 0; i < data.length; i++ ) {
408 ds[i] = (DelegationStruct)data[i];
409
410 g1 = (Goal)ds[i].goals.elementAt(0);
411 g0 = (Goal)present.elementAt(i);
412 f0 = g0.getFact();
413 f1 = g1.getFact();
414 result.ok = f1.unifiesWith(f0,bindings);
415 if ( !result.ok )
416 break;
417 }
418
419 Core.DEBUG(3,"Current selection ... ");
420 Core.DEBUG(3,ds);
421
422 result.ok = result.ok && bindings.add(struct.bindings);
423 if ( result.ok ) {
424 for(int j = 0; j < struct.internal.size(); j++ ) {
425 rec = (PlanRecord) struct.internal.elementAt(j);
426 Core.ERROR(rec.applyConstraints(bindings),1011,this);
427 }
428 struct.bindings = bindings;
429
430 for( int i = 0; i < data.length; i++ ) {
431 ds[i] = (DelegationStruct)data[i];
432 result.selection.addElement(ds[i]);
433 }
434 }
435 }
436
437 if ( result.ok ) {
438 result.rejection = Misc.difference(input,result.selection);
439 resume_planning(ds,struct);
440 }
441 else {
442 result.rejection = input;
443 softFailParentOf(struct.external,struct,mode);
444 result.ok = !struct.internal.isEmpty() ||
445 !struct.decompositions.isEmpty();
446 }
447
448 result.external = Misc.copyVector(struct.external);
449
450 Core.DEBUG(3," Bind struct\n" + struct);
451 Core.DEBUG(3," Bind goals\n" + goals);
452 Core.DEBUG(3," Bind bindings\n" + struct.bindings);
453 Core.DEBUG(3," Bind result\n" + result + "\n" );
454
455 return result;
456 }
457
458 protected Vector sortFeasible(String gid, Vector input) {
459 Core.DEBUG(3,"sortFeasible input " + gid + "\n" + input);
460 Goal g0, g1;
461 Object obj;
462 DelegationStruct ds;
463 Vector reduced = new Vector();
464 for(int i = 0; i < input.size(); i++ ) {
465 ds = (DelegationStruct)input.elementAt(i);
466
467 g0 = (Goal)ds.goals.elementAt(0);
468 if ( gid.equals(g0.getId()) )
469 reduced.addElement(ds);
470 }
471 Core.DEBUG(3,"sortFeasible reduced " + gid + "\n" + reduced);
472 boolean changed = true;
473 while( changed ) {
474 changed = false;
475 for( int i = 0; i < reduced.size()-1; i++ ) {
476
477 ds = (DelegationStruct)reduced.elementAt(i);
478 g0 = (Goal)ds.goals.elementAt(0);
479 ds = (DelegationStruct)reduced.elementAt(i+1);
480 g1 = (Goal)ds.goals.elementAt(0);
481 if ( g0.getCost() > g1.getCost() ) {
482 obj = reduced.elementAt(i);
483 reduced.setElementAt(reduced.elementAt(i+1),i);
484 reduced.setElementAt(obj,i+1);
485 changed = true;
486 }
487 }
488 }
489 Core.DEBUG(3,"sortFeasible results " + gid + "\n" + reduced);
490 return reduced;
491 }
492
493
494 public PlannerEnactStruct enact(Goal goal, Goal sla) {
495 PlannerEnactStruct es = new PlannerEnactStruct();
496 PlanRecord rec, image;
497
498 notifyMonitors(goal,START,PlanningEvent.ENACTMENT);
499
500 rec = lookUp(sla);
501 if ( rec == null ) {
502 es.ok = false;
503 notifyMonitors(goal,FAIL,PlanningEvent.ENACTMENT);
504 Core.DEBUG(3,"PlannerEnactStruct no sla found for\n" + sla);
505 return es;
506 }
507
508 rec.enact(es,goal,null,goal.getId(),new Hashtable());
509
510 if ( es.ok ) {
511 for( int i = 0; i < es.images.size(); i++ ) {
512 image = (PlanRecord)es.images.elementAt(i);
513 image.setState(PlanRecord.FIRM);
514 }
515 if ( !rec.hasMoreEnactments() )
516 rec.dispose();
517 notifyMonitors(goal,SUCCEED,PlanningEvent.ENACTMENT);
518 }
519 else {
520 notifyMonitors(goal,FAIL,PlanningEvent.ENACTMENT);
521 }
522
523 Core.DEBUG(3,"Final PlannerEnactStruct\n" + es);
524 return es;
525 }
526
527 int latestConfirmTime(Vector goals) {
528 Core.ERROR(goals,1012,this);
529 Core.ERROR(!goals.isEmpty(),1013,this);
530 int lct = now + plannerLength;
531 for( int i = 0; i < goals.size(); i++ )
532 lct = Math.min(lct,latestConfirmTime((Goal)goals.elementAt(i)));
533 return lct;
534 }
535 int latestConfirmTime(Goal goal) {
536 PlanRecord rec;
537 rec = lookUp(goal);
538 return rec.latestConfirmTime();
539 }
540
541 protected String makeIndex(Vector goals) {
542 Core.ERROR(goals,1014,this);
543 if ( goals.isEmpty() ) return null;
544
545 String[] Items = new String[goals.size()];
546 for( int i = 0; i < goals.size(); i++ )
547 Items[i] = ((Goal)goals.elementAt(i)).getId();
548
549 Misc.sort(Items);
550
551 String index = new String();
552 for(int i = 0; i < Items.length-1; i++ )
553 index += Items[i] + "/";
554 index += Items[Items.length-1];
555
556 return index;
557 }
558
559 protected void index(PlannerQueryStruct Results) {
560 String index = makeIndex(Results.goals);
561 Core.ERROR(BindTable.put(index,Results) == null,1015,this);
562 }
563
564 protected void removeFromIndexTable(Vector goals) {
565 Core.DEBUG(3,"Planner removeFromIndexTable");
566 String index = makeIndex(goals);
567 BindTable.remove(index);
568 }
569
570 public void book(int type, Vector goals, Vector records) {
571 Vector rootSet = new Vector();
572 PlanRecord root;
573
574 for(int i = 0; i < records.size(); i++ ) {
575 root = ((PlanRecord)records.elementAt(i)).getRoot();
576 if ( !rootSet.contains(root) ) rootSet.addElement(root);
577 }
578 Goal g;
579 for(int i = 0; i < goals.size(); i++ ) {
580 g = (Goal)goals.elementAt(i);
581 book(type,g,rootSet);
582 if ( type == PlanRecord.FIRM )
583 notifyMonitors(g,SUCCEED,PlanningEvent.PLANNING);
584 }
585 for(int i = 0; i < rootSet.size(); i++ ) {
586 root = (PlanRecord)rootSet.elementAt(i);
587 root.setState(type);
588 }
589 }
590
591 protected void book(int type, Goal goal, Vector rootSet) {
592 PlanRecord rec = lookUp(goal);
593 if ( rec != null ) {
594 rec.setState(type);
595 rootSet.removeElement(rec);
596 }
597 }
598
599 public void reject(Vector goals, Vector records) {
600
601 Core.DEBUG(3,"Planner Reject goals called " + goals);
602 removeFromIndexTable(goals);
603 Vector rootSet = new Vector();
604 PlanRecord root;
605
606 for(int i = 0; i < records.size(); i++ ) {
607 root = ((PlanRecord)records.elementAt(i)).getRoot();
608 if ( !rootSet.contains(root) ) rootSet.addElement(root);
609 }
610 Goal g;
611 for(int i = 0; i < goals.size(); i++ ) {
612 g = (Goal)goals.elementAt(i);
613 reject(g,rootSet);
614 notifyMonitors(g,FAIL,PlanningEvent.PLANNING);
615 }
616 for(int i = 0; i < rootSet.size(); i++ ) {
617 root = (PlanRecord)rootSet.elementAt(i);
618 root.dispose();
619 }
620 }
621
622 protected void reject(Goal goal, Vector rootSet) {
623
624 PlanRecord rec = lookUp(goal);
625 if ( rec != null ) {
626 rec.dispose();
627 rootSet.removeElement(rec);
628 }
629 }
630
631 Vector schedule(String key, PlanRecord parent, Vector path,
632 Vector goals, PlannerQueryStruct struct, boolean mode) {
633 Core.DEBUG(3,"schedule: 0");
634 Vector lpath;
635 Goal goal;
636 Vector sub_records, records = new Vector();
637 for(int i = 0; i < goals.size(); i++ ) {
638 goal = (Goal)goals.elementAt(i);
639 lpath = Misc.copyVector(path);
640 sub_records = schedule(key,parent,lpath,goal,struct,mode);
641 records = Misc.union(records,sub_records);
642 }
643 return records;
644 }
645
646 Vector schedule(String key, PlanRecord parent, Vector path,
647 Goal goal, PlannerQueryStruct struct, boolean mode) {
648
649 Core.DEBUG(3,"schedule: 1");
650
651 if ( parent != null ) {
652 goal = new Goal(goal);
653 Fact desc = goal.getFact();
654 int required = desc.getNumber();
655 required = anySideEffect(desc,parent,goal.getId(),required);
656 if ( required == 0 )
657 return new Vector();
658 else {
659 desc.setNumber(required);
660 goal.setFact(desc);
661 }
662 }
663
664 if ( !validTime(goal.getEndTime()) ) {
665 addToExternal(struct.external,goal);
666 return new Vector();
667 }
668
669 Vector tasks = context.TaskDb().findAll(goal.getFact(),path);
670
671 Core.DEBUG(3,"Tasks for: " + goal.getFactType());
672 Core.DEBUG(3,tasks);
673
674 return schedule(key,parent,path,goal,tasks,struct,mode);
675 }
676
677 protected void addToExternal(Vector List, Goal goal) {
678 Core.DEBUG(3,"Adding to external ... attempt");
679 String id = goal.getId();
680 Goal g;
681 for(int i = 0; i < List.size(); i++ ) {
682 g = (Goal)List.elementAt(i);
683 if ( id.equals(g.getId()) ) return;
684 }
685 Core.DEBUG(3,"Adding to external ... done");
686 List.addElement(goal);
687 }
688
689
690 Vector schedule(String key, PlanRecord parent, Vector path, Goal goal,
691 Vector tasks, PlannerQueryStruct struct, boolean mode) {
692
693 Core.DEBUG(3,"schedule: 2");
694 Core.DEBUG(3,"schedule: 2 Path0 = " + path);
695 Vector records;
696 Task t;
697
698 if ( tasks == null )
699 tasks = context.TaskDb().findAll(goal.getFact(),path);
700
701 Core.DEBUG(3,"schedule: 2 Path1 = " + path);
702
703 while( !tasks.isEmpty() ) {
704 t = (Task)tasks.firstElement();
705 records = (t.isPrimitive())
706 ? schedule_primitive(key,parent,path,goal,tasks,struct,mode)
707 : schedule_summary(key,parent,path,goal,tasks,struct,mode);
708
709 if ( !records.isEmpty() )
710 return records;
711 }
712 addToExternal(struct.external,goal);
713 return new Vector();
714 }
715
716
717 Vector schedule_summary(String key, PlanRecord parent, Vector path,
718 Goal goal, Vector tasks, PlannerQueryStruct struct,
719 boolean mode) {
720
721 Core.DEBUG(3,"schedule_summary");
722 Core.DEBUG(3,"schedule_summary: Path = " + path);
723 SummaryTask task = (SummaryTask)tasks.firstElement();
724 tasks.removeElementAt(0);
725
726 Vector records;
727 String node;
728 Decomposition decomposition;
729
730 decomposition = new Decomposition(this,key,parent,path,goal,task);
731 records = expand_summary(decomposition,struct,mode);
732 Core.DEBUG(3,"schedule_summary end:");
733 Core.DEBUG(3,struct);
734 return records;
735 }
736
737 Vector expand_summary(Decomposition decomposition, PlannerQueryStruct struct,
738 boolean mode) {
739
740 Core.DEBUG(3,"expand_summary");
741
742 Vector records, path, sub_tasks;
743 Fact[] consumed, produced;
744 String node, key;
745 Vector all_records = new Vector();
746 PlanRecord rec, parent;
747 SuppliedDb given;
748 TaskDb db = context.TaskDb();
749 Goal goal;
750
751 decomposition.reset();
752 while( (node = decomposition.nextNode()) != null ) {
753 Core.DEBUG(3,"expand_summary node ... " + node);
754 if ( !decomposition.isScheduled(node) &&
755 !decomposition.isQueued(node) ) {
756 consumed = decomposition.getPreconditions(node);
757 produced = decomposition.getPostconditions(node);
758 path = decomposition.getPath(node);
759 goal = decomposition.getGoal(node);
760 Core.DEBUG(3,"expand_summary: goal = " + goal);
761 sub_tasks = db.findAll(consumed,produced,path);
762 key = decomposition.getKey(node);
763 parent = decomposition.getParentRecord(node);
764 records = schedule(key,parent,path,goal,sub_tasks,struct,!EXPAND);
765 Core.DEBUG(3,"expand_summary record:");
766 Core.DEBUG(3,records);
767 if ( !records.isEmpty() ) {
768 decomposition.setRecords(node,records);
769 all_records = Misc.union(all_records,records);
770 }
771 else {
772 struct.decompositions.put(goal.getId(),decomposition);
773 given = decomposition.getSuppliedDb(node);
774 goal.setSuppliedDb(given);
775 decomposition.setQueued(node,true);
776 }
777 }
778 }
779 if ( decomposition.allNodesScheduled() ) {
780 decomposition.enforceLinks();
781 decomposition.reset();
782 while( (node = decomposition.nextNode()) != null ) {
783 Core.DEBUG(3,"expand_summary node: " + node);
784 rec = decomposition.getRecord(node);
785 Core.DEBUG(3,"expand_summary getRecord: " + rec);
786 if ( rec != null ) {
787 key = decomposition.getKey(node);
788 path = decomposition.getPath(node);
789 records = schedule_children(key,rec,path,struct,mode);
790 all_records = Misc.union(all_records,records);
791 }
792 }
793 }
794 Core.DEBUG(3,"expand_summary end");
795 Core.DEBUG(3,struct);
796 return all_records;
797 }
798
799 Vector schedule_primitive(String key, PlanRecord parent, Vector path,
800 Goal goal, Vector tasks, PlannerQueryStruct struct,
801 boolean mode) {
802
803 Core.DEBUG(3,"schedule_primitive");
804 PrimitiveTask task = (PrimitiveTask)tasks.firstElement();
805 tasks.removeElementAt(0);
806
807 PlanRecord rec;
808 int stime, etime, duration, top, lstime, ttime;
809 boolean space_found;
810 Fact consumed;
811 Vector sub_records;
812 Vector records = new Vector();
813
814 ResourceDb db = context.ResourceDb();
815 SuppliedDb given = goal.getSuppliedDb();
816
817 etime = goal.getEndTime();
818 ttime = task.getTime();
819 if ( goal.isContinuous() ) {
820 stime = goal.getStartTime();
821 lstime = stime-ttime;
822 duration = etime - lstime;
823 if ( duration/ttime < goal.getInvocations() )
824 return records;
825 }
826 else {
827 lstime = etime-ttime;
828 duration = ttime;
829 }
830
831 if ( !validTime(etime) ) return records;
832 if ( !validTime(lstime) ) return records;
833
834
835 for(int i = 0; i < task.countPreconditions(); i++ ) {
836 consumed = task.getPrecondition(i);
837 if ( consumed.isLocal() ) {
838
839
840 Core.DEBUG(3,"Checking consumed:\n" + consumed.pprint());
841 Core.DEBUG(3,"IsLocal: true");
842
843 Fact x1 = null, x2 = null, x = null;
844 if ( given != null ) {
845 x1 = given.evalLocal(consumed);
846 Core.DEBUG(3,"SuppliedDb contains fact:\n" + x1.pprint());
847 }
848 x2 = db.evalLocal(consumed);
849 if ( x1 == null && x2 == null )
850 return records;
851
852 if ( x1 != null && x2 != null ) {
853 Core.ERROR(x1.disjoin(x2),1016,this);
854 x = x1;
855 }
856 else if ( x1 == null )
857 x = x2;
858 else
859 x = x1;
860
861 Core.DEBUG(3,"Db contains fact:\n" + x.pprint());
862 Bindings b = new Bindings(context.whoami());
863 consumed.unifiesWith(x,b);
864 task.resolve(b);
865 Core.DEBUG(3,"IsLocal bindings: " + b);
866 }
867 else if ( consumed.isNegative() ) {
868 Core.DEBUG(3,"Checking negative:\n" + consumed.pprint());
869 Core.DEBUG(3,"IsNegative: true");
870
871 if ( !db.evalNegative(consumed) )
872 return records;
873
874 Core.DEBUG(3,"Db does not contain fact:\n" + consumed.pprint());
875 }
876 }
877
878 for(top = etime-1; validTime(top-duration); top-- ) {
879 for(int proc = 0; proc < plannerWidth; proc++ ) {
880 space_found = true;
881 for(int i = top; space_found && i > top-duration; i-- )
882 space_found = isFreeCell(proc,i) & space_found;
883 if ( space_found ) {
884 rec = new PlanRecord(this,key,parent,goal,task,proc,
885 top-duration+1,top+1);
886 rec.setPath(Misc.copyVector(path));
887 rec.setAlternativeTasks(tasks);
888
889 for(int i = top; i > top-duration; i-- )
890 assignCell(proc,i,rec);
891
892 struct.internal.addElement(rec);
893 records.addElement(rec);
894 path.addElement(goal.getFact());
895
896 sub_records = schedule_children(key,rec,path,struct,mode);
897 records = Misc.union(records,sub_records);
898 return records;
899 }
900 }
901 }
902
903
904
905 Core.DEBUG(3,"Space not found for: " + goal.getFactType());
906 Core.DEBUG(3,"tduration = " + duration);
907 Core.DEBUG(3,"tetime = " + etime);
908 Core.DEBUG(3,"tlstime = " + lstime);
909
910 return records;
911 }
912
913 protected Vector schedule_children(String key, PlanRecord rec, Vector path,
914 PlannerQueryStruct struct, boolean mode) {
915
916 Vector external, subgoals, sub_records, lpath;
917 Vector records = new Vector();
918 ResourceDb db = context.ResourceDb();
919 SuppliedDb given = rec.getSuppliedDb();
920
921 if ( mode == EXPAND ) {
922 external = struct.external;
923 struct.external = new Vector();
924 do {
925 if ( given != null )
926 given.allocateResources(rec);
927 subgoals = db.allocateResources(rec);
928 if ( !subgoals.isEmpty() ) {
929 lpath = Misc.copyVector(path);
930 sub_records = schedule(key,rec,lpath,subgoals,struct,mode);
931 records = Misc.union(records,sub_records);
932 }
933 } while ( struct.external.isEmpty() && !subgoals.isEmpty() );
934 struct.external = Misc.union(struct.external,external);
935 }
936 return records;
937 }
938
939
940 protected void resume_planning(DelegationStruct[] ds,
941 PlannerQueryStruct struct) {
942 Goal g;
943 boolean found;
944 Decomposition decomposition = null;
945 String key;
946 Vector path, records;
947 PlanRecord rec = null;
948
949 Core.DEBUG(3,"resume_planning ... ds/struct");
950 Core.DEBUG(3,ds);
951 Core.DEBUG(3,struct);
952
953 String consumer, consumer_id;
954 String producer, producer_id;
955 String use_ref;
956 int amount, start;
957 boolean consumed;
958
959 struct.external.removeAllElements();
960 for(int i = 0; i < ds.length; i++ ) {
961
962 g = (Goal)ds[i].goals.elementAt(0);
963
964 decomposition = (Decomposition)struct.decompositions.remove(g.getId());
965 if ( decomposition == null ) {
966 found = false;
967 for(int j = 0; !found && j < struct.internal.size(); j++ ) {
968 rec = (PlanRecord)struct.internal.elementAt(j);
969 found = rec.hasSubgoal(g.getId());
970 }
971 Core.ERROR(found,1017,this);
972
973 producer = ds[i].agent;
974 producer_id = g.getId();
975 consumer = context.whoami();
976 consumer_id = rec.getGoal().getId();
977 use_ref = context.newId("used");
978 start = rec.getStartTime();
979 int precond_position = rec.getConsumedPosition(producer_id);
980 consumed = rec.isPreconditionConsumed(precond_position);
981 amount = rec.getAmountUsed(precond_position);
982 Core.ERROR(amount > 0,1031,this);
983
984 g.addConsumer(producer, producer_id, consumer, consumer_id,
985 use_ref, ds[i].key, start, amount, consumed);
986
987 rec.getConsumedDb().update(producer_id+"/"+use_ref, producer_id);
988
989 path = rec.getChildPath();
990 key = rec.getKey();
991 schedule_children(key,rec,path,struct,EXPAND);
992 }
993 else {
994 String node = decomposition.getNodeWithGoalId(g.getId());
995 Core.DEBUG(3,"getNodeWithGoalId " + g.getId() + " " + node);
996 decomposition.setImage(node,g,ds[i].agent,ds[i].key);
997 expand_summary(decomposition,struct,EXPAND);
998 }
999 }
1000 }
1001
1002 public void goalConfirmed(Vector original_goals, Vector confirmed_goals,
1003 Vector selection) {
1004 Goal g, g1;
1005 Vector records;
1006 DelegationStruct ds;
1007 ProducerRecord pr;
1008 ConsumerRecord cr;
1009 PlanRecord rec;
1010 ConsumedDb cdb;
1011 ProducedDb pdb;
1012 boolean test;
1013 SuppliedDb given;
1014
1015
1016
1017 for(int i = 0; i < confirmed_goals.size(); i++ ) {
1018 g = (Goal)confirmed_goals.elementAt(i);
1019
1020 records = g.getProducerRecords();
1021 for(int j = 0; records != null && j < records.size(); j++ ) {
1022 pr = (ProducerRecord)records.elementAt(j);
1023 if ( pr.consumer.equals(context.whoami()) ) {
1024 rec = (PlanRecord)this.get(pr.consumer_id);
1025 Core.ERROR(rec,1001,this);
1026 cdb = rec.getConsumedDb();
1027 test = cdb.update(pr.producer_id+"/"+pr.use_ref,pr.use_ref);
1028 Core.ERROR(test,1002,this);
1029 }
1030 else {
1031 for(int k = 0; k < selection.size(); k++ ) {
1032 ds = (DelegationStruct)selection.elementAt(k);
1033
1034 g1 = (Goal)ds.goals.elementAt(0);
1035 given = g1.getSuppliedDb();
1036 if ( given != null && given.isReserved(pr.supply_ref) )
1037 g1.addProducer(pr);
1038 }
1039 }
1040 }
1041
1042 records = g.getConsumerRecords();
1043 for(int j = 0; records != null && j < records.size(); j++ ) {
1044 cr = (ConsumerRecord)records.elementAt(j);
1045 if ( cr.producer.equals(context.whoami()) ) {
1046 rec = (PlanRecord)this.get(cr.producer_id);
1047 Core.ERROR(rec,1003,this);
1048 pdb = rec.getProducedDb();
1049 Core.DEBUG(3,"CdB replacing " + cr.producer_id + " with " +
1050 cr.consumer_id+"/"+cr.use_ref);
1051 Core.DEBUG(3,records);
1052 Core.DEBUG(3,rec);
1053
1054 test = pdb.replaceOrAdd(cr.producer_id,
1055 cr.consumer_id + "/" + cr.use_ref,
1056 cr.start, cr.amount, cr.consumed );
1057 Core.DEBUG(3,"Replacement is " + test);
1058 Core.ERROR(test,1004,this);
1059 }
1060 else {
1061 for(int k = 0; k < selection.size(); k++ ) {
1062 ds = (DelegationStruct)selection.elementAt(k);
1063
1064 g1 = (Goal)ds.goals.elementAt(0);
1065 g1.addConsumer(cr);
1066 }
1067 }
1068 }
1069 }
1070 }
1071
1072 protected boolean validTime(int t) {
1073 return (now + plannerLength >= t && t >= now);
1074 }
1075
1076 protected boolean validProc(int proc) {
1077 return ( proc >= 0 && proc < plannerWidth);
1078 }
1079
1080 protected boolean isFreeCell(int proc, int t) {
1081 Core.ERROR(proc >= 0 && proc < plannerWidth, 1018,this);
1082 Core.ERROR(now + plannerLength > t && t >= now, 1019,this);
1083 return (table[proc][t-now] == null);
1084 }
1085
1086 /***
1087 1.3 promoted to public - used to decide which job to execute
1088 */
1089
1090 public void shuffle() {
1091 checkRecords();
1092 for(int i = 0; i < plannerWidth; i++ ) {
1093 for(int j = 0; j < plannerLength-1; j++ )
1094 assignCell(i,j+now,table[i][j+1]);
1095 assignCell(i,plannerLength-1+now,null);
1096 }
1097 now++;
1098 }
1099
1100
1101 synchronized void executeEarliest() {
1102 PlanRecord rec;
1103 Enumeration enum = this.elements();
1104 while( enum.hasMoreElements() ) {
1105 rec = (PlanRecord)enum.nextElement();
1106 if ( rec.getState() == PlanRecord.FIRM &&
1107 rec.isDiscrete() &&
1108 rec.getStartTime() > now &&
1109 rec.hasEnoughResources() )
1110 executeEarliest(rec);
1111 }
1112 }
1113
1114
1115
1116 synchronized void executeEarliest(PlanRecord rec) {
1117 int stime, etime, duration, top;
1118 boolean space_found;
1119
1120 etime = rec.getEndTime();
1121 stime = rec.getStartTime();
1122 duration = etime - stime;
1123
1124 if ( !validTime(etime) ) return;
1125 if ( !validTime(stime) ) return;
1126
1127 for( top = now+1; top < stime; top++ ) {
1128 for( int proc = 0; proc < plannerWidth; proc++ ) {
1129 space_found = true;
1130 for( int i = top; i < top+duration; i++ ) {
1131 space_found = space_found && (isFreeCell(proc,i) ||
1132 rec.isOnCell(proc,i));
1133 if ( !space_found ) break;
1134 }
1135 if ( space_found ) {
1136 Core.DEBUG(3,"Reassigning rec " + rec.getId() +
1137 " from [" + stime + "," + etime + "] to [" +
1138 top + "," + (top+duration) +"]");
1139 rec.reassign(proc,top);
1140 for(int i = top; i < top+duration; i++ )
1141 assignCell(proc,i,rec);
1142 return;
1143 }
1144 }
1145 }
1146 }
1147
1148
1149
1150 synchronized boolean incrementProcessorTime(PlanRecord rec,int time) {
1151 if ( !validTime(time) ) return false;
1152 if ( isFreeCell(rec.getProc(),time) ) {
1153 rec.incrementTime(time);
1154 assignCell(rec.getProc(),time,rec);
1155 return true;
1156 }
1157 else {
1158
1159
1160 }
1161 return false;
1162 }
1163
1164
1165 /***
1166 start Firmly booked tasks & cancel Tentatively booked ones
1167 1.3 - promoted to public
1168 // synched ?
1169 */
1170 synchronized public void checkRecords() {
1171 PlanRecord rec, root;
1172 ExecutionMonitor monitor = context.ExecutionMonitor();
1173 for( int i = 0; i < plannerWidth; i++ ) {
1174 if ( (rec = table[i][0]) != null ) {
1175 switch( rec.getState() ) {
1176 case PlanRecord.JEOPARDY:
1177 case PlanRecord.AGREEMENT:
1178 break;
1179 case PlanRecord.TEMP:
1180 case PlanRecord.TENTATIVE:
1181
1182 root = rec.getRoot();
1183 root.dispose();
1184 break;
1185 case PlanRecord.FIRM:
1186 if ( rec.exec() )
1187 ;
1188 break;
1189 case PlanRecord.RUNNING:
1190 if ( rec.overRun() )
1191 ;
1192 else
1193 break;
1194 case PlanRecord.FAILED:
1195
1196 root = rec.getRoot();
1197 root.dispose();
1198 break;
1199 case PlanRecord.COMPLETED:
1200
1201 rec.dispose();
1202 break;
1203 }
1204 }
1205 }
1206 if ( context.getExecuteEarliest() ) executeEarliest();
1207 }
1208
1209
1210 public void notifyReceived(Fact f1, String goalId, String subgoalId) {
1211 try {
1212 Core.DEBUG(3,"NotifyReceived...\n" + f1.pprint());
1213 PlanRecord rec = (PlanRecord)this.get(goalId);
1214 Core.ERROR(rec,1020,this);
1215 context.ResourceDb().add(f1);
1216 rec.preconditionExists(subgoalId);}
1217 catch (Exception e) {
1218 e.printStackTrace();
1219 }
1220
1221 }
1222
1223 protected void assignCell(int proc, int t, PlanRecord rec) {
1224 Core.ERROR(proc >= 0 && proc < plannerWidth,1021,this);
1225 Core.ERROR(now + plannerLength > t && t >= now,1022,this);
1226 table[proc][t-now] = rec;
1227 }
1228
1229 void freeCell( int proc, int t) {
1230 Core.ERROR(proc >= 0 && proc < plannerWidth,1023,this);
1231 if ( now + plannerLength > t && t >= now ) {
1232 table[proc][t-now] = null;
1233 }
1234 }
1235
1236 void freeCells(int proc, int s, int e) {
1237 for(int i = s; i < e; i++ ) freeCell(proc,i);
1238 }
1239
1240 public Goal recreateSubgoal(Goal goal) {
1241 PlanRecord rec;
1242 String goalId = goal.getId();
1243 Enumeration enum = this.elements();
1244 while( enum.hasMoreElements() ) {
1245 rec = (PlanRecord) enum.nextElement();
1246 if ( rec.hasSubgoal(goalId) )
1247 return rec.recreateSubgoal(goal);
1248 }
1249 Goal g = new Goal(goal);
1250 g.setId(context.newId("subgoal"));
1251 g.setImage(goal.getId());
1252 g.setConfirmTime(new Time(now() +
1253 context.getReplanPeriod()));
1254 return g;
1255 }
1256
1257
1258 public void reconfirmParentOf(Vector goals) {
1259 for( int i = 0; i < goals.size(); i++ )
1260 reconfirmParentOf( (Goal)goals.elementAt(i) );
1261 }
1262
1263
1264 public void reconfirmParentOf(Goal g) {
1265 PlanRecord rec;
1266 String goalId = g.getId();
1267 Enumeration enum = this.elements();
1268 while( enum.hasMoreElements() ) {
1269 rec = (PlanRecord) enum.nextElement();
1270 if ( rec.hasSubgoal(goalId) ) {
1271 rec.reconfirm();
1272 return;
1273 }
1274 else if ( rec.getGoal().getId().equals(goalId) ) {
1275 if ( rec.getParent() != null ) {
1276 rec.getParent().reconfirm();
1277 return;
1278 }
1279 }
1280 }
1281 Core.DEBUG(3,"reconfirmParentOf error ... " + g);
1282 Core.ERROR(null,1024,this);
1283 }
1284
1285
1286 public void failParentOf(Vector goals) {
1287 for( int i = 0; i < goals.size(); i++ )
1288 failParentOf( (Goal)goals.elementAt(i) );
1289 }
1290
1291
1292 public void failParentOf(Goal g) {
1293 PlanRecord rec;
1294 String goalId = g.getId();
1295 Enumeration enum = this.elements();
1296 while( enum.hasMoreElements() ) {
1297 rec = (PlanRecord) enum.nextElement();
1298 if ( rec.hasSubgoal(goalId) ) {
1299 rec.setState(PlanRecord.FAILED);
1300 return;
1301 }
1302 }
1303 Core.DEBUG(3,"failParentOf error ... " + g);
1304
1305 }
1306
1307
1308 void softFailParentOf(Vector goals, PlannerQueryStruct struct, int mode) {
1309 Core.DEBUG(3,"softFailParentOf Goal = " + goals);
1310 Core.DEBUG(3,"softFailParentOf PlannerQueryStruct = " + struct);
1311
1312 PlanRecord rec = null;
1313 Goal g, goal = null;
1314 String goalId;
1315 boolean found;
1316 Decomposition decomposition;
1317
1318 for(int i = 0; i < goals.size(); i++ ) {
1319 g = (Goal)goals.elementAt(i);
1320 goalId = g.getId();
1321
1322
1323 for(int j = 0; j < struct.external.size(); j++ ) {
1324 goal = (Goal)struct.external.elementAt(j);
1325 if ( goalId.equals(goal.getId()) ) {
1326 struct.external.removeElementAt(j--);
1327 break;
1328 }
1329 }
1330
1331 decomposition = (Decomposition)struct.decompositions.remove(g.getId());
1332 if ( decomposition != null ) {
1333
1334 }
1335 else {
1336 found = false;
1337 for(int j = 0; !found && j < struct.internal.size(); j++ ) {
1338 rec = (PlanRecord) struct.internal.elementAt(j);
1339 found = rec.hasSubgoal(goalId);
1340 }
1341 if ( found )
1342 rec.softFail(struct,mode);
1343 }
1344 }
1345
1346
1347 for(int i = 0; i < struct.internal.size(); i++ ) {
1348 rec = (PlanRecord)struct.internal.elementAt(i);
1349 if ( !containsRecord(rec) )
1350 struct.internal.removeElementAt(i--);
1351 }
1352
1353 Enumeration enum = struct.decompositions.keys();
1354 while( enum.hasMoreElements() ) {
1355 goalId = (String)enum.nextElement();
1356 found = false;
1357 for(int i = 0; !found && i < struct.external.size(); i++ ) {
1358 goal = (Goal)struct.external.elementAt(i);
1359 found = goalId.equals(goal.getId());
1360 }
1361 if ( !found ) struct.decompositions.remove(goalId);
1362 }
1363 }
1364
1365 /***
1366 * Use a PlanningMonitor if your code needs to react to changes in the Planner
1367 */
1368 public void addPlanningMonitor(PlanningMonitor monitor, long type) {
1369 if ( (type & PlanningEvent.START_MASK) != 0 )
1370 eventMonitor[START].add(monitor);
1371 if ( (type & PlanningEvent.FAIL_MASK) != 0 )
1372 eventMonitor[FAIL].add(monitor);
1373 if ( (type & PlanningEvent.SUCCEED_MASK) != 0 )
1374 eventMonitor[SUCCEED].add(monitor);
1375 }
1376
1377 public void removePlanningMonitor(PlanningMonitor monitor, long type) {
1378 if ( (type & PlanningEvent.START_MASK) != 0 )
1379 eventMonitor[START].remove(monitor);
1380 if ( (type & PlanningEvent.FAIL_MASK) != 0 )
1381 eventMonitor[FAIL].remove(monitor);
1382 if ( (type & PlanningEvent.SUCCEED_MASK) != 0 )
1383 eventMonitor[SUCCEED].remove(monitor);
1384 }
1385
1386 /***
1387 * Use a PlanStepMonitor if your code needs to react to state changes in a
1388 * particular plan
1389 */
1390 public void addPlanStepMonitor(PlanStepMonitor monitor, long type,
1391 boolean notify_previous) {
1392 addPlanStepMonitor(monitor,type);
1393 if ( !notify_previous ) return;
1394
1395 Enumeration enum = elements();
1396 PlanRecord record;
1397 PlanStepEvent event;
1398
1399 while( enum.hasMoreElements() ) {
1400 record = (PlanRecord)enum.nextElement();
1401 event = new PlanStepEvent(this,record,PlanStepEvent.CREATE_MASK);
1402 monitor.planStepCreatedEvent(event);
1403 }
1404 }
1405
1406 public void addPlanStepMonitor(PlanStepMonitor monitor, long type) {
1407 if ( (type & PlanStepEvent.CREATE_MASK) != 0 )
1408 eventMonitor[CREATE].add(monitor);
1409 if ( (type & PlanStepEvent.DISPOSE_MASK) != 0 )
1410 eventMonitor[DISPOSE].add(monitor);
1411 if ( (type & PlanStepEvent.STATE_CHANGE_MASK) != 0 )
1412 eventMonitor[STATE_CHANGE].add(monitor);
1413 }
1414
1415 public void removePlanStepMonitor(PlanStepMonitor monitor, long type) {
1416 if ( (type & PlanStepEvent.CREATE_MASK) != 0 )
1417 eventMonitor[CREATE].remove(monitor);
1418 if ( (type & PlanStepEvent.DISPOSE_MASK) != 0 )
1419 eventMonitor[DISPOSE].remove(monitor);
1420 if ( (type & PlanStepEvent.STATE_CHANGE_MASK) != 0 )
1421 eventMonitor[STATE_CHANGE].remove(monitor);
1422 }
1423
1424 void notifyMonitors(Goal goal, int event_type, int sub_type) {
1425 if ( eventMonitor[event_type].isEmpty() ) return;
1426
1427 Enumeration enum = eventMonitor[event_type].elements();
1428 PlanningMonitor monitor;
1429 PlanningEvent event;
1430 switch(event_type) {
1431 case START:
1432 event = new PlanningEvent(this,goal,PlanningEvent.START_MASK,sub_type);
1433 while( enum.hasMoreElements() ) {
1434 monitor = (PlanningMonitor)enum.nextElement();
1435 monitor.planningStartedEvent(event);
1436 }
1437 break;
1438 case FAIL:
1439 event = new PlanningEvent(this,goal,PlanningEvent.FAIL_MASK,sub_type);
1440 while( enum.hasMoreElements() ) {
1441 monitor = (PlanningMonitor)enum.nextElement();
1442 monitor.planningFailedEvent(event);
1443 }
1444 break;
1445 case SUCCEED:
1446 event = new PlanningEvent(this,goal,PlanningEvent.SUCCEED_MASK,sub_type);
1447 while( enum.hasMoreElements() ) {
1448 monitor = (PlanningMonitor)enum.nextElement();
1449 monitor.planningSucceededEvent(event);
1450 }
1451 break;
1452 }
1453 }
1454
1455 void notifyMonitors(PlanRecord record, int type) {
1456 if ( eventMonitor[type].isEmpty() ) return;
1457
1458 Enumeration enum = eventMonitor[type].elements();
1459 Core.ERROR(enum,2001,this);
1460 PlanStepMonitor monitor;
1461 PlanStepEvent event;
1462 switch(type) {
1463 case CREATE:
1464 event = new PlanStepEvent(this,record,PlanStepEvent.CREATE_MASK);
1465 while( enum.hasMoreElements() ) {
1466 monitor = (PlanStepMonitor)enum.nextElement();
1467 monitor.planStepCreatedEvent(event);
1468 }
1469 break;
1470 case DISPOSE:
1471 event = new PlanStepEvent(this,record,PlanStepEvent.DISPOSE_MASK);
1472 while( enum.hasMoreElements() ) {
1473 monitor = (PlanStepMonitor)enum.nextElement();
1474 monitor.planStepDisposedEvent(event);
1475 }
1476 break;
1477 case STATE_CHANGE:
1478 event = new PlanStepEvent(this,record,PlanStepEvent.STATE_CHANGE_MASK);
1479 while( enum.hasMoreElements() ) {
1480 monitor = (PlanStepMonitor)enum.nextElement();
1481 monitor.planStepStateChangedEvent(event);
1482 }
1483 break;
1484 }
1485 }
1486
1487
1488 /***
1489 now introduced to prevent the need for a call back to the context object
1490 to get timeing - decouples the Planner a bit..
1491 */
1492 protected double now () {
1493 return context.now();
1494 }
1495
1496 }