View Javadoc

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   * Shared component controller is meant to provide management of lifecycle methods of the {@link ISharedComponent} 
25   * while providing methods that has to be implemented by any {@link ISharedComponent}.
26   * <p><p>
27   * You can't actualy create {@link ISharedComponent} by extending this class, you have to create your own class implementing
28   * {@link ISharedComponent} interface and instantiate this class (wrap it) for yourself (and delegete all calls to methods
29   * from {@link ISharedComponent} to this class).
30   * <p><p>
31   * This decision has been deliberately made in order to allow anybody to create their shared components out of blue and add 
32   * lifecycle-management later on using this object.
33   * <p><p>
34   * To get the impression of what this class is doing, first read javadoc for {@link ComponentController}. Read? Good! So this
35   * object does something similar as {@link ComponentController} but not for simple {@link IComponent} but for {@link ISharedComponent} which
36   * means that we're dealing with the component that is shared by multiple agent instances, i.e., component that will be active on
37   * multiple {@link ILifecycleBus}es. Which means that we must auto-start/stop controlled component differently than {@link ComponentController} is
38   * doing.
39   * <p><p>
40   * The component should be started when any agent using it is starting and should be stop when the last agent that is using it is stopping. Similar 
41   * things applies for pause/resume. Simple to say, harder to perform. Nevertheless, the implementation is here ;-)
42   * 
43   * @author Jimmy
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  	 * Used as {@link IComponentControlHelper} that is passed to every {@link ILifecycleBus#addLifecycleManagement(IComponent, IComponentControlHelper, ComponentDependencies)}
68  	 * sensing decisions of ordinary {@link ComponentController} that signalizes when the component should be started for a given bus.
69  	 * <p><p>
70  	 * All lifecycle methods are just recalling {@link SharedComponentControl} signalizeXXX() methods where we truly decide whether the component
71  	 * should start/stop, etc.
72  	 * 
73  	 * @author Jimmy
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 	 * Mutex that is synchronizing access to internal data structures of the controller.
171 	 */
172 	protected Object ctrlMutex = new Object();
173 	
174 	/**
175 	 * Control helpers that are used to signalizes starting/stopping of the controlled {@link AbstractComponentControllerBase#component} inside
176 	 * bus of respective agents. 
177 	 */
178 	protected Map<IAgentId, ControlHelper> localControlHelpers = new HashMap<IAgentId, ControlHelper>();
179 	
180 	/**
181 	 * Controllers that are used to store {@link IComponentController} provided by respective {@link ILifecycleBus#addLifecycleManagement(IComponent, IComponentControlHelper, ComponentDependencies)}
182 	 * of agents using the component.
183 	 */
184 	protected Map<IAgentId, LocalController> localControllers = new HashMap<IAgentId, LocalController>();
185 	
186 	/**
187 	 * This map holds the currently desired {@link SharedComponentController#component} state inside the agent's bus.
188 	 */
189 	protected Map<IAgentId, ComponentState> componentStates = new HashMap<IAgentId, ComponentState>();
190 	
191 	
192 	/**
193 	 * Map tracking count of states of dependencies.
194 	 */
195 	protected Map<ComponentState, Integer> componentStateCount = new HashMap<ComponentState, Integer>();
196 
197 	/**
198 	 * Last fatal error sensed.
199 	 */
200 	protected IFatalErrorEvent fatalError;
201 	
202 	/**
203 	 * Default constructor. Nothing fancy...
204 	 * 
205 	 * @param component
206 	 * @param componentControl
207 	 * @param log
208 	 */
209 	public SharedComponentController(COMPONENT component, ISharedComponentControlHelper componentControl, Logger log) {
210 		super(component, componentControl, log);		
211 		
212 		// set initiali component state count
213 		for(ComponentState state : ComponentState.values()) {
214 			componentStateCount.put(state, 0);
215 		}
216 	}
217 	
218 	//
219 	//
220 	// PUBLIC INTERFACE - ISharedComponentController
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 			// alter the state count
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 				// the component was not registered for this agent
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 			// remove the lifecycle management for the component of respective bus
255 			bus.removeLifecycleManagement(component);
256 			
257 			// drop the control helper
258 			localControllers.remove(agentId);
259 			
260 			// unregister from the bus
261 			bus.remove(component);
262 			bus.remove(this);
263 			
264 			// decrease the state count
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 	// UTILITY METHODS
372 	//
373 	//
374 	
375 	/**
376 	 * Return how many components are in one of 'states'
377 	 * 
378 	 * @param states
379 	 * @return number of components in one of 'states'
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 	 * Checks sanity of the 'state' count 'newCount'
394 	 * @param newCount
395 	 * @param state
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 	 * Changes the count (by 'change') of the 'state', DOES NOT TRIGGER {@link SharedComponentController#componentStateCountChanged()}.
404 	 * @param state
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 	 * Increases (+1) count of the 'state', DOES NOT TRIGGER {@link SharedComponentController#componentStateCountChanged()}.
415 	 * @param state
416 	 */
417 	protected int increaseStateCount(ComponentState state) {
418 		return alterStateCount(state, 1);
419 	}
420 	
421 	
422 	/**
423 	 * Increases count (+n) of the 'state', DOES NOT TRIGGER {@link SharedComponentController#componentStateCountChanged()}.
424 	 * @param state
425 	 */
426 	protected int increaseStateCount(ComponentState state, int n) {
427 		return alterStateCount(state, n);
428 	}
429 
430 	/**
431 	 * Decreases (-1) count of the 'state', DOES NOT TRIGGER {@link SharedComponentController#componentStateCountChanged()}.
432 	 * @param state
433 	 */
434 	protected int decreaseStateCount(ComponentState state) {
435 		return alterStateCount(state, -1);
436 	}
437 	
438 	/**
439 	 * Decreases (-n) count of the 'state', DOES NOT TRIGGER {@link SharedComponentController#componentStateCountChanged()}.
440 	 * @param state
441 	 */
442 	protected int decreaseStateCount(ComponentState state, int n) {
443 		return alterStateCount(state, -n);
444 	}
445 	
446 	//
447 	//
448 	// LEVEL 1.A - SIGNALS FROM ComponentControllers(s)
449 	//   -- SYNCHRONIZED METHODS
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 				// can't happen ...
474 				throw new ComponentCantStartException(id(component) + "[" + getState().getFlag() + "] STATE INVALID AT THIS POINT!", this);				
475 			case RUNNING:
476 				// nothing to do
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(); // first reset the component
481 				if (notInState(ComponentState.RESETED)) throw new PogamutException(id(component) + "[" + getState().getFlag() + "] reset has failed, could not resolve the state change.", this);
482 				start(); // start it
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 				// nothing to do
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 				// can't happen ...
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(); // first reset the component
520 				if (notInState(ComponentState.RESETED)) throw new PogamutException(id(component) + "[" + getState().getFlag() + "] reset has failed, could not resolve the state change.", this);
521 				start(); // start it
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 				// nothing to do
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 				// can't happen ...
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(); // first reset the component
555 				if (notInState(ComponentState.RESETED)) throw new PogamutException(id(component) + "[" + getState().getFlag() + "] reset has failed, could not resolve the state change.", this);
556 				startPaused(); // start it in paused state
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 				// nothing to do
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 				// can't happen ...
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();       // reset the component first
590 				if (notInState(ComponentState.RESETED)) throw new PogamutException(id(component) + "[" + getState().getFlag() + "] reset has failed, could not resolve the state change.", this);
591 				startPaused(); // start the component
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 				// nothing to do ...
613 				// ... wait for the localPause(agentId)
614 				break;
615 			case PAUSED:
616 				// nothing to do
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 				// can't happen ...
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();       // reset the component first
630 				if (notInState(ComponentState.RESETED)) throw new PogamutException(id(component) + "[" + getState().getFlag() + "] reset has failed, could not resolve the state change.", this);
631 				startPaused(); // start the component
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 					// there is not a single agent that would need to utilize the component
653 					pause();
654 				}
655 				break;
656 			case PAUSED:
657 				// nothing to do
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 				// can't happen ...
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();       // reset the component first
671 				if (notInState(ComponentState.RESETED)) throw new PogamutException(id(component) + "[" + getState().getFlag() + "] reset has failed, could not resolve the state change.", this);
672 				startPaused(); // start the component
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 				// nothing to do
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 				// can't happen ...
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();       // reset the component first
707 				if (notInState(ComponentState.RESETED)) throw new PogamutException(id(component) + "[" + getState().getFlag() + "] reset has failed, could not resolve the state change.", this);
708 				start(); // start the component
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 				// nothing to do
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 				// can't happen ...
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();       // reset the component first
745 				if (notInState(ComponentState.RESETED)) throw new PogamutException(id(component) + "[" + getState().getFlag() + "] reset has failed, could not resolve the state change.", this);
746 				start(); // start the component
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 				// nothing to do
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 					// there is not a single agent that would need to utilize the component
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 				// can't happen ...
781 				throw new ComponentCantStartException(id(component) + "[" + getState().getFlag() + "] STATE INVALID AT THIS POINT!", this);				
782 			case KILLED:
783 				// nothing to do
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 				// nothing to do
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 					// there is not a single agent that would need to utilize the component
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 				// can't happen ...
816 				throw new ComponentCantStartException(id(component) + "[" + getState().getFlag() + "] STATE INVALID AT THIS POINT!", this);				
817 			case KILLED:
818 				// nothing to do
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 				// nothing to do move along
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 				// hups, fatal error has happened in agentId
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 				// expected, nothing to do...
855 				break;
856 			case KILLING:
857 				// can't happen ...
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 				// can't happen ...
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 	// LEVEL 1.B - STATE CHANGES FROM ComponentController(s)
879 	//   -- SYNCHRONIZED METHODS
880 	//
881 
882 	/**
883 	 * Signal that the component in the bus of agent identified by 'agentId' has changed into 'changedValue'.
884 	 */
885 	protected void stateChanged(IAgentId agentId, ComponentState changedValue) {
886 		synchronized(ctrlMutex) {
887 			// POSSIBLY GOING TO LEVEL 2
888 			setState(agentId, changedValue);
889 		}
890 	}
891 	
892 	/**
893 	 * Changes the state of the component for given agentId, triggers {@link SharedComponentController#componentStateCountChanged()}.
894 	 * 
895 	 * @param agentId
896 	 * @param newState may be null (== agentId has been deleted)
897 	 */
898 	protected void setState(IAgentId agentId, ComponentState newState) {
899 		synchronized(ctrlMutex) {
900 			// POSSIBLY GOING TO LEVEL 2
901 			setState(agentId, componentStates.get(agentId), newState);
902 		}
903 	}
904 	
905 	/**
906 	 * Changes the state of the component for given agentId, triggers {@link SharedComponentController#componentStateCountChanged()}.
907 	 * 
908 	 * @param agentId
909 	 * @param oldState may be null (== there was no previous state stored), MUST BE CORRECT!
910 	 * @param newState may be null (== agentId has been deleted)
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 			// GOING TO LEVEL 2
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 	// LEVEL 2 - CHANGES TO THE COMPONENT STATE COUNTS
939 	//   -- UNSYNCHRONIZED METHODS
940 	//
941 	
942 	protected void componentStateCountChanged(IAgentId origin, ComponentState oldState, ComponentState newState) {
943 		if (oldState == null) {
944 			// component has been registered to new agent
945 			newAgentIsUsingTheComponent(origin, newState);
946 		} else
947 		if (newState == null) {
948 			// component has been removed from the agent
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 		// check whether the component should not be started / resumed
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 				// there are agent wishing to use the component
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 				// there are agent wishing to use the component but currently are paused
970 				startPaused();
971 			}	
972 			break;
973 
974 		case RUNNING:
975 			// nothing to do
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 				// there are agent wishing to use the component
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 			// can't happen ...
993 			throw new ComponentCantStartException(id(component) + "[" + getState().getFlag() + "] STATE INVALID AT THIS POINT!", this);
994 			
995 		case KILLING:
996 			// can't happen ...
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); // evaluate the state again
1004 			break;
1005 		}
1006 	}
1007 	
1008 	protected void agentStoppedUsingTheComponent(IAgentId agentId, ComponentState oldState) {
1009 		// check whether the component should not be stopped / paused
1010 		switch(getState().getFlag()) {
1011 		case INSTANTIATED:
1012 		case STOPPED:
1013 		case RESETED:
1014 			// nothing to do	
1015 			break;
1016 
1017 		case RUNNING:
1018 			if (getStateCount(ComponentState.STARTING, ComponentState.RUNNING, ComponentState.RESUMING) == 0) {
1019 				// there is nobody that wants to activelly use the agent
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 					// there are agent wishing to use the component but are currently paused
1023 					pause();
1024 				} else
1025 				if (getStateCount(ComponentState.PAUSING) == 0) {
1026 					// nobody is actively using the component nor is paused
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 						// and is event not stopping
1030 						stop();
1031 					}
1032 				}				 
1033 			} // else, there are still somebody who wants to use the component, keep it running!
1034 			break;
1035 			
1036 		case PAUSED:
1037 			if (getStateCount(ComponentState.STARTING, ComponentState.RUNNING, ComponentState.RESUMING) == 0) {
1038 				// there is nobody that wants to activelly use the agent
1039 				if (getStateCount(ComponentState.STARTING_PAUSED, ComponentState.PAUSING, ComponentState.PAUSED) > 0) {
1040 					// nothing to do
1041 				} else {
1042 					// nobody is actively using the component nor is paused
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 						// and is event not stopping
1046 						stop();
1047 					}
1048 				}				 
1049 			} else {
1050 				// can't happen ...
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 			// can't happen ...
1062 			throw new ComponentCantStartException(id(component) + "[" + getState().getFlag() + "] STATE INVALID AT THIS POINT!", this);
1063 			
1064 		case KILLING:
1065 			// can't happen ...
1066 			throw new ComponentCantStartException(id(component) + "[" + getState().getFlag() + "] STATE INVALID AT THIS POINT!", this);
1067 			
1068 		case KILLED:
1069 			// nothing to do
1070 			break;
1071 		}
1072 	}
1073 
1074 	protected void componentStateChanged(IAgentId origin, ComponentState oldState, ComponentState newState) {
1075 		// should we be killed?
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 				// the component is being currently killed ... we've got here because fatal error has been broadcast to all other buses
1083 				return;
1084 			}
1085 			// we have to kill the component
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 		// we should not be killed
1094 		// check whether the component should not be stopped / paused / started / resumed
1095 		switch(getState().getFlag()) {
1096 		case INSTANTIATED:
1097 		case STOPPED:
1098 		case RESETED:
1099 			if (getStateCount(ComponentState.RUNNING) > 0) {				
1100 				// this means we have screwed up!
1101 				throw new PogamutException(id(component) + "[" + getState().getFlag() + "] the component should have been already running!", this);
1102 			}
1103 			if (getStateCount(ComponentState.PAUSED) > 0) {
1104 				// this means we have screwed up!
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 				// there are agent wishing to use the component
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 				// there are agent wishing to use the component but currently are paused
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 				// there is nobody that wants to activelly use the agent
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 					// there are agent wishing to use the component but are currently paused
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 						// nobody is actively using the component nor is paused
1135 						stop();
1136 					}
1137 				}				 
1138 			} // else, there are still somebody who wants to use the component, keep it running!
1139 			break;
1140 			
1141 		case PAUSED:
1142 			if (getStateCount(ComponentState.STARTING, ComponentState.RUNNING, ComponentState.RESUMING) == 0) {
1143 				// there is nobody that wants to activelly use the agent
1144 				if (getStateCount(ComponentState.STARTING_PAUSED, ComponentState.PAUSING, ComponentState.PAUSED) > 0) {
1145 					// nothing to do!
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 						// nobody is actively using the component nor is paused
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 			// can't happen ...
1166 			throw new ComponentCantStartException(id(component) + "[" + getState().getFlag() + "] STATE INVALID AT THIS POINT!", this);
1167 			
1168 		case KILLING:
1169 			// can't happen ...
1170 			throw new ComponentCantStartException(id(component) + "[" + getState().getFlag() + "] STATE INVALID AT THIS POINT!", this);
1171 			
1172 		case KILLED:
1173 			reset(); // reset the component
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); // reevaluate the state again
1176 			break;
1177 		}
1178 	}
1179 
1180 	
1181 	//
1182 	//
1183 	// LEVEL 4 - START / STOP
1184 	//   -- UNSYNCHRONIZED METHODS!
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 	 * AgentId has broadcast {@link IFatalErrorEvent}, tear down the whole system!
1237 	 * @param agentId may be null
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; // do not broadcast fatal error to the bus which triggers the KILL
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 }