1 package cz.cuni.amis.pogamut.base.agent.impl;
2
3 import java.util.HashMap;
4 import java.util.HashSet;
5 import java.util.Map;
6 import java.util.Set;
7 import java.util.concurrent.TimeUnit;
8 import java.util.logging.Level;
9
10 import cz.cuni.amis.introspection.Folder;
11 import cz.cuni.amis.introspection.java.ReflectionObjectFolder;
12 import cz.cuni.amis.pogamut.base.agent.IAgent;
13 import cz.cuni.amis.pogamut.base.agent.IAgentId;
14 import cz.cuni.amis.pogamut.base.agent.component.event.AgentEvents;
15 import cz.cuni.amis.pogamut.base.agent.exceptions.AgentException;
16 import cz.cuni.amis.pogamut.base.agent.jmx.AgentJMXComponents;
17 import cz.cuni.amis.pogamut.base.agent.jmx.IJMXEnabled;
18 import cz.cuni.amis.pogamut.base.agent.state.WaitForAgentStateChange;
19 import cz.cuni.amis.pogamut.base.agent.state.impl.AgentState;
20 import cz.cuni.amis.pogamut.base.agent.state.impl.AgentStateFailed;
21 import cz.cuni.amis.pogamut.base.agent.state.impl.AgentStateFailing;
22 import cz.cuni.amis.pogamut.base.agent.state.impl.AgentStateInstantiated;
23 import cz.cuni.amis.pogamut.base.agent.state.impl.AgentStatePaused;
24 import cz.cuni.amis.pogamut.base.agent.state.impl.AgentStatePausing;
25 import cz.cuni.amis.pogamut.base.agent.state.impl.AgentStateResumed;
26 import cz.cuni.amis.pogamut.base.agent.state.impl.AgentStateResuming;
27 import cz.cuni.amis.pogamut.base.agent.state.impl.AgentStateStarted;
28 import cz.cuni.amis.pogamut.base.agent.state.impl.AgentStateStartedPaused;
29 import cz.cuni.amis.pogamut.base.agent.state.impl.AgentStateStarting;
30 import cz.cuni.amis.pogamut.base.agent.state.impl.AgentStateStartingPaused;
31 import cz.cuni.amis.pogamut.base.agent.state.impl.AgentStateStopped;
32 import cz.cuni.amis.pogamut.base.agent.state.impl.AgentStateStopping;
33 import cz.cuni.amis.pogamut.base.agent.state.level0.IAgentState;
34 import cz.cuni.amis.pogamut.base.agent.state.level1.IAgentStateDown;
35 import cz.cuni.amis.pogamut.base.agent.state.level1.IAgentStateGoingDown;
36 import cz.cuni.amis.pogamut.base.agent.state.level1.IAgentStateGoingUp;
37 import cz.cuni.amis.pogamut.base.agent.state.level1.IAgentStateUp;
38 import cz.cuni.amis.pogamut.base.agent.state.level2.IAgentStateFailed;
39 import cz.cuni.amis.pogamut.base.agent.state.level2.IAgentStateFailing;
40 import cz.cuni.amis.pogamut.base.agent.state.level2.IAgentStateInstantiated;
41 import cz.cuni.amis.pogamut.base.agent.state.level2.IAgentStatePaused;
42 import cz.cuni.amis.pogamut.base.agent.state.level2.IAgentStatePausing;
43 import cz.cuni.amis.pogamut.base.agent.state.level2.IAgentStateResuming;
44 import cz.cuni.amis.pogamut.base.agent.state.level2.IAgentStateRunning;
45 import cz.cuni.amis.pogamut.base.agent.state.level2.IAgentStateStarting;
46 import cz.cuni.amis.pogamut.base.agent.state.level2.IAgentStateStartingPaused;
47 import cz.cuni.amis.pogamut.base.agent.state.level2.IAgentStateStopped;
48 import cz.cuni.amis.pogamut.base.agent.state.level2.IAgentStateStopping;
49 import cz.cuni.amis.pogamut.base.agent.state.level3.IAgentStateStarted;
50 import cz.cuni.amis.pogamut.base.component.IComponent;
51 import cz.cuni.amis.pogamut.base.component.bus.IComponentBus;
52 import cz.cuni.amis.pogamut.base.component.bus.IComponentEventListener;
53 import cz.cuni.amis.pogamut.base.component.bus.event.IFatalErrorEvent;
54 import cz.cuni.amis.pogamut.base.component.bus.event.IPausedEvent;
55 import cz.cuni.amis.pogamut.base.component.bus.event.IPausingEvent;
56 import cz.cuni.amis.pogamut.base.component.bus.event.IResetEvent;
57 import cz.cuni.amis.pogamut.base.component.bus.event.IResumedEvent;
58 import cz.cuni.amis.pogamut.base.component.bus.event.IResumingEvent;
59 import cz.cuni.amis.pogamut.base.component.bus.event.IStartedEvent;
60 import cz.cuni.amis.pogamut.base.component.bus.event.IStartingEvent;
61 import cz.cuni.amis.pogamut.base.component.bus.event.IStartingPausedEvent;
62 import cz.cuni.amis.pogamut.base.component.bus.event.IStoppedEvent;
63 import cz.cuni.amis.pogamut.base.component.bus.event.IStoppingEvent;
64 import cz.cuni.amis.pogamut.base.component.bus.event.impl.FatalErrorEvent;
65 import cz.cuni.amis.pogamut.base.component.controller.ComponentController;
66 import cz.cuni.amis.pogamut.base.component.exception.ComponentCantPauseException;
67 import cz.cuni.amis.pogamut.base.component.exception.ComponentCantResumeException;
68 import cz.cuni.amis.pogamut.base.component.exception.ComponentCantStartException;
69 import cz.cuni.amis.pogamut.base.component.exception.ComponentCantStopException;
70 import cz.cuni.amis.pogamut.base.component.lifecyclebus.ILifecycleBus;
71 import cz.cuni.amis.pogamut.base.utils.jmx.FolderToIJMXEnabledAdapter;
72 import cz.cuni.amis.pogamut.base.utils.logging.IAgentLogger;
73 import cz.cuni.amis.pogamut.base.utils.logging.LogCategory;
74 import cz.cuni.amis.utils.ExceptionToString;
75 import cz.cuni.amis.utils.NullCheck;
76 import cz.cuni.amis.utils.collections.HashSetClass;
77 import cz.cuni.amis.utils.exception.PogamutException;
78 import cz.cuni.amis.utils.exception.PogamutInterruptedException;
79 import cz.cuni.amis.utils.flag.Flag;
80 import cz.cuni.amis.utils.flag.ImmutableFlag;
81 import cz.cuni.amis.utils.flag.WaitForFlagChange;
82 import cz.cuni.amis.utils.token.IToken;
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127 public abstract class AbstractAgent implements IAgent {
128
129
130
131
132 public static final String INTROSPECTION_ROOT_NAME = "root";
133
134
135
136
137 public static final String LOG_CATEGORY_NAME = "Agent";
138
139
140
141
142
143 private IAgentLogger logger = null;
144
145
146
147
148 protected LogCategory log = null;
149
150
151
152
153 private Flag<IAgentState> agentState = new Flag<IAgentState>(new AgentStateInstantiated("Just created."));
154
155
156
157
158
159
160
161
162
163
164
165
166
167 private AgentJMXComponents jmx = null;
168
169 private Object jmxMutex = new Object();
170
171
172
173
174 private IComponentBus eventBus;
175
176
177
178
179 private Folder folder = null;
180
181
182
183
184 protected AgentEvents events;
185
186
187
188
189 private IAgentId agentId;
190
191
192
193
194 private Map<IToken, IComponent> runningComponents = new HashMap<IToken, IComponent>();
195
196
197
198
199 private HashSetClass stopDependencyClass = new HashSetClass();
200
201
202
203
204 private Set<IToken> stopDependencyToken = new HashSet<IToken>();
205
206 private IComponentEventListener<IStartedEvent> startedEventListener = new IComponentEventListener<IStartedEvent>() {
207
208 @Override
209 public void notify(IStartedEvent event) {
210 if (event.getSource() == null) return;
211 if (event.getSource() == AbstractAgent.this) return;
212 synchronized(runningComponents) {
213 IComponent component = runningComponents.get(event.getSource().getComponentId());
214 if (component == null) {
215
216 if (log.isLoggable(Level.FINE)) log.fine("Component " + event.getSource() + " started.");
217 componentStarted(event);
218 } else {
219 if (component == event.getSource()) {
220 if (log.isLoggable(Level.WARNING)) log.warning("Component " + event.getSource() + " has started more than once.");
221 } else {
222 throw new AgentException("Component id clash, two instances of components have the same component id = " + event.getSource().getComponentId(), this);
223 }
224 }
225 }
226 }
227
228 };
229
230 private IComponentEventListener<IPausedEvent> pausedEventListener = new IComponentEventListener<IPausedEvent>() {
231
232 @Override
233 public void notify(IPausedEvent event) {
234 if (event.getSource() == null) return;
235 if (event.getSource() == AbstractAgent.this) return;
236 synchronized(runningComponents) {
237 IComponent component = runningComponents.get(event.getSource().getComponentId());
238 if (component == null) {
239
240 if (log.isLoggable(Level.FINE)) log.fine("Component " + event.getSource() + " started.");
241 componentStarted(event);
242 } else {
243 if (component != event.getSource()) {
244 throw new AgentException("Component id clash, two instances of components have the same component id = " + event.getSource().getComponentId(), this);
245 }
246 }
247 }
248 }
249
250 };
251
252 private IComponentEventListener<IStoppingEvent> stoppingEventListener = new IComponentEventListener<IStoppingEvent>() {
253
254 @Override
255 public void notify(IStoppingEvent event) {
256 componentStopping(event);
257 }
258
259 };
260
261 private IComponentEventListener<IStoppedEvent> stoppedEventListener = new IComponentEventListener<IStoppedEvent>() {
262
263 @Override
264 public void notify(IStoppedEvent event) {
265 synchronized(runningComponents) {
266 IComponent component = runningComponents.get(event.getSource().getComponentId());
267 if (component == null) {
268 if (log.isLoggable(Level.WARNING)) log.warning("Component " + event.getSource() + " stopped, but it has never reported that it started.");
269 } else {
270 if (component == event.getSource()) {
271
272 if (log.isLoggable(Level.WARNING)) log.warning("Component " + event.getSource() + " has stopped.");
273 componentStopped(event);
274 } else {
275 throw new AgentException("Component id clash, two instances of components have the same component id = " + event.getSource().getComponentId(), this);
276 }
277 }
278 }
279 }
280
281 };
282
283 private IComponentEventListener<IFatalErrorEvent> fatalErrorEventListener = new IComponentEventListener<IFatalErrorEvent>() {
284
285 @Override
286 public void notify(IFatalErrorEvent event) {
287 if (log.isLoggable(Level.SEVERE)) log.severe("Fatal error sensed: " + event);
288 componentFatalError(event);
289 }
290
291 };
292
293 private IComponentEventListener<IResetEvent> resetEventListener = new IComponentEventListener<IResetEvent>() {
294
295 @Override
296 public void notify(IResetEvent event) {
297 resetEvent(event);
298 }
299
300 };
301
302
303
304
305
306
307
308
309 public AbstractAgent(IAgentId agentId, IComponentBus eventBus, IAgentLogger logger) {
310 this.logger = logger;
311 NullCheck.check(this.logger, "logger");
312 this.agentId = agentId;
313 NullCheck.check(this.agentId, "agentId");
314 this.eventBus = eventBus;
315 NullCheck.check(this.eventBus, "eventBus");
316 this.log = this.logger.getCategory(LOG_CATEGORY_NAME);
317 NullCheck.check(this.log, "logger.getCategory()");
318
319 if (log.isLoggable(Level.INFO)) log.info("Initializing " + getClass().getSimpleName() + ", id: " + this.agentId.getToken());
320
321 this.events = new AgentEvents(this.eventBus, this, log);
322
323 this.eventBus.addEventListener(IStartedEvent.class, startedEventListener);
324 this.eventBus.addEventListener(IPausedEvent.class, pausedEventListener);
325 this.eventBus.addEventListener(IStoppingEvent.class, stoppingEventListener);
326 this.eventBus.addEventListener(IStoppedEvent.class, stoppedEventListener);
327 this.eventBus.addEventListener(IFatalErrorEvent.class, fatalErrorEventListener);
328 this.eventBus.addEventListener(IResetEvent.class, resetEventListener);
329 }
330
331 @Override
332 public boolean equals(Object other) {
333 if (other == null) return false;
334 if (!(other instanceof AbstractAgent)) return false;
335 AbstractAgent otherAgent = (AbstractAgent) other;
336 return this.agentId.equals(otherAgent.getComponentId());
337 }
338
339 @Override
340 public int hashCode() {
341 return this.agentId.hashCode();
342 }
343
344
345
346
347
348
349
350 @Override
351 public IAgentLogger getLogger() {
352 return this.logger;
353 }
354
355 @Override
356 public ImmutableFlag<IAgentState> getState() {
357 return agentState.getImmutable();
358 }
359
360
361
362
363
364
365 public boolean inState(Class<?>... states) {
366 Class<?> agentState = getState().getFlag().getClass();
367 for (Class<?> state : states) {
368 if (state.isAssignableFrom(agentState)) return true;
369 }
370 return false;
371 }
372
373
374
375
376
377
378 public boolean notInState(Class<?>... states) {
379 Class<?> agentState = getState().getFlag().getClass();
380 for (Class<?> state : states) {
381 if (state.isAssignableFrom(agentState)) return false;
382 }
383 return true;
384 }
385
386 @Override
387 public IComponentBus getEventBus() {
388 return eventBus;
389 }
390
391 @Override
392 public String getName() {
393 return agentId.getName().getFlag();
394 }
395
396 @Override
397 public IAgentId getComponentId() {
398 return agentId;
399 }
400
401
402
403
404 public LogCategory getLog() {
405 return log;
406 }
407
408 private void startFailedTest() {
409 if (inState(IAgentStateFailed.class)) {
410 throw new ComponentCantStartException("Agent has been killed during initialization.", log, this);
411 }
412 }
413
414 private boolean startMethodCalled = false;
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431 @Override
432 public final synchronized void start() throws ComponentCantStartException {
433 if (startMethodCalled) return;
434
435 if (inState(IAgentStateGoingUp.class, IAgentStateUp.class)) return;
436 if (notInState(IAgentStateDown.class)) {
437 throw new ComponentCantStartException("Agent can't start, it is in wrong state (" + getState().getFlag() + ") stop() or kill() agent before start()ing.", log, this);
438 }
439
440 startMethodCalled = true;
441 try {
442 if (log.isLoggable(Level.WARNING)) log.warning("Starting agent " + getComponentId().getToken());
443 if (jmx != null) {
444
445 getJMX().registerJMX();
446 }
447 if (!eventBus.isRunning()) {
448 if (log.isLoggable(Level.WARNING)) log.warning("Event bus is not running, resetting.");
449 eventBus.reset();
450 if (!eventBus.isRunning()) {
451 throw new ComponentCantStartException("Event bus reset()ed but it's still not running.", log, this);
452 }
453 }
454 setState(new AgentStateStarting("Sending 'starting' event."));
455 startFailedTest();
456 events.startingTransactional();
457 startFailedTest();
458 setState(new AgentStateStarting("Calling startAgent()."));
459 startFailedTest();
460 startAgent();
461 startFailedTest();
462 setState(new AgentStateStarting("Sending 'started' event."));
463 startFailedTest();
464 events.startedTransactional();
465 startFailedTest();
466 setState(new AgentStateStarted("Agent has started."));
467 startFailedTest();
468 if (log.isLoggable(Level.INFO)) log.info(runningComponents.size() + " component" + (runningComponents.size() > 1 ? "s" : "") + " has started along with the agent.");
469 } catch (Exception e) {
470 if (!inState(IAgentStateFailed.class) && !events.fatalError("Can't start the agent", e)) {
471 componentFatalError(new FatalErrorEvent(this, "agent's fatal error not propagated"));
472 }
473 if (e instanceof ComponentCantStartException) throw (ComponentCantStartException)e;
474 throw new ComponentCantStartException("Can't start: " + e.getMessage(), e, log, this);
475 } finally {
476 startMethodCalled = false;
477 }
478 }
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495 @Override
496 public final synchronized void startPaused() throws ComponentCantStartException {
497 if (startMethodCalled) return;
498
499 if (inState(IAgentStateGoingUp.class, IAgentStateUp.class)) return;
500 if (notInState(IAgentStateDown.class)) {
501 throw new ComponentCantStartException("Agent can't start, it is in wrong state (" + getState().getFlag() + ") stop() or kill() agent before start()ing.", log, this);
502 }
503
504 startMethodCalled = true;
505 try {
506 if (log.isLoggable(Level.WARNING)) log.warning("Starting-paused agent " + getComponentId().getToken());
507 if (jmx != null) {
508
509 getJMX().registerJMX();
510 }
511 if (!eventBus.isRunning()) {
512 if (log.isLoggable(Level.WARNING)) log.warning("Event bus is not running, resetting.");
513 eventBus.reset();
514 if (!eventBus.isRunning()) {
515 throw new ComponentCantStartException("Event bus reset()ed but it's still not running.", log, this);
516 }
517 }
518 setState(new AgentStateStartingPaused("Sending 'starting-paused' event."));
519 startFailedTest();
520 events.startingPausedTransactional();
521 startFailedTest();
522 setState(new AgentStateStartingPaused("Calling startPausedAgent()."));
523 startFailedTest();
524 startPausedAgent();
525 startFailedTest();
526 setState(new AgentStateStartingPaused("Sending 'paused' event."));
527 startFailedTest();
528 events.pausedTransactional();
529 startFailedTest();
530 setState(new AgentStateStartedPaused("Agent has started into paused state."));
531 startFailedTest();
532 if (log.isLoggable(Level.INFO)) log.info(runningComponents.size() + " component" + (runningComponents.size() > 1 ? "s" : "") + " has started along with the agent.");
533 } catch (Exception e) {
534 if (!inState(IAgentStateFailed.class) && !events.fatalError("Can't start-paused the agent", e)) {
535 componentFatalError(new FatalErrorEvent(this, "agent's fatal error not propagated"));
536 }
537 if (e instanceof ComponentCantStartException) throw (ComponentCantStartException)e;
538 throw new ComponentCantStartException("Can't start-paused: " + e.getMessage(), e, log, this);
539 } finally {
540 startMethodCalled = false;
541 }
542 }
543
544
545
546
547
548 protected void preStopAgent() {
549 }
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570 @Override
571 public final synchronized void stop() throws ComponentCantStopException {
572 if (stopMethodCalled) return;
573
574 if (inState(IAgentStateGoingDown.class, IAgentStateDown.class, IAgentStateInstantiated.class)) return;
575 if (inState(IAgentStateGoingUp.class)) {
576 throw new ComponentCantStopException("stop() requested during initialization, kill() the agent.", log, this);
577 }
578 if (notInState(IAgentStateUp.class)) {
579 throw new ComponentCantStopException("Agent can't stop, it is in wrong state (" + getState().getFlag() + "), call start() first.", log, this);
580 }
581
582 stopMethodCalled = true;
583 try {
584 if (log.isLoggable(Level.WARNING)) log.warning("Stopping agent " + getComponentId().getToken());
585 setState(new AgentStateStopping("stop() requested, calling preStopAgent()"));
586 preStopAgent();
587 setState(new AgentStateStopping("stop() requested, sending 'stopping' event"));
588 events.stoppingTransactional();
589 setState(new AgentStateStopping("Calling stopAgent()."));
590 stopAgent();
591 if (runningComponents.size() > 1) {
592 StringBuffer sb = new StringBuffer();
593 boolean first = true;
594 for (IComponent component : runningComponents.values()) {
595 if (component == this) continue;
596 if (first) first = false;
597 else sb.append(", ");
598 sb.append(component.getComponentId().getToken());
599 sb.append(":");
600 sb.append(component);
601 }
602 ComponentCantStopException e = new ComponentCantStopException("Not all components has stopped along with the agent - components that did not send stopped event (id:toString): " + sb.toString(), log, this);
603 if (!events.fatalError(e)) {
604 componentFatalError(new FatalErrorEvent(this, "agent's fatal error not propagated"));
605 }
606 throw e;
607 }
608 setState(new AgentStateStopping("Sending 'stopped' event."));
609 events.stoppedTransactional();
610 setState(new AgentStateStopped("Agent stopped."));
611 if (jmx != null) {
612 getJMX().unregisterJMX();
613 }
614 getLogger().removeDefaultNetworkHandler();
615 } catch (Exception e) {
616 if (!events.fatalError("Can't stop the agent.", e)) {
617 componentFatalError(new FatalErrorEvent(this, "agent's fatal error not propagated"));
618 }
619 if (e instanceof ComponentCantStopException) throw ((ComponentCantStopException)e);
620 throw new ComponentCantStopException("Can't stop.", e, log, this);
621 } finally {
622 stopMethodCalled = false;
623 System.gc();
624 }
625 }
626
627 private boolean stopMethodCalled = false;
628
629
630
631
632
633 protected void preKillAgent() {
634 }
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650 @Override
651 public final synchronized void kill() {
652 if (killMethodCalled) return;
653 killMethodCalled = true;
654 try {
655 if (inState(IAgentStateFailing.class, IAgentStateFailed.class)) return;
656 try {
657 if (log.isLoggable(Level.SEVERE)) log.severe("Killing agent " + getComponentId().getToken());
658 } finally {
659 try {
660 preKillAgent();
661 } finally {
662 try {
663 setState(new AgentStateFailing("kill() requested, sending fatal error event."));
664 } finally {
665 try {
666 events.fatalError("agent kill() requested");
667 } finally {
668 try {
669 setState(new AgentStateFailing("Calling killAgent()."));
670 } finally {
671 try {
672 innerKillAgent();
673 } finally {
674
675 try {
676 setState(new AgentStateFailed("Agent killed."));
677 } finally {
678 if (jmx != null) {
679 getJMX().unregisterJMX();
680 }
681 }
682 }
683 }
684 }
685 }
686 }
687 }
688 } catch (Exception e) {
689 if (e instanceof PogamutException) {
690 ((PogamutException) e).logExceptionOnce(log);
691 } else {
692 if (log.isLoggable(Level.SEVERE)) log.severe(ExceptionToString.process(e));
693 }
694 } finally {
695 killMethodCalled = false;
696 System.gc();
697 }
698 }
699
700 private boolean killMethodCalled = false;
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715 @Override
716 public final synchronized void pause() throws ComponentCantPauseException {
717 if (pauseMethodCalled) return;
718
719 if (inState(IAgentStatePaused.class)) return;
720 if (notInState(IAgentStateRunning.class)) {
721 throw new ComponentCantPauseException("Agent can't pause, it is not in the running state but " + getState().getFlag() + ".", log, this);
722 }
723
724 pauseMethodCalled = true;
725 try {
726 setState(new AgentStatePausing("Sending 'pausing' event."));
727 events.pausingTransactional();
728 setState(new AgentStatePausing("Calling pauseAgent()."));
729 pauseAgent();
730 setState(new AgentStatePausing("Sending 'paused' event."));
731 events.pausedTransactional();
732 setState(new AgentStatePaused("Agent paused."));
733 } catch (Exception e) {
734 if (!events.fatalError("Can't pause the agent", e)) {
735 componentFatalError(new FatalErrorEvent(this, "agent's fatal error not propagated"));
736 }
737 if (e instanceof ComponentCantPauseException) throw ((ComponentCantPauseException)e);
738 throw new ComponentCantPauseException("Can't pause.", e, log, this);
739 } finally {
740 pauseMethodCalled = false;
741 }
742 }
743
744 private boolean pauseMethodCalled = false;
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759 @Override
760 public final synchronized void resume() throws ComponentCantResumeException {
761 if (resumeMethodCalled) return;
762
763 if (inState(IAgentStateRunning.class)) return;
764 if (notInState(IAgentStatePaused.class)) {
765 throw new ComponentCantResumeException("Agent can't resume, it is not in the paused state but " + getState().getFlag() + ".", log, this);
766 }
767
768 resumeMethodCalled = true;
769 try {
770 setState(new AgentStateResuming("resume() requested, sending 'resuming' event."));
771 events.resumingTransactional();
772 setState(new AgentStateResuming("Calling resumeAgent()."));
773 resumeAgent();
774 setState(new AgentStateResuming("Sending 'resumed' event."));
775 events.resumedTransactional();
776 setState(new AgentStateResumed("Agent resumed."));
777 } catch (Exception e) {
778 if (!events.fatalError("Can't resume the agent.", e)) {
779 componentFatalError(new FatalErrorEvent(this, "agent's fatal error not propagated"));
780 }
781 if (e instanceof ComponentCantResumeException) throw ((ComponentCantResumeException)e);
782 throw new ComponentCantResumeException("Can't resume.", e, log, this);
783 } finally {
784 resumeMethodCalled = false;
785 }
786 }
787
788 private boolean resumeMethodCalled = false;
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803 public final AgentJMXComponents getJMX() {
804 if (jmx == null) {
805 synchronized(jmxMutex) {
806 if (jmx == null) {
807 jmx = createAgentJMX();
808 addJMXComponents();
809 }
810 }
811 }
812 return jmx;
813 }
814
815
816
817
818
819
820
821
822
823
824
825
826 public IAgentState awaitState(final Class awaitAgentState) throws AgentException {
827 IAgentState state = getState().getFlag();
828 if (awaitAgentState.isAssignableFrom(state.getClass())) return state;
829 state = new WaitForFlagChange<IAgentState>(agentState, new WaitForFlagChange.IAccept<IAgentState>() {
830
831 @Override
832 public boolean accept(IAgentState flagValue) {
833 return awaitAgentState.isAssignableFrom(flagValue.getClass()) || flagValue instanceof IAgentStateDown;
834 }
835
836 }).await();
837 if (awaitAgentState.isAssignableFrom(state.getClass())) return state;
838 if (state instanceof IAgentStateDown) return null;
839 throw new PogamutException("Agent is in unexpected state, not IAgentStateUp nor IAgentStateDown but " + state + ".", log, this);
840 }
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856 public IAgentState awaitState(final Class awaitAgentState, long timeoutMillis) throws AgentException {
857 IAgentState state = getState().getFlag();
858 if (awaitAgentState.isAssignableFrom(state.getClass())) return state;
859 state = new WaitForFlagChange<IAgentState>(agentState, new WaitForFlagChange.IAccept<IAgentState>() {
860
861 @Override
862 public boolean accept(IAgentState flagValue) {
863 return awaitAgentState.isAssignableFrom(flagValue.getClass()) || flagValue instanceof IAgentStateDown;
864 }
865
866 }).await(timeoutMillis, TimeUnit.MILLISECONDS);
867 if (state == null) {
868 return null;
869 }
870 if (awaitAgentState.isAssignableFrom(state.getClass())) return state;
871 if (state instanceof IAgentStateDown) return null;
872 throw new PogamutException("Agent is in unexpected state, not IAgentStateUp nor IAgentStateDown but " + state + ".", log, this);
873 }
874
875 @Override
876 final public Folder getIntrospection() {
877 if(folder == null) {
878 folder = createIntrospection();
879 }
880 return folder;
881 }
882
883
884
885
886
887 protected Folder createIntrospection() {
888 return new ReflectionObjectFolder(INTROSPECTION_ROOT_NAME, this);
889 }
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905 protected void startAgent() {
906 }
907
908
909
910
911
912
913
914
915
916 protected void startPausedAgent() {
917 }
918
919
920
921
922
923
924
925
926
927 protected void stopAgent() {
928 }
929
930
931
932
933
934
935
936
937
938 protected void killAgent() {
939 }
940
941
942
943
944 private void innerKillAgent() {
945 try {
946 runningComponents.clear();
947 } finally {
948 killAgent();
949 }
950 }
951
952
953
954
955
956
957
958
959
960 protected void pauseAgent() {
961 }
962
963
964
965
966
967
968
969
970
971 protected void resumeAgent() {
972 }
973
974
975
976
977
978
979
980
981
982
983 protected void resetAgent() {
984
985 }
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001 protected synchronized void componentStarted(IStartedEvent event) {
1002
1003 synchronized(runningComponents) {
1004 if (runningComponents.containsKey(event.getSource().getComponentId())) return;
1005 runningComponents.put(event.getSource().getComponentId(), event.getSource());
1006 }
1007
1008 if (event.getSource() instanceof IJMXEnabled) {
1009 synchronized(getJMX()) {
1010 jmx.addComponent((IJMXEnabled) event.getSource());
1011 }
1012 }
1013 }
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023 protected synchronized void componentStarted(IPausedEvent event) {
1024
1025 synchronized(runningComponents) {
1026 if (runningComponents.containsKey(event.getSource().getComponentId())) return;
1027 runningComponents.put(event.getSource().getComponentId(), event.getSource());
1028 }
1029
1030 if (event.getSource() instanceof IJMXEnabled) {
1031 synchronized(getJMX()) {
1032 jmx.addComponent((IJMXEnabled) event.getSource());
1033 }
1034 }
1035 }
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045 protected synchronized void componentStopping(IStoppingEvent event) {
1046 if (stopMethodCalled) return;
1047 synchronized(stopDependencyToken) {
1048 if (stopDependencyToken.contains(event.getSource().getComponentId())) {
1049 if (log.isLoggable(Level.WARNING)) log.warning("Component " + event.getSource().getComponentId().getToken() + " that the agent depends on is stopping, stopping agent as well.");
1050 stop();
1051 return;
1052 }
1053 }
1054 synchronized(stopDependencyClass) {
1055 Class dependency = stopDependencyClass.containsClass(event.getSource().getClass());
1056 if (dependency != null) {
1057 if (log.isLoggable(Level.WARNING)) log.warning("Component of class " + dependency.getSimpleName() + " (id: " + event.getSource().getComponentId().getToken() + ") that tghe agent depends on is stopping, stopping agent as well.");
1058 stop();
1059 return;
1060 }
1061 }
1062 }
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072 protected synchronized void componentStopped(IStoppedEvent event) {
1073
1074 synchronized(runningComponents) {
1075 runningComponents.remove(event.getSource().getComponentId());
1076 if (runningComponents.size() == 0) {
1077 if (log.isLoggable(Level.WARNING)) log.warning("All agent's components has stopped. Stopping agent as well.");
1078 stop();
1079 }
1080 }
1081 }
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091 protected void componentFatalError(IFatalErrorEvent event) {
1092 if (inState(IAgentStateFailing.class)) return;
1093 try {
1094 setState(new AgentStateFailing(event.getMessage() + ", calling killAgent()."));
1095 } finally {
1096 try {
1097 preKillAgent();
1098 } finally {
1099 try {
1100 innerKillAgent();
1101 } finally {
1102
1103 try {
1104 setState(new AgentStateFailed(event.getMessage()));
1105 } finally {
1106 if (jmx != null) {
1107 getJMX().unregisterJMX();
1108 }
1109 }
1110 }
1111 }
1112 }
1113 }
1114
1115 protected void resetEvent(IResetEvent event) {
1116 resetAgent();
1117 }
1118
1119
1120
1121
1122
1123
1124
1125 protected AgentJMXComponents createAgentJMX() {
1126 return new AgentJMXComponents(this);
1127 }
1128
1129 protected void addDependency(IComponent component) {
1130 NullCheck.check(component, "component");
1131 addDependency(component.getComponentId());
1132 }
1133
1134 protected void addDependency(Class componentClass) {
1135 NullCheck.check(componentClass, "componentClass");
1136 synchronized(stopDependencyClass) {
1137 stopDependencyClass.add(componentClass);
1138 }
1139 }
1140
1141 protected void addDependency(IToken componentId) {
1142 NullCheck.check(componentId, "componentId");
1143 synchronized(stopDependencyToken) {
1144 stopDependencyToken.add(componentId);
1145 }
1146 }
1147
1148
1149
1150
1151
1152
1153
1154 protected void setState(AgentState state) {
1155 synchronized(agentState) {
1156 if (log.isLoggable(Level.FINER)) log.finer("Agent state is going to be switched to: " + state.toString());
1157 this.agentState.setFlag(state);
1158 if (log.isLoggable(Level.INFO)) log.info("Agent state switched to: " + state.toString());
1159 }
1160 }
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181 protected void addJMXComponents() {
1182 jmx.addComponent(logger);
1183 jmx.addComponent(new FolderToIJMXEnabledAdapter(getIntrospection()));
1184 }
1185
1186 @Override
1187 public String toString() {
1188 if (this == null) return "AbstractAgent[constructing]";
1189 else return getClass().getSimpleName() + "[" + getName() + "]";
1190 }
1191
1192 }