1 package cz.cuni.amis.pogamut.base.component.controller;
2
3 import java.util.HashMap;
4 import java.util.Map;
5 import java.util.logging.Level;
6 import java.util.logging.Logger;
7
8 import cz.cuni.amis.pogamut.base.agent.IAgentId;
9 import cz.cuni.amis.pogamut.base.component.IComponent;
10 import cz.cuni.amis.pogamut.base.component.ISharedComponent;
11 import cz.cuni.amis.pogamut.base.component.bus.event.IFatalErrorEvent;
12 import cz.cuni.amis.pogamut.base.component.bus.event.impl.FatalErrorEvent;
13 import cz.cuni.amis.pogamut.base.component.exception.ComponentCantPauseException;
14 import cz.cuni.amis.pogamut.base.component.exception.ComponentCantResumeException;
15 import cz.cuni.amis.pogamut.base.component.exception.ComponentCantStartException;
16 import cz.cuni.amis.pogamut.base.component.lifecyclebus.ILifecycleBus;
17 import cz.cuni.amis.utils.ExceptionToString;
18 import cz.cuni.amis.utils.NullCheck;
19 import cz.cuni.amis.utils.exception.PogamutException;
20 import cz.cuni.amis.utils.flag.FlagListener;
21 import cz.cuni.amis.utils.token.IToken;
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45 public class SharedComponentController<COMPONENT extends ISharedComponent> extends AbstractComponentControllerBase<COMPONENT> implements ISharedComponentController<COMPONENT> {
46
47 protected class ComponentStateListener implements FlagListener<ComponentState> {
48
49 protected IAgentId agentId;
50
51 public ComponentStateListener(IAgentId agentId) {
52 this.agentId = agentId;
53 }
54
55 public IAgentId getAgentId() {
56 return agentId;
57 }
58
59 @Override
60 public void flagChanged(ComponentState changedValue) {
61 stateChanged(agentId, changedValue);
62 }
63
64 }
65
66
67
68
69
70
71
72
73
74
75 protected class LocalController {
76
77 protected ComponentStateListener listener;
78
79 protected IComponentController controller;
80
81 public LocalController(IAgentId agentId, IComponentController controller) {
82 NullCheck.check(agentId, "agentId");
83 this.listener = new ComponentStateListener(agentId);
84 this.controller = controller;
85 NullCheck.check(this.controller, "controller");
86 this.controller.getState().addListener(listener);
87 }
88
89 public IAgentId getAgentId() {
90 return listener.getAgentId();
91 }
92
93 public void destroy() {
94 this.controller.getState().removeListener(listener);
95 }
96
97 }
98
99 protected class ControlHelper implements IComponentControlHelper {
100
101 protected IAgentId agentId;
102
103 public ControlHelper(IAgentId agentId) {
104 this.agentId = agentId;
105 }
106
107 @Override
108 public void preStart() throws PogamutException {
109 localPreStart(agentId);
110 }
111
112 @Override
113 public void start() throws PogamutException {
114 localStart(agentId);
115 }
116
117 @Override
118 public void preStartPaused() throws PogamutException {
119 localPreStartPaused(agentId);
120 }
121
122 @Override
123 public void startPaused() throws PogamutException {
124 localStartPaused(agentId);
125 }
126
127 @Override
128 public void prePause() throws PogamutException {
129 localPrePause(agentId);
130 }
131
132 @Override
133 public void pause() throws PogamutException {
134 localPause(agentId);
135 }
136
137 @Override
138 public void preResume() throws PogamutException {
139 localPreResume(agentId);
140 }
141
142 @Override
143 public void resume() throws PogamutException {
144 localResume(agentId);
145 }
146
147 @Override
148 public void preStop() throws PogamutException {
149 localPreStop(agentId);
150 }
151
152 @Override
153 public void stop() throws PogamutException {
154 localStop(agentId);
155 }
156
157 @Override
158 public void kill() {
159 localKill(agentId);
160 }
161
162 @Override
163 public void reset() throws PogamutException {
164 localReset(agentId);
165 }
166
167 }
168
169
170
171
172 protected Object ctrlMutex = new Object();
173
174
175
176
177
178 protected Map<IAgentId, ControlHelper> localControlHelpers = new HashMap<IAgentId, ControlHelper>();
179
180
181
182
183
184 protected Map<IAgentId, LocalController> localControllers = new HashMap<IAgentId, LocalController>();
185
186
187
188
189 protected Map<IAgentId, ComponentState> componentStates = new HashMap<IAgentId, ComponentState>();
190
191
192
193
194
195 protected Map<ComponentState, Integer> componentStateCount = new HashMap<ComponentState, Integer>();
196
197
198
199
200 protected IFatalErrorEvent fatalError;
201
202
203
204
205
206
207
208
209 public SharedComponentController(COMPONENT component, ISharedComponentControlHelper componentControl, Logger log) {
210 super(component, componentControl, log);
211
212
213 for(ComponentState state : ComponentState.values()) {
214 componentStateCount.put(state, 0);
215 }
216 }
217
218
219
220
221
222
223
224 @Override
225 public ISharedComponentControlHelper getComponentControl() {
226 return (ISharedComponentControlHelper) super.getComponentControl();
227 }
228
229 @Override
230 public void addComponentBus(IAgentId agentId, ILifecycleBus bus, ComponentDependencies dependencies) {
231 synchronized(ctrlMutex) {
232 if (isUsedBy(agentId)) {
233 throw new PogamutException(id(component) + "[" + getState().getFlag() + "] is already a member of the " + agentId.getToken() + " lifecycle bus!", this);
234 }
235 ControlHelper helper = new ControlHelper(agentId);
236 localControlHelpers.put(agentId, helper);
237 IComponentController<COMPONENT> controller = bus.addLifecycleManagement(component, helper, dependencies);
238 LocalController localController = new LocalController(agentId, controller);
239 localControllers.put(agentId, localController);
240
241 setState(agentId, controller.getState().getFlag());
242 }
243 }
244
245 @Override
246 public void removeComponentBus(IAgentId agentId, ILifecycleBus bus) {
247 synchronized(ctrlMutex) {
248 if (!isUsedBy(agentId)) {
249
250 if (log.isLoggable(Level.WARNING)) log.warning(id(component) + "[" + getState().getFlag() + "] is not registered for agent " + agentId.getToken() + ", can't perform removeComponentBus().");
251 return;
252 }
253
254
255 bus.removeLifecycleManagement(component);
256
257
258 localControllers.remove(agentId);
259
260
261 bus.remove(component);
262 bus.remove(this);
263
264
265 setState(agentId, null);
266 }
267 }
268
269 @Override
270 public boolean isUsedBy(IAgentId agentId) {
271 return localControllers.containsKey(agentId);
272 }
273
274 @Override
275 public boolean isDependent(IAgentId agentId, IToken componentId) {
276 LocalController helper = localControllers.get(agentId);
277 if (helper == null) {
278 if (log.isLoggable(Level.WARNING)) log.warning(id(component) + "[" + getState().getFlag() + "] is not registered for agent " + agentId.getToken() + ", can't perform isDependent(" + componentId.getToken() + ").");
279 return false;
280 }
281 return helper.controller.isDependent(componentId);
282 }
283
284 @Override
285 public boolean isDependent(IAgentId agentId, IComponent component) {
286 LocalController helper = localControllers.get(agentId);
287 if (helper == null) {
288 if (log.isLoggable(Level.WARNING)) log.warning(id(component) + "[" + getState().getFlag() + "] is not registered for agent " + agentId.getToken() + ", can't perform isDependent(" + id(component) + ").");
289 return false;
290 }
291 return helper.controller.isDependent(component);
292 }
293
294 @Override
295 public void fatalError(String message) {
296 kill(null, message, null);
297 }
298
299 @Override
300 public void fatalError(String message, Throwable e) {
301 kill(null, message, e);
302 }
303
304 @Override
305 public IFatalErrorEvent getFatalError() {
306 return fatalError;
307 }
308
309 @Override
310 public void manualStart(String reason) {
311 synchronized(ctrlMutex) {
312 if (notInState(ComponentState.INSTANTIATED, ComponentState.RESETED, ComponentState.STOPPED)) {
313 throw new ComponentCantStartException(id(component) + " in state " + getState().getFlag() + ", can't manual start (" + reason + ")!", this);
314 }
315 start();
316 }
317 }
318
319 @Override
320 public void manualStartPaused(String reason) {
321 synchronized(ctrlMutex) {
322 if (notInState(ComponentState.INSTANTIATED, ComponentState.RESETED, ComponentState.STOPPED)) {
323 throw new ComponentCantStartException(id(component) + "[" + getState().getFlag() + "], can't manual start paused (reason: " + reason + ")!", this);
324 }
325 startPaused();
326 }
327 }
328
329 @Override
330 public void manualPause(String reason) {
331 synchronized(ctrlMutex) {
332 if (notInState(ComponentState.RUNNING)) {
333 throw new ComponentCantStartException(id(component) + "[" + getState().getFlag() + "], can't manual pause (reason: " + reason + ")!", this);
334 }
335 startPaused();
336 }
337 }
338
339 @Override
340 public void manualResume(String reason) {
341 synchronized(ctrlMutex) {
342 if (notInState(ComponentState.PAUSED)) {
343 throw new ComponentCantStartException(id(component) + "[" + getState().getFlag() + "], can't manual reason (reason: " + reason + ")!", this);
344 }
345 resume();
346 }
347 }
348
349 @Override
350 public void manualStop(String reason) {
351 synchronized(ctrlMutex) {
352 if (notInState(ComponentState.PAUSED, ComponentState.RUNNING)) {
353 throw new ComponentCantStartException(id(component) + "[" + getState().getFlag() + "], can't manual reason (reason: " + reason + ")!", this);
354 }
355 stop();
356 }
357 }
358
359 @Override
360 public void manualKill(String reason) {
361 synchronized(ctrlMutex) {
362 if (inState(ComponentState.KILLING, ComponentState.KILLED)) {
363 return;
364 }
365 kill(null, reason, null);
366 }
367 }
368
369
370
371
372
373
374
375
376
377
378
379
380
381 public int getStateCount(ComponentState... states) {
382 if (states == null) return 0;
383 if (states.length == 0) return 0;
384 if (states.length == 1) return componentStateCount.get(states[0]);
385 int count = 0;
386 for (ComponentState state : states) {
387 count += this.componentStateCount.get(state);
388 }
389 return count;
390 }
391
392
393
394
395
396
397 protected void checkStateCount(int newCount, ComponentState state) {
398 if (newCount < 0) throw new PogamutException(id(component) + "[" + getState().getFlag() + "] attempt to change state count of " + state + " to " + newCount + ", invalid.", this);
399 if (newCount > componentStates.size()) throw new PogamutException(id(component) + "[" + getState().getFlag() + "] attempt to change state count of " + state + " to " + newCount + " > " + componentStates.size() + " = all-component-states state count, invalid.", this);
400 }
401
402
403
404
405
406 protected int alterStateCount(ComponentState state, int change) {
407 Integer newCount = componentStateCount.get(state) + change;
408 checkStateCount(newCount, state);
409 componentStateCount.put(state, newCount);
410 return newCount;
411 }
412
413
414
415
416
417 protected int increaseStateCount(ComponentState state) {
418 return alterStateCount(state, 1);
419 }
420
421
422
423
424
425
426 protected int increaseStateCount(ComponentState state, int n) {
427 return alterStateCount(state, n);
428 }
429
430
431
432
433
434 protected int decreaseStateCount(ComponentState state) {
435 return alterStateCount(state, -1);
436 }
437
438
439
440
441
442 protected int decreaseStateCount(ComponentState state, int n) {
443 return alterStateCount(state, -n);
444 }
445
446
447
448
449
450
451
452 protected void localPreStart(IAgentId agentId) {
453 synchronized(ctrlMutex) {
454 if (log != null && log.isLoggable(Level.FINER)) log.finer(id(component) + "[" + getState().getFlag() + "] processing localPreStart(" + agentId + ")");
455 switch(getState().getFlag()) {
456 case INSTANTIATED:
457 case STOPPED:
458 case RESETED:
459 if (log != null && log.isLoggable(Level.FINER)) log.finer(id(component) + "[" + getState().getFlag() + "] must start!");
460 start();
461 break;
462 case PAUSED:
463 if (log != null && log.isLoggable(Level.FINER)) log.finer(id(component) + "[" + getState().getFlag() + "] must resume!");
464 resume();
465 break;
466 case STARTING:
467 case STARTING_PAUSED:
468 case PAUSING:
469 case RESUMING:
470 case STOPPING:
471 case KILLING:
472 case RESETTING:
473
474 throw new ComponentCantStartException(id(component) + "[" + getState().getFlag() + "] STATE INVALID AT THIS POINT!", this);
475 case RUNNING:
476
477 break;
478 case KILLED:
479 if (log != null && log.isLoggable(Level.FINER)) log.finer(id(component) + "[" + getState().getFlag() + "] must start! But is in killed state, must be reset()ed first in order to start!");
480 reset();
481 if (notInState(ComponentState.RESETED)) throw new PogamutException(id(component) + "[" + getState().getFlag() + "] reset has failed, could not resolve the state change.", this);
482 start();
483 break;
484 }
485 if (log != null && log.isLoggable(Level.FINER)) log.finer(id(component) + "[" + getState().getFlag() + "] calling componentControlHelper.localPreStart(" + agentId + ")");
486 getComponentControl().localPreStart(agentId);
487 }
488 }
489
490 protected void localStart(IAgentId agentId) {
491 synchronized(ctrlMutex) {
492 if (log != null && log.isLoggable(Level.FINER)) log.finer(id(component) + "[" + getState().getFlag() + "] processing localStart(" + agentId + ")");
493 switch(getState().getFlag()) {
494 case INSTANTIATED:
495 case STOPPED:
496 case RESETED:
497 if (log != null && log.isLoggable(Level.FINER)) log.finer(id(component) + "[" + getState().getFlag() + "] must start!");
498 start();
499 break;
500 case PAUSED:
501 if (log != null && log.isLoggable(Level.FINER)) log.finer(id(component) + "[" + getState().getFlag() + "] must resume!");
502 resume();
503 break;
504 case RUNNING:
505
506 break;
507 case STARTING:
508 case STARTING_PAUSED:
509 case PAUSING:
510 case RESUMING:
511 case STOPPING:
512 case KILLING:
513 case RESETTING:
514
515 throw new ComponentCantStartException(id(component) + "[" + getState().getFlag() + "] STATE INVALID AT THIS POINT!", this);
516
517 case KILLED:
518 if (log != null && log.isLoggable(Level.FINER)) log.finer(id(component) + "[" + getState().getFlag() + "] must start! But is in killed state, must be reset()ed first in order to start!");
519 reset();
520 if (notInState(ComponentState.RESETED)) throw new PogamutException(id(component) + "[" + getState().getFlag() + "] reset has failed, could not resolve the state change.", this);
521 start();
522 break;
523 }
524 if (log != null && log.isLoggable(Level.FINER)) log.finer(id(component) + "[" + getState().getFlag() + "] calling componentControlHelper.localStart(" + agentId + ")");
525 getComponentControl().localStart(agentId);
526 }
527 }
528
529 protected void localPreStartPaused(IAgentId agentId) {
530 synchronized(ctrlMutex) {
531 if (log != null && log.isLoggable(Level.FINER)) log.finer(id(component) + "[" + getState().getFlag() + "] processing localPreStartPaused(" + agentId + ")");
532 switch(getState().getFlag()) {
533 case INSTANTIATED:
534 case STOPPED:
535 case RESETED:
536 if (log != null && log.isLoggable(Level.FINER)) log.finer(id(component) + "[" + getState().getFlag() + "] must start-paused!");
537 startPaused();
538 break;
539 case RUNNING:
540 case PAUSED:
541
542 break;
543 case STARTING:
544 case STARTING_PAUSED:
545 case PAUSING:
546 case RESUMING:
547 case STOPPING:
548 case KILLING:
549 case RESETTING:
550
551 throw new ComponentCantStartException(id(component) + "[" + getState().getFlag() + "] STATE INVALID AT THIS POINT!", this);
552 case KILLED:
553 if (log != null && log.isLoggable(Level.FINER)) log.finer(id(component) + "[" + getState().getFlag() + "] must start-paused! But is in killed state, must be reset()ed first in order to start-paused!");
554 reset();
555 if (notInState(ComponentState.RESETED)) throw new PogamutException(id(component) + "[" + getState().getFlag() + "] reset has failed, could not resolve the state change.", this);
556 startPaused();
557 break;
558 }
559 if (log != null && log.isLoggable(Level.FINER)) log.finer(id(component) + "[" + getState().getFlag() + "] calling componentControlHelper.localPreStartPaused(" + agentId + ")");
560 getComponentControl().localPreStartPaused(agentId);
561 }
562 }
563
564 protected void localStartPaused(IAgentId agentId) {
565 synchronized(ctrlMutex) {
566 if (log != null && log.isLoggable(Level.FINER)) log.finer(id(component) + "[" + getState().getFlag() + "] processing localStartPaused(" + agentId + ")");
567 switch(getState().getFlag()) {
568 case INSTANTIATED:
569 case STOPPED:
570 case RESETED:
571 if (log != null && log.isLoggable(Level.FINER)) log.finer(id(component) + "[" + getState().getFlag() + "] must start-paused!");
572 startPaused();
573 break;
574 case RUNNING:
575 case PAUSED:
576
577 break;
578 case STARTING:
579 case STARTING_PAUSED:
580 case PAUSING:
581 case RESUMING:
582 case STOPPING:
583 case KILLING:
584 case RESETTING:
585
586 throw new ComponentCantStartException(id(component) + "[" + getState().getFlag() + "] STATE INVALID AT THIS POINT!", this);
587 case KILLED:
588 if (log != null && log.isLoggable(Level.FINER)) log.finer(id(component) + "[" + getState().getFlag() + "] must start-paused! But is in killed state, must be reset()ed first in order to start-paused!");
589 reset();
590 if (notInState(ComponentState.RESETED)) throw new PogamutException(id(component) + "[" + getState().getFlag() + "] reset has failed, could not resolve the state change.", this);
591 startPaused();
592 break;
593 }
594 if (log != null && log.isLoggable(Level.FINER)) log.finer(id(component) + "[" + getState().getFlag() + "] calling componentControlHelper.localStartPaused(" + agentId + ")");
595 getComponentControl().localStartPaused(agentId);
596 }
597 }
598
599 protected void localPrePause(IAgentId agentId) {
600 synchronized(ctrlMutex) {
601 if (log != null && log.isLoggable(Level.FINER)) log.finer(id(component) + "[" + getState().getFlag() + "] processing localPrePause(" + agentId + ")");
602 if (log != null && log.isLoggable(Level.FINER)) log.finer(id(component) + "[" + getState().getFlag() + "] calling componentControlHelper.localPrePause(" + agentId + ")");
603 getComponentControl().localPrePause(agentId);
604 switch(getState().getFlag()) {
605 case INSTANTIATED:
606 case STOPPED:
607 case RESETED:
608 if (log != null && log.isLoggable(Level.FINER)) log.finer(id(component) + "[" + getState().getFlag() + "] must start-paused!");
609 startPaused();
610 break;
611 case RUNNING:
612
613
614 break;
615 case PAUSED:
616
617 break;
618 case STARTING:
619 case STARTING_PAUSED:
620 case PAUSING:
621 case RESUMING:
622 case STOPPING:
623 case KILLING:
624 case RESETTING:
625
626 throw new ComponentCantPauseException(id(component) + "[" + getState().getFlag() + "] STATE INVALID AT THIS POINT!", this);
627 case KILLED:
628 if (log != null && log.isLoggable(Level.FINER)) log.finer(id(component) + "[" + getState().getFlag() + "] must start-paused! But is in killed state, must be reset()ed first in order to start-paused!");
629 reset();
630 if (notInState(ComponentState.RESETED)) throw new PogamutException(id(component) + "[" + getState().getFlag() + "] reset has failed, could not resolve the state change.", this);
631 startPaused();
632 break;
633 }
634 }
635 }
636
637 protected void localPause(IAgentId agentId) {
638 synchronized(ctrlMutex) {
639 if (log != null && log.isLoggable(Level.FINER)) log.finer(id(component) + "[" + getState().getFlag() + "] processing localPreStart(" + agentId + ")");
640 if (log != null && log.isLoggable(Level.FINER)) log.finer(id(component) + "[" + getState().getFlag() + "] calling componentControlHelper.localPause(" + agentId + ")");
641 getComponentControl().localPause(agentId);
642 switch(getState().getFlag()) {
643 case INSTANTIATED:
644 case STOPPED:
645 case RESETED:
646 if (log != null && log.isLoggable(Level.FINER)) log.finer(id(component) + "[" + getState().getFlag() + "] must start-paused!");
647 startPaused();
648 break;
649 case RUNNING:
650 if (getStateCount(ComponentState.STARTING, ComponentState.RUNNING, ComponentState.RESUMING) == 0) {
651 if (log != null && log.isLoggable(Level.FINER)) log.finer(id(component) + "[" + getState().getFlag() + "] there are no more starting/running/resuming local component states, must pause!");
652
653 pause();
654 }
655 break;
656 case PAUSED:
657
658 break;
659 case STARTING:
660 case STARTING_PAUSED:
661 case PAUSING:
662 case RESUMING:
663 case STOPPING:
664 case KILLING:
665 case RESETTING:
666
667 throw new ComponentCantPauseException(id(component) + "[" + getState().getFlag() + "] STATE INVALID AT THIS POINT!", this);
668 case KILLED:
669 if (log != null && log.isLoggable(Level.FINER)) log.finer(id(component) + "[" + getState().getFlag() + "] must start-paused! But is in killed state, must be reset()ed first in order to start-paused!");
670 reset();
671 if (notInState(ComponentState.RESETED)) throw new PogamutException(id(component) + "[" + getState().getFlag() + "] reset has failed, could not resolve the state change.", this);
672 startPaused();
673 break;
674 }
675 }
676 }
677
678 protected void localPreResume(IAgentId agentId) {
679 synchronized(ctrlMutex) {
680 if (log != null && log.isLoggable(Level.FINER)) log.finer(id(component) + "[" + getState().getFlag() + "] processing localPreResume(" + agentId + ")");
681 switch(getState().getFlag()) {
682 case INSTANTIATED:
683 case STOPPED:
684 case RESETED:
685 if (log != null && log.isLoggable(Level.FINER)) log.finer(id(component) + "[" + getState().getFlag() + "] must start!");
686 start();
687 break;
688 case RUNNING:
689
690 break;
691 case PAUSED:
692 if (log != null && log.isLoggable(Level.FINER)) log.finer(id(component) + "[" + getState().getFlag() + "] must resume!");
693 resume();
694 break;
695 case STARTING:
696 case STARTING_PAUSED:
697 case PAUSING:
698 case RESUMING:
699 case STOPPING:
700 case KILLING:
701 case RESETTING:
702
703 throw new ComponentCantResumeException(id(component) + "[" + getState().getFlag() + "] STATE INVALID AT THIS POINT!", this);
704 case KILLED:
705 if (log != null && log.isLoggable(Level.FINER)) log.finer(id(component) + "[" + getState().getFlag() + "] must star! But is in killed state, must be reset()ed first in order to start!");
706 reset();
707 if (notInState(ComponentState.RESETED)) throw new PogamutException(id(component) + "[" + getState().getFlag() + "] reset has failed, could not resolve the state change.", this);
708 start();
709 break;
710 }
711 if (log != null && log.isLoggable(Level.FINER)) log.finer(id(component) + "[" + getState().getFlag() + "] calling componentControlHelper.localPreResume(" + agentId + ")");
712 getComponentControl().localPreResume(agentId);
713 }
714 }
715
716 protected void localResume(IAgentId agentId) {
717 synchronized(ctrlMutex) {
718 if (log != null && log.isLoggable(Level.FINER)) log.finer(id(component) + "[" + getState().getFlag() + "] processing localResume(" + agentId + ")");
719 switch(getState().getFlag()) {
720 case INSTANTIATED:
721 case STOPPED:
722 case RESETED:
723 if (log != null && log.isLoggable(Level.FINER)) log.finer(id(component) + "[" + getState().getFlag() + "] must start!");
724 start();
725 break;
726 case RUNNING:
727
728 break;
729 case PAUSED:
730 if (log != null && log.isLoggable(Level.FINER)) log.finer(id(component) + "[" + getState().getFlag() + "] must resume!");
731 resume();
732 break;
733 case STARTING:
734 case STARTING_PAUSED:
735 case PAUSING:
736 case RESUMING:
737 case STOPPING:
738 case KILLING:
739 case RESETTING:
740
741 throw new ComponentCantResumeException(id(component) + "[" + getState().getFlag() + "] STATE INVALID AT THIS POINT!", this);
742 case KILLED:
743 if (log != null && log.isLoggable(Level.FINER)) log.finer(id(component) + "[" + getState().getFlag() + "] must start! But is in killed state, must be reset()ed first in order to evaluate the state!");
744 reset();
745 if (notInState(ComponentState.RESETED)) throw new PogamutException(id(component) + "[" + getState().getFlag() + "] reset has failed, could not resolve the state change.", this);
746 start();
747 break;
748 }
749 if (log != null && log.isLoggable(Level.FINER)) log.finer(id(component) + "[" + getState().getFlag() + "] calling componentControlHelper.localResume(" + agentId + ")");
750 getComponentControl().localResume(agentId);
751 }
752 }
753
754 protected void localPreStop(IAgentId agentId) {
755 synchronized(ctrlMutex) {
756 if (log != null && log.isLoggable(Level.FINER)) log.finer(id(component) + "[" + getState().getFlag() + "] processing localPreStop(" + agentId + ")");
757 if (log != null && log.isLoggable(Level.FINER)) log.finer(id(component) + "[" + getState().getFlag() + "] calling componentControlHelper.localPreStop(" + agentId + ")");
758 getComponentControl().localPreStop(agentId);
759 switch(getState().getFlag()) {
760 case INSTANTIATED:
761 case STOPPED:
762 case RESETED:
763
764 break;
765 case RUNNING:
766 case PAUSED:
767 if (getStateCount(ComponentState.STARTING, ComponentState.STARTING_PAUSED, ComponentState.RUNNING, ComponentState.PAUSING, ComponentState.PAUSED, ComponentState.RESUMING, ComponentState.STOPPING) == 0) {
768 if (log != null && log.isLoggable(Level.FINER)) log.finer(id(component) + "[" + getState().getFlag() + "] there are no more running/paused/... local component states, must stop!");
769
770 stop();
771 }
772 break;
773 case STARTING:
774 case STARTING_PAUSED:
775 case PAUSING:
776 case RESUMING:
777 case STOPPING:
778 case KILLING:
779 case RESETTING:
780
781 throw new ComponentCantStartException(id(component) + "[" + getState().getFlag() + "] STATE INVALID AT THIS POINT!", this);
782 case KILLED:
783
784 break;
785 }
786 }
787 }
788
789 protected void localStop(IAgentId agentId) {
790 synchronized(ctrlMutex) {
791 if (log != null && log.isLoggable(Level.FINER)) log.finer(id(component) + "[" + getState().getFlag() + "] processing localStop(" + agentId + ")");
792 if (log != null && log.isLoggable(Level.FINER)) log.finer(id(component) + "[" + getState().getFlag() + "] calling componentControlHelper.localPreStop(" + agentId + ")");
793 getComponentControl().localStop(agentId);
794 switch(getState().getFlag()) {
795 case INSTANTIATED:
796 case STOPPED:
797 case RESETED:
798
799 break;
800 case RUNNING:
801 case PAUSED:
802 if (getStateCount(ComponentState.STARTING, ComponentState.STARTING_PAUSED, ComponentState.RUNNING, ComponentState.PAUSING, ComponentState.PAUSED, ComponentState.RESUMING, ComponentState.STOPPING) == 0) {
803 if (log != null && log.isLoggable(Level.FINER)) log.finer(id(component) + "[" + getState().getFlag() + "] there are no more running/paused/... local component states, must stop!");
804
805 stop();
806 }
807 break;
808 case STARTING:
809 case STARTING_PAUSED:
810 case PAUSING:
811 case RESUMING:
812 case STOPPING:
813 case KILLING:
814 case RESETTING:
815
816 throw new ComponentCantStartException(id(component) + "[" + getState().getFlag() + "] STATE INVALID AT THIS POINT!", this);
817 case KILLED:
818
819 break;
820 }
821 }
822 }
823
824 protected void localKill(IAgentId agentId) {
825 synchronized(ctrlMutex) {
826 if (log != null && log.isLoggable(Level.WARNING)) log.warning(id(component) + "[" + getState().getFlag() + "] processing localKill(" + agentId + ")");
827 if (log != null && log.isLoggable(Level.WARNING)) log.warning(id(component) + "[" + getState().getFlag() + "] calling componentControlHelper.localKill(" + agentId + ")");
828 getComponentControl().localKill(agentId);
829 switch(getState().getFlag()) {
830 case KILLING:
831 case KILLED:
832
833 break;
834 default:
835 if (log != null && log.isLoggable(Level.WARNING)) log.warning(id(component) + "[" + getState().getFlag() + "] fatal error has happened inside agent " + agentId + ", killing the component!");
836
837 kill(agentId, null, null);
838 break;
839 }
840 }
841 }
842
843 protected void localReset(IAgentId agentId) {
844 synchronized(ctrlMutex) {
845 if (log != null && log.isLoggable(Level.FINER)) log.finer(id(component) + "[" + getState().getFlag() + "] processing localReset(" + agentId + ")");
846 if (log != null && log.isLoggable(Level.FINER)) log.finer(id(component) + "[" + getState().getFlag() + "] calling componentControlHelper.localReset(" + agentId + ")");
847 if (inState(ComponentState.KILLED)) {
848 reset();
849 if (notInState(ComponentState.RESETED)) throw new PogamutException(id(component) + "[" + getState().getFlag() + "] reset has failed, could not resolve the state change.", this);
850 }
851 getComponentControl().localReset(agentId);
852 switch(getState().getFlag()) {
853 case RESETED:
854
855 break;
856 case KILLING:
857
858 throw new ComponentCantStartException(id(component) + "[" + getState().getFlag() + "] STATE INVALID AT THIS POINT!", this);
859 default:
860 case INSTANTIATED:
861 case STOPPED:
862 case RUNNING:
863 case PAUSED:
864 case STARTING:
865 case STARTING_PAUSED:
866 case PAUSING:
867 case RESUMING:
868 case STOPPING:
869 case RESETTING:
870
871 throw new ComponentCantStartException(id(component) + "[" + getState().getFlag() + "] component was not killed before, state is " + getState().getFlag() + ", INVALID!", this);
872 }
873 }
874 }
875
876
877
878
879
880
881
882
883
884
885 protected void stateChanged(IAgentId agentId, ComponentState changedValue) {
886 synchronized(ctrlMutex) {
887
888 setState(agentId, changedValue);
889 }
890 }
891
892
893
894
895
896
897
898 protected void setState(IAgentId agentId, ComponentState newState) {
899 synchronized(ctrlMutex) {
900
901 setState(agentId, componentStates.get(agentId), newState);
902 }
903 }
904
905
906
907
908
909
910
911
912 protected void setState(IAgentId agentId, ComponentState oldState, ComponentState newState) {
913 synchronized(ctrlMutex) {
914 if (log != null && log.isLoggable(Level.FINER)) log.finer(id(component) + "[" + getState().getFlag() + "] got local state change event: " + agentId + " " + oldState + " -> " + newState);
915 if (newState == null) {
916 oldState = componentStates.remove(agentId);
917 } else {
918 oldState = componentStates.put(agentId, newState);
919 }
920 if (oldState == newState) return;
921 if (oldState == null) {
922 increaseStateCount(newState);
923 } else {
924 decreaseStateCount(oldState);
925 if (newState != null) {
926 increaseStateCount(newState);
927 }
928 }
929
930 componentStateCountChanged(agentId, oldState, newState);
931 if (log != null && log.isLoggable(Level.FINER)) log.finer(id(component) + "[" + getState().getFlag() + "] /PROCESSED/ got local state change event: " + agentId + " " + oldState + " -> " + newState);
932 }
933 }
934
935
936
937
938
939
940
941
942 protected void componentStateCountChanged(IAgentId origin, ComponentState oldState, ComponentState newState) {
943 if (oldState == null) {
944
945 newAgentIsUsingTheComponent(origin, newState);
946 } else
947 if (newState == null) {
948
949 agentStoppedUsingTheComponent(origin, oldState);
950 } else {
951 componentStateChanged(origin, oldState, newState);
952 }
953 }
954
955 protected void newAgentIsUsingTheComponent(IAgentId agentId, ComponentState state) {
956 if (log != null && log.isLoggable(Level.FINE)) log.fine(id(component) + "[" + getState().getFlag() + "] has started to be used by " + agentId);
957
958 switch(getState().getFlag()) {
959 case INSTANTIATED:
960 case STOPPED:
961 case RESETED:
962 if (getStateCount(ComponentState.STARTING, ComponentState.RUNNING, ComponentState.RESUMING) > 0) {
963 if (log != null && log.isLoggable(Level.FINER)) log.finer(id(component) + "[" + getState().getFlag() + "] number of starting/running/resuming of local component states is greater than 0, must start!");
964
965 start();
966 } else
967 if (getStateCount(ComponentState.STARTING_PAUSED, ComponentState.PAUSING, ComponentState.PAUSED) > 0) {
968 if (log != null && log.isLoggable(Level.FINER)) log.finer(id(component) + "[" + getState().getFlag() + "] number of starting_paused/pausing/paused of local component states is greater than 0, must start paused!");
969
970 startPaused();
971 }
972 break;
973
974 case RUNNING:
975
976 break;
977
978 case PAUSED:
979 if (getStateCount(ComponentState.STARTING, ComponentState.RUNNING, ComponentState.RESUMING) > 0) {
980 if (log != null && log.isLoggable(Level.FINER)) log.finer(id(component) + "[" + getState().getFlag() + "] number of starting/resuming/running of local component states is greater than 0, must resume!");
981
982 resume();
983 }
984 break;
985
986 case STARTING:
987 case STARTING_PAUSED:
988 case RESUMING:
989 case PAUSING:
990 case STOPPING:
991 case RESETTING:
992
993 throw new ComponentCantStartException(id(component) + "[" + getState().getFlag() + "] STATE INVALID AT THIS POINT!", this);
994
995 case KILLING:
996
997 throw new ComponentCantStartException(id(component) + "[" + getState().getFlag() + "] STATE INVALID AT THIS POINT!", this);
998
999 case KILLED:
1000 if (log != null && log.isLoggable(Level.FINER)) log.finer(id(component) + "[" + getState().getFlag() + "] must star! But is in killed state, must be reset()ed first in order to start!");
1001 reset();
1002 if (notInState(ComponentState.RESETED)) throw new PogamutException(id(component) + "[" + getState().getFlag() + "] reset has failed, could not resolve the state change.", this);
1003 newAgentIsUsingTheComponent(agentId, state);
1004 break;
1005 }
1006 }
1007
1008 protected void agentStoppedUsingTheComponent(IAgentId agentId, ComponentState oldState) {
1009
1010 switch(getState().getFlag()) {
1011 case INSTANTIATED:
1012 case STOPPED:
1013 case RESETED:
1014
1015 break;
1016
1017 case RUNNING:
1018 if (getStateCount(ComponentState.STARTING, ComponentState.RUNNING, ComponentState.RESUMING) == 0) {
1019
1020 if (getStateCount(ComponentState.STARTING_PAUSED, ComponentState.PAUSED) > 0) {
1021 if (log != null && log.isLoggable(Level.FINER)) log.finer(id(component) + "[" + getState().getFlag() + "] there are only starting-paused/paused component, must pause!");
1022
1023 pause();
1024 } else
1025 if (getStateCount(ComponentState.PAUSING) == 0) {
1026
1027 if (getStateCount(ComponentState.STOPPING) == 0) {
1028 if (log != null && log.isLoggable(Level.FINER)) log.finer(id(component) + "[" + getState().getFlag() + "] there are no running/paused component, must stop!");
1029
1030 stop();
1031 }
1032 }
1033 }
1034 break;
1035
1036 case PAUSED:
1037 if (getStateCount(ComponentState.STARTING, ComponentState.RUNNING, ComponentState.RESUMING) == 0) {
1038
1039 if (getStateCount(ComponentState.STARTING_PAUSED, ComponentState.PAUSING, ComponentState.PAUSED) > 0) {
1040
1041 } else {
1042
1043 if (getStateCount(ComponentState.STOPPING) == 0) {
1044 if (log != null && log.isLoggable(Level.FINER)) log.finer(id(component) + "[" + getState().getFlag() + "] there are no running/paused component, must stop!");
1045
1046 stop();
1047 }
1048 }
1049 } else {
1050
1051 throw new ComponentCantStartException(id(component) + "[" + getState().getFlag() + "] STATE INVALID AT THIS POINT!", this);
1052 }
1053 break;
1054
1055 case STARTING:
1056 case STARTING_PAUSED:
1057 case RESUMING:
1058 case PAUSING:
1059 case STOPPING:
1060 case RESETTING:
1061
1062 throw new ComponentCantStartException(id(component) + "[" + getState().getFlag() + "] STATE INVALID AT THIS POINT!", this);
1063
1064 case KILLING:
1065
1066 throw new ComponentCantStartException(id(component) + "[" + getState().getFlag() + "] STATE INVALID AT THIS POINT!", this);
1067
1068 case KILLED:
1069
1070 break;
1071 }
1072 }
1073
1074 protected void componentStateChanged(IAgentId origin, ComponentState oldState, ComponentState newState) {
1075
1076 if (newState == ComponentState.KILLED) {
1077 if (inState(ComponentState.KILLED)) {
1078 if (log != null && log.isLoggable(Level.FINER)) log.finer(id(component) + "[" + getState().getFlag() + "] local component has been switched to killed, but we are killed too!");
1079 return;
1080 }
1081 if (inState(ComponentState.KILLING)) {
1082
1083 return;
1084 }
1085
1086 if (log != null && log.isLoggable(Level.FINER)) log.finer(id(component) + "[" + getState().getFlag() + "] local component has been switched to killed, must kill!");
1087 kill(origin, null, null);
1088 }
1089 if (getStateCount(ComponentState.KILLING) > 0) {
1090 if (log != null && log.isLoggable(Level.FINER)) log.finer(id(component) + "[" + getState().getFlag() + "] there is a local component in KILLING state, awaiting its KILLED to tear down the whole system!");
1091 return;
1092 }
1093
1094
1095 switch(getState().getFlag()) {
1096 case INSTANTIATED:
1097 case STOPPED:
1098 case RESETED:
1099 if (getStateCount(ComponentState.RUNNING) > 0) {
1100
1101 throw new PogamutException(id(component) + "[" + getState().getFlag() + "] the component should have been already running!", this);
1102 }
1103 if (getStateCount(ComponentState.PAUSED) > 0) {
1104
1105 throw new PogamutException(id(component) + "[" + getState().getFlag() + "] the component should have been already running/paused!", this);
1106 }
1107 if (getStateCount(ComponentState.STARTING, ComponentState.RESUMING) > 0) {
1108 if (log != null && log.isLoggable(Level.FINER)) log.finer(id(component) + "[" + getState().getFlag() + "] number of starting/resuming of local component states is greater than 0, must start!");
1109
1110 start();
1111 } else
1112 if (getStateCount(ComponentState.STARTING_PAUSED, ComponentState.PAUSING) > 0) {
1113 if (log != null && log.isLoggable(Level.FINER)) log.finer(id(component) + "[" + getState().getFlag() + "] number of starting-paused/pausing of local component states is greater than 0, must start!");
1114
1115 startPaused();
1116 }
1117 break;
1118
1119 case RUNNING:
1120 if (getStateCount(ComponentState.STARTING, ComponentState.RUNNING, ComponentState.RESUMING) == 0) {
1121 if (log != null && log.isLoggable(Level.FINER)) log.finer(id(component) + "[" + getState().getFlag() + "] number of starting/resuming/running of local component states is zero!");
1122
1123 if (getStateCount(ComponentState.STARTING_PAUSED, ComponentState.PAUSED) > 0) {
1124 if (log != null && log.isLoggable(Level.FINER)) log.finer(id(component) + "[" + getState().getFlag() + "] number of starting-paused/paused of local component states is greater than 0, there are still agents using the component!");
1125
1126 if (getStateCount(ComponentState.PAUSING) == 0) {
1127 if (log != null && log.isLoggable(Level.FINER)) log.finer(id(component) + "[" + getState().getFlag() + "] all local components in paused state, must pause!");
1128 pause();
1129 }
1130 } else
1131 if (getStateCount(ComponentState.PAUSING) == 0) {
1132 if (getStateCount(ComponentState.STOPPING) == 0) {
1133 if (log != null && log.isLoggable(Level.FINER)) log.finer(id(component) + "[" + getState().getFlag() + "] number of running/paused of local component states is 0, must stop!");
1134
1135 stop();
1136 }
1137 }
1138 }
1139 break;
1140
1141 case PAUSED:
1142 if (getStateCount(ComponentState.STARTING, ComponentState.RUNNING, ComponentState.RESUMING) == 0) {
1143
1144 if (getStateCount(ComponentState.STARTING_PAUSED, ComponentState.PAUSING, ComponentState.PAUSED) > 0) {
1145
1146 } else {
1147 if (getStateCount(ComponentState.STOPPING) == 0) {
1148 if (log != null && log.isLoggable(Level.FINER)) log.finer(id(component) + "[" + getState().getFlag() + "] number of running/paused of local component states is 0, must stop!");
1149
1150 stop();
1151 }
1152 }
1153 } else {
1154 if (log != null && log.isLoggable(Level.FINER)) log.finer(id(component) + "[" + getState().getFlag() + "] number of starting/resuming/running of local component states is > 0, must resume!");
1155 resume();
1156 }
1157 break;
1158
1159 case STARTING:
1160 case STARTING_PAUSED:
1161 case RESUMING:
1162 case PAUSING:
1163 case STOPPING:
1164 case RESETTING:
1165
1166 throw new ComponentCantStartException(id(component) + "[" + getState().getFlag() + "] STATE INVALID AT THIS POINT!", this);
1167
1168 case KILLING:
1169
1170 throw new ComponentCantStartException(id(component) + "[" + getState().getFlag() + "] STATE INVALID AT THIS POINT!", this);
1171
1172 case KILLED:
1173 reset();
1174 if (notInState(ComponentState.RESETED)) throw new PogamutException(id(component) + "[" + getState().getFlag() + "] reset has failed, could not resolve the state change.", this);
1175 componentStateChanged(origin, oldState, newState);
1176 break;
1177 }
1178 }
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188 protected void start() {
1189 setState(ComponentState.STARTING);
1190 if (log != null && log.isLoggable(Level.FINER)) log.finer(id(component) + "[" + getState().getFlag() + "] calling preStart()");
1191 getComponentControl().preStart();
1192 if (log != null && log.isLoggable(Level.FINER)) log.finer(id(component) + "[" + getState().getFlag() + "] calling start()");
1193 getComponentControl().start();
1194 setState(ComponentState.RUNNING);
1195 }
1196
1197 protected void startPaused() {
1198 setState(ComponentState.STARTING_PAUSED);
1199 if (log != null && log.isLoggable(Level.FINER)) log.finer(id(component) + "[" + getState().getFlag() + "] calling preStartPaused()");
1200 getComponentControl().preStartPaused();
1201 if (log != null && log.isLoggable(Level.FINER)) log.finer(id(component) + "[" + getState().getFlag() + "] calling startPaused()");
1202 getComponentControl().startPaused();
1203 setState(ComponentState.PAUSED);
1204 }
1205
1206 protected void pause() {
1207 setState(ComponentState.PAUSING);
1208 if (log != null && log.isLoggable(Level.FINER)) log.finer(id(component) + "[" + getState().getFlag() + "] calling prePause()");
1209 getComponentControl().prePause();
1210 if (log != null && log.isLoggable(Level.FINER)) log.finer(id(component) + "[" + getState().getFlag() + "] calling pause()");
1211 getComponentControl().pause();
1212 setState(ComponentState.PAUSED);
1213 }
1214
1215 protected void resume() {
1216 setState(ComponentState.RESUMING);
1217 if (log != null && log.isLoggable(Level.FINER)) log.finer(id(component) + "[" + getState().getFlag() + "] calling preResume()");
1218 getComponentControl().preResume();
1219 if (log != null && log.isLoggable(Level.FINER)) log.finer(id(component) + "[" + getState().getFlag() + "] calling resume()");
1220 getComponentControl().resume();
1221 setState(ComponentState.RUNNING);
1222 }
1223
1224 protected void stop() {
1225 setState(ComponentState.STOPPING);
1226 if (log != null && log.isLoggable(Level.FINER)) log.finer(id(component) + "[" + getState().getFlag() + "] calling preStop()");
1227 getComponentControl().preStop();
1228 if (log != null && log.isLoggable(Level.FINER)) log.finer(id(component) + "[" + getState().getFlag() + "] calling stop()");
1229 getComponentControl().stop();
1230 setState(ComponentState.STOPPED);
1231 }
1232
1233 boolean killing = false;
1234
1235
1236
1237
1238
1239 protected void kill(IAgentId agentId, String message, Throwable cause) {
1240 if (killing) return;
1241 killing = true;
1242 try {
1243 try {
1244 setState(ComponentState.KILLING);
1245 } catch (Exception e) {
1246 if (log.isLoggable(Level.SEVERE)) log.severe(ExceptionToString.process(id(component) + "[" + getState().getFlag() + "] could not set component state to KILLING.", e));
1247 }
1248
1249 String msg = null;
1250 try {
1251 msg =
1252 id(component) + "[" + getState().getFlag() + "] " +
1253 (agentId == null ?
1254 "General component failure."
1255 : "Agent " + agentId + " has failed, tearing down the whole team.")
1256 +
1257 (message != null ? "Reason: " + message : "");
1258 for (LocalController ctrl : localControllers.values()) {
1259 if (ctrl.getAgentId().equals(agentId)) continue;
1260 try {
1261 ctrl.controller.fatalError(msg, cause);
1262 } catch (PogamutException pe) {
1263 pe.logExceptionOnce(log);
1264 } catch (Exception e) {
1265 if (log.isLoggable(Level.SEVERE)) log.severe(ExceptionToString.process(e));
1266 }
1267 }
1268 } catch (Exception e) {
1269 if (log.isLoggable(Level.SEVERE)) log.severe(ExceptionToString.process(id(component) + "[" + getState().getFlag() + "] failed to broadcast fatal error to all other buses.", e));
1270 }
1271
1272 try {
1273 if (log != null && log.isLoggable(Level.FINER)) log.finer(id(component) + "[" + getState().getFlag() + "] calling kill()");
1274 } catch (Exception e) {
1275 }
1276
1277 try {
1278 getComponentControl().kill();
1279 } catch (Exception e) {
1280 if (log.isLoggable(Level.SEVERE)) log.severe(ExceptionToString.process(id(component) + "[" + getState().getFlag() + "] could not kill the component.", e));
1281 }
1282
1283
1284 if (agentId == null) {
1285 fatalError = new FatalErrorEvent(this, msg, cause);
1286 } else {
1287 fatalError = localControllers.get(agentId).controller.getFatalError();
1288 }
1289 } finally {
1290 try {
1291 setState(ComponentState.KILLED);
1292 } catch (Exception e) {
1293 if (log.isLoggable(Level.SEVERE)) log.severe(ExceptionToString.process(id(component) + "[" + getState().getFlag() + "] could not set component state to KILLED.", e));
1294 } finally {
1295 killing = false;
1296 }
1297 }
1298
1299 }
1300
1301 protected void reset() {
1302 setState(ComponentState.RESETTING);
1303 getComponentControl().reset();
1304 setState(ComponentState.RESETED);
1305 }
1306
1307 }