View Javadoc

1   package cz.cuni.amis.pogamut.base.component.lifecyclebus;
2   
3   import java.util.Collection;
4   import java.util.Collections;
5   import java.util.HashMap;
6   import java.util.HashSet;
7   import java.util.Map;
8   import java.util.Queue;
9   import java.util.Set;
10  import java.util.concurrent.ConcurrentHashMap;
11  import java.util.concurrent.ConcurrentLinkedQueue;
12  import java.util.logging.Level;
13  import java.util.logging.Logger;
14  
15  import com.google.inject.Inject;
16  
17  import cz.cuni.amis.pogamut.base.agent.IAgentId;
18  import cz.cuni.amis.pogamut.base.component.IComponent;
19  import cz.cuni.amis.pogamut.base.component.IComponentAware;
20  import cz.cuni.amis.pogamut.base.component.bus.ComponentBus;
21  import cz.cuni.amis.pogamut.base.component.bus.IComponentBus;
22  import cz.cuni.amis.pogamut.base.component.bus.IComponentEvent;
23  import cz.cuni.amis.pogamut.base.component.bus.IComponentEventListener;
24  import cz.cuni.amis.pogamut.base.component.bus.event.IFatalErrorEvent;
25  import cz.cuni.amis.pogamut.base.component.bus.event.IPausedEvent;
26  import cz.cuni.amis.pogamut.base.component.bus.event.IPausingEvent;
27  import cz.cuni.amis.pogamut.base.component.bus.event.IResetEvent;
28  import cz.cuni.amis.pogamut.base.component.bus.event.IResumedEvent;
29  import cz.cuni.amis.pogamut.base.component.bus.event.IResumingEvent;
30  import cz.cuni.amis.pogamut.base.component.bus.event.IStartedEvent;
31  import cz.cuni.amis.pogamut.base.component.bus.event.IStartingEvent;
32  import cz.cuni.amis.pogamut.base.component.bus.event.IStartingPausedEvent;
33  import cz.cuni.amis.pogamut.base.component.bus.event.IStoppedEvent;
34  import cz.cuni.amis.pogamut.base.component.bus.event.IStoppingEvent;
35  import cz.cuni.amis.pogamut.base.component.bus.event.impl.ComponentBusErrorEvent;
36  import cz.cuni.amis.pogamut.base.component.bus.event.impl.FatalErrorEvent;
37  import cz.cuni.amis.pogamut.base.component.bus.event.impl.FatalErrorPropagatingEvent;
38  import cz.cuni.amis.pogamut.base.component.bus.event.impl.ResetEvent;
39  import cz.cuni.amis.pogamut.base.component.bus.exception.ComponentBusErrorException;
40  import cz.cuni.amis.pogamut.base.component.bus.exception.ComponentBusNotRunningException;
41  import cz.cuni.amis.pogamut.base.component.bus.exception.ComponentIdClashException;
42  import cz.cuni.amis.pogamut.base.component.bus.exception.FatalErrorPropagatingEventException;
43  import cz.cuni.amis.pogamut.base.component.bus.exception.MoreComponentsForClassException;
44  import cz.cuni.amis.pogamut.base.component.bus.exception.ResetFailedException;
45  import cz.cuni.amis.pogamut.base.component.controller.ComponentController;
46  import cz.cuni.amis.pogamut.base.component.controller.ComponentDependencies;
47  import cz.cuni.amis.pogamut.base.component.controller.ComponentState;
48  import cz.cuni.amis.pogamut.base.component.controller.IComponentControlHelper;
49  import cz.cuni.amis.pogamut.base.component.controller.IComponentController;
50  import cz.cuni.amis.pogamut.base.component.exception.ComponentLifecycleManagementAlreadyRegisteredException;
51  import cz.cuni.amis.pogamut.base.utils.guice.AgentScoped;
52  import cz.cuni.amis.pogamut.base.utils.logging.IAgentLogger;
53  import cz.cuni.amis.pogamut.base.utils.logging.LogCategory;
54  import cz.cuni.amis.utils.ClassUtils;
55  import cz.cuni.amis.utils.Const;
56  import cz.cuni.amis.utils.ExceptionToString;
57  import cz.cuni.amis.utils.NullCheck;
58  import cz.cuni.amis.utils.flag.Flag;
59  import cz.cuni.amis.utils.flag.ImmutableFlag;
60  import cz.cuni.amis.utils.flag.WaitForFlagChange.IAccept;
61  import cz.cuni.amis.utils.maps.LazyMap;
62  import cz.cuni.amis.utils.sets.ConcurrentHashSet;
63  import cz.cuni.amis.utils.sets.ConcurrentLinkedHashSet;
64  import cz.cuni.amis.utils.token.IToken;
65  import cz.cuni.amis.utils.token.Tokens;
66  
67  /**
68   * Lifecycle bus is implementing {@link ILifecycleBus} which is extending {@link IComponentBus} by implementing the knowledge of lifecycle states of various {@link IComponent}s. It watches
69   * over the {@link ComponentState}s, providing information about them.
70   * <p><p>
71   * Too complex - not suitable for inheritance ... copy paste source code and change it manually ... as it was done for {@link ComponentBus} before.
72   * <p><p>
73   * For more documentation see {@link IComponentBus}.
74   * <p><p>
75   * For more documentation regarding lifecycle management, see {@link ComponentController} as {@link LifecycleBus} is working the same way.
76   * 
77   * @author Jimmy
78   */
79  @AgentScoped
80  public class LifecycleBus implements ILifecycleBus, IComponentAware {
81  	
82  	/////
83  	//////////
84  	//
85  	// EVENT MANAGEMENT - IMPLEMENTATION OF IComponentBus INTERFACE
86  	//
87  	//////////
88  	/////
89  
90  	
91  	public static final IToken COMPONENT_ID = Tokens.get("LifecycleBus");
92  	
93  	private Map<IToken, IComponent> componentsByToken = new ConcurrentHashMap<IToken, IComponent>();
94  
95  	private Map<Class, Set<IComponent>> componentsByClass = new LazyMap<Class, Set<IComponent>>(new ConcurrentHashMap<Class, Set<IComponent>>()) {
96  
97  		@Override
98  		protected Set<IComponent> create(Class key) {
99  			return new ConcurrentHashSet<IComponent>();
100 		}
101 		
102 	};
103 
104 	private Map<Class, Set<IComponentEventListener>> eventListeners = new LazyMap<Class, Set<IComponentEventListener>>(new ConcurrentHashMap<Class, Set<IComponentEventListener>>()) {
105 
106 		@Override
107 		protected Set<IComponentEventListener> create(Class key) {
108 			return new ConcurrentLinkedHashSet<IComponentEventListener>();
109 		}
110 				
111 	};
112 	
113 	private Map<Class, Map<Class, Set<IComponentEventListener>>> componentEventListeners = new LazyMap<Class, Map<Class, Set<IComponentEventListener>>>(new ConcurrentHashMap<Class, Map<Class, Set<IComponentEventListener>>>()) {
114 
115 		@Override
116 		protected Map<Class, Set<IComponentEventListener>> create(Class key) {
117 			return new LazyMap<Class, Set<IComponentEventListener>>(new ConcurrentHashMap<Class, Set<IComponentEventListener>>()) {
118 
119 				@Override
120 				protected Set<IComponentEventListener> create(Class key) {
121 					return new ConcurrentLinkedHashSet<IComponentEventListener>();
122 				}
123 				
124 			};
125 		}
126 		
127 	};
128 	
129 	private Map<IToken, Map<Class, Set<IComponentEventListener>>> componentNameEventListeners = new LazyMap<IToken, Map<Class, Set<IComponentEventListener>>>() {
130 
131 		@Override
132 		protected Map<Class, Set<IComponentEventListener>> create(IToken key) {
133 			return new LazyMap<Class, Set<IComponentEventListener>>(new ConcurrentHashMap<Class, Set<IComponentEventListener>>()) {
134 
135 				@Override
136 				protected Set<IComponentEventListener> create(Class key) {
137 					return new ConcurrentLinkedHashSet<IComponentEventListener>();
138 				}
139 				
140 			};
141 		}
142 		
143 	};
144 	
145 	/**
146 	 * Whether the bus is running. Dropped after IFatalError event.
147 	 */
148 	private boolean running = true;
149 		
150 	/**
151 	 * List of events we have to process.
152 	 * <p><p>
153 	 * It is managed only by raiseEvent() method - DO NOT MODIFY OUTSIDE IT!
154 	 */
155 	private Queue<IComponentEvent> queue = new ConcurrentLinkedQueue();
156 
157 	/**
158 	 * Flag that is telling us whether there is an event being processed or not.
159 	 * <p><p>
160 	 * It is managed only by raiseEvent() method - DO NOT MODIFY IT FROM OUTSIDE THAT METHOD!
161 	 */
162 	private boolean queueProcessing = false;
163 	
164 	/**
165 	 * Used by processQueue() for the sync.
166 	 */
167 	private Object queueProcessingMutex = new Object();
168 	
169 	private LogCategory log;
170 
171 	private IAgentId agentId;
172 	
173 	@Inject
174 	public LifecycleBus(IAgentLogger logger) {
175 		NullCheck.check(logger, "logger");
176 		this.agentId = logger.getAgentId();
177 		this.log = logger.getCategory(this);
178 		NullCheck.check(this.log, "log category returned by the logger");
179 		registerComponentStateListeners();
180 	}
181 	
182 	@Override
183 	public String toString() {
184 		return "LifecycleBus[" + agentId.getToken() + ", running=" + running + ", queue length=" + (this.queue == null ? "null" : this.queue.size()) + "]";
185 	}
186 	
187 	@Override
188 	public IComponentBus getEventBus() {
189 		return this;
190 	}
191 	
192 	@Override
193 	public IToken getComponentId() {
194 		return COMPONENT_ID;
195 	}
196 	
197 	public Logger getLog() {
198 		return log;
199 	}
200 	
201 	@Override
202 	public boolean isRunning() {
203 		return running;
204 	}
205 	
206 	@Override
207 	public synchronized void reset() throws ResetFailedException {
208 		if (log.isLoggable(Level.WARNING)) log.warning("reset() called.");
209 		try {
210 			if (running) {
211 				if (log.isLoggable(Level.WARNING)) log.warning(LifecycleBus.COMPONENT_ID.getToken() + " is still running, broadcasting fatal error to stop all components.");
212 				event(new FatalErrorEvent<IComponent>(this, "Resetting."));
213 			}
214 			if (log.isLoggable(Level.WARNING)) log.warning("Broadcasting reset event.");
215 			resetBus();
216 			innerRaiseEvent(new ResetEvent(this));
217 		} catch (Exception e) {
218 			if (e instanceof ComponentBusErrorException) {
219 				innerRaiseEvent(new FatalErrorEvent(this, "Reset failed.", e.getCause()));
220 				throw new ResetFailedException(e.getCause(), log, this);
221 			} else {
222 				innerRaiseEvent(new FatalErrorEvent(this, "Reset failed.", e));
223 				throw new ResetFailedException(e, log, this);
224 			}
225 		}
226 		if (log.isLoggable(Level.WARNING)) log.warning("Reseted, bus is running again.");
227 	} 
228 	
229 	private void resetBus() {
230 		running = true;
231 		queue.clear();
232 		queueProcessing = false;
233 	}
234 	
235 	//
236 	//
237 	// COMPONENTS
238 	//
239 	//
240 	
241 	@Override
242 	public <T> T getComponent(Class<T> cls) throws MoreComponentsForClassException {
243 		Set<T> components = (Set<T>) componentsByClass.get(cls);
244 		if (components.size() > 0) throw new MoreComponentsForClassException(cls, components, this);
245 		return components.iterator().next();
246 	}
247 
248 	@Override
249 	public <T> Set<T> getComponents(Class<T> cls) {
250 		return (Set<T>) Collections.unmodifiableSet(componentsByClass.get(cls));
251 	}
252 	
253 	@Override
254 	public void register(IComponent component) throws ComponentIdClashException {
255 		synchronized(componentsByToken) {
256 			NullCheck.check(component.getComponentId(), "component's id is null ("+ component + ")");
257 			if (componentsByToken.get(component.getComponentId()) != null) {
258 				if (componentsByToken.get(component.getComponentId()) == component) {
259 					return;
260 				} else {
261 					ComponentIdClashException e = new ComponentIdClashException(component.getComponentId(), log, this);
262 					try {
263 						event(new FatalErrorEvent(this, e));
264 					} catch (Exception e1) {
265 					}
266 					throw e;
267 				}
268 			}			
269 			registerComponent(component);
270 		}
271 	}
272 	
273 	@Override
274 	public void remove(IComponent component) {
275 		synchronized(componentsByToken) {
276 			componentsByToken.remove(component.getComponentId());
277 			Collection<Class> componentClasses = ClassUtils.getSubclasses(component.getClass());
278 			for (Class cls : componentClasses) {
279 				componentsByClass.get(cls).remove(component);
280 			}
281 			if (log.isLoggable(Level.INFO)) log.info(component + " of the id " + component.getComponentId().getToken() + " removed from the bus.");
282 		}
283 	}
284 	
285 	/**
286 	 * Called whenever new component is being registered.
287 	 * <p><p>
288 	 * Method assumes it is "synchronized" by caller.
289 	 * <p><p>
290 	 * This method also assumes there is no component-id clash with existing components! Checks
291 	 * has been done already inside register() method.
292 	 * 
293 	 * @param component
294 	 */
295 	private void registerComponent(IComponent component) {
296 		componentsByToken.put(component.getComponentId(), component);
297 		Collection<Class> componentClasses = ClassUtils.getSubclasses(component.getClass());
298 		for (Class cls : componentClasses) {
299 			componentsByClass.get(cls).add(component);
300 		}
301 		setComponentState(component.getComponentId(), ComponentState.INSTANTIATED);
302 		if (log.isLoggable(Level.INFO)) log.info(component + " registered under id " + component.getComponentId().getToken());
303 	}
304 	
305 	@Override
306 	public IComponent getComponent(IToken name) {
307 		return componentsByToken.get(name);
308 	}
309 	
310 	//
311 	//
312 	// EVENTS LISTENER
313 	// 
314 	//
315 	
316 	@Override
317 	public void addEventListener(Class<?> event, IComponentEventListener<?> listener) {
318 		NullCheck.check(event, "event");
319 		NullCheck.check(listener, "listener");
320 		eventListeners.get(event).add(listener);
321 	}
322 	
323 	@Override
324 	public void addEventListener(Class<?> event, Class<?> component, IComponentEventListener<?> listener) {
325 		NullCheck.check(event, "event");
326 		NullCheck.check(component, "comopnent");
327 		NullCheck.check(listener, "listener");
328 		componentEventListeners.get(component).get(event).add(listener);
329 	}
330 
331 	@Override
332 	public void addEventListener(Class<?> event, IToken componentName, IComponentEventListener<?> listener) {
333 		NullCheck.check(event, "event");
334 		NullCheck.check(componentName, "componentName");
335 		NullCheck.check(listener, "listener");
336 		componentNameEventListeners.get(componentName).get(event).add(listener);
337 	}
338 	
339 	@Override
340 	public void addEventListener(Class<?> event, IComponent component, IComponentEventListener<?> listener) {
341 		NullCheck.check(component, "component");
342 		addEventListener(event, component.getComponentId(), listener);
343 	}
344 	
345 	@Override
346 	public boolean isListening(Class<?> event, IComponentEventListener<?> listener) {
347 		NullCheck.check(event, "event");
348 		NullCheck.check(listener, "listener");
349 		if (!eventListeners.containsKey(event)) return false;
350 		return eventListeners.get(event).contains(listener);
351 	}
352 	
353 	@Override
354 	public boolean isListening(Class<?> event, Class<?> component, IComponentEventListener<?> listener) {
355 		NullCheck.check(event, "event");
356 		NullCheck.check(component, "component");
357 		NullCheck.check(listener, "listener");
358 		if (!componentEventListeners.containsKey(component)) return false;
359 		Map<Class, Set<IComponentEventListener>> listeners = componentEventListeners.get(component);
360 		if (!listeners.containsKey(event)) return false;
361 		return listeners.get(event).contains(listener);
362 	}
363 
364 	@Override
365 	public boolean isListening(Class<?> event, IToken componentId, IComponentEventListener<?> listener) {
366 		NullCheck.check(event, "event");
367 		NullCheck.check(componentId, "componentId");
368 		NullCheck.check(listener, "listener");
369 		if (!componentNameEventListeners.containsKey(componentId)) return false;
370 		Map<Class, Set<IComponentEventListener>> listeners = componentNameEventListeners.get(componentId);
371 		if (!listeners.containsKey(event)) return false;
372 		return listeners.get(event).contains(listener);
373 	}
374 	
375 	@Override
376 	public boolean isListening(Class<?> event, IComponent component, IComponentEventListener<?> listener) {
377 		NullCheck.check(component, "component");
378 		return isListening(event, component.getComponentId(), listener);
379 	}
380 
381 	@Override
382 	public void removeEventListener(Class<?> event, IComponentEventListener<?> listener) {
383 		NullCheck.check(event, "event");
384 		NullCheck.check(listener, "listener");
385 		if (!eventListeners.containsKey(event)) return;
386 		eventListeners.get(event).remove(listener);
387 	}
388 
389 	@Override
390 	public void removeEventListener(Class<?> event, Class<?> component,	IComponentEventListener<?> listener) {
391 		NullCheck.check(event, "event");
392 		NullCheck.check(component, "component");
393 		NullCheck.check(listener, "listener");
394 		if (!componentEventListeners.containsKey(component)) return;
395 		Map<Class, Set<IComponentEventListener>> listeners = componentEventListeners.get(component);
396 		if (!listeners.containsKey(event)) return;
397 		listeners.get(event).remove(listener);
398 	}
399 
400 	@Override
401 	public void removeEventListener(Class<?> event, IToken componentId, IComponentEventListener<?> listener) {
402 		NullCheck.check(event, "event");
403 		NullCheck.check(componentId, "componentId");
404 		NullCheck.check(listener, "listener");
405 		if (!componentNameEventListeners.containsKey(componentId)) return;
406 		Map<Class, Set<IComponentEventListener>> listeners = componentNameEventListeners.get(componentId);
407 		if (!listeners.containsKey(event)) return;
408 		listeners.get(event).remove(listener);
409 	}
410 	
411 	@Override
412 	public void removeEventListener(Class<?> event, IComponent component, IComponentEventListener<?> listener) {
413 		NullCheck.check(component, "component");
414 		removeEventListener(event, component.getComponentId(), listener);
415 	}
416 	
417 	//
418 	//
419 	// EVENT PROCESSING
420 	//
421 	//
422 		
423 	/**
424 	 * Helper method used ONLY FROM innerRaiseEvent. DO NOT USE OUTSIDE THAT METHOD!
425 	 * <p><p>
426 	 * Notifies only if isRunning().
427 	 * 
428 	 * @param event
429 	 */
430 	private void notifyListenersA(IComponentEvent event) {
431 		Collection<Class> eventClasses = ClassUtils.getSubclasses(event.getClass());
432 		for (Class eventClass : eventClasses) {
433 			if (!eventListeners.containsKey(eventClass)) continue;
434 			for (IComponentEventListener listener : eventListeners.get(eventClass)) {
435 				if (!isRunning()) return;
436 				listener.notify(event);
437 			}
438 		}
439 	}
440 
441 	/**
442 	 * Helper method used ONLY FROM innerRaiseEvent. DO NOT USE OUTSIDE THAT METHOD!
443 	 * <p><p>
444 	 * Notifies only if isRunning().
445 	 * 
446 	 * @param event
447 	 */
448 	private void notifyListenersB(IComponentEvent event) {
449 		Collection<Class> componentClasses = ClassUtils.getSubclasses(event.getSource().getClass());
450 		Collection<Class> eventClasses = ClassUtils.getSubclasses(event.getClass());
451 		for (Class componentClass : componentClasses) {
452 			if (!componentEventListeners.containsKey(componentClass)) continue;
453 			Map<Class, Set<IComponentEventListener>> listeners = componentEventListeners.get(componentClass);
454 			for (Class eventClass : eventClasses) {
455 				if (!listeners.containsKey(eventClass)) continue;
456 				for (IComponentEventListener listener : listeners.get(eventClass)) {
457 					if (!isRunning()) return;
458 					listener.notify(event);
459 				}
460 			}
461 		}
462 	}
463 	
464 	/**
465 	 * Helper method used ONLY FROM innerRaiseEvent. DO NOT USE OUTSIDE THAT METHOD!
466 	 * <p><p>
467 	 * Notifies only if isRunning().
468 	 * 
469 	 * @param event
470 	 */
471 	private void notifyListenersC(IComponentEvent event) {
472 		if (!componentNameEventListeners.containsKey(event.getSource().getComponentId())) return;
473 		Map<Class, Set<IComponentEventListener>> listeners = componentNameEventListeners.get(event.getSource().getComponentId());
474 		Collection<Class> eventClasses = ClassUtils.getSubclasses(event.getClass());
475 		for (Class eventClass : eventClasses) {
476 			if (!listeners.containsKey(eventClass)) continue;
477 			for (IComponentEventListener listener : listeners.get(eventClass)) {
478 				if (!isRunning()) return;
479 				listener.notify(event);
480 			}
481 		}
482 	}
483 
484 	/**
485 	 * Helper method used ONLY FROM innerRaiseEvent. DO NOT USE OUTSIDE THAT METHOD!
486 	 * <p><p>
487 	 * Notification is done safe-way ... every listener is notified even if an exception happens in one of them.
488 	 * <p><p>
489 	 * Notifies also if is not running (used for propagation of {@link IFatalErrorEvent}.
490 	 * 
491 	 * @param event
492 	 */
493 	private void notifyListenersA_Safe(IComponentEvent event) {
494 		Collection<Class> eventClasses = ClassUtils.getSubclasses(event.getClass());
495 		for (Class eventClass : eventClasses) {
496 			if (!eventListeners.containsKey(eventClass)) continue;
497 			for (IComponentEventListener listener : eventListeners.get(eventClass)) {
498 				try {
499 					listener.notify(event);
500 				} catch (Exception e) {
501 					if (log.isLoggable(Level.WARNING)) log.warning(ExceptionToString.process("Exception happened during notification of event " + event + " on listener " + listener + ".", e));
502 				}
503 			}
504 		}
505 	}
506 
507 	/**
508 	 * Helper method used ONLY FROM innerRaiseEvent. DO NOT USE OUTSIDE THAT METHOD!
509 	 * <p><p>
510 	 * Notification is done safe-way ... every listener is notified even if an exception happens in one of them.
511 	 * <p><p>
512 	 * Notifies also if is not running (used for propagation of {@link IFatalErrorEvent}.
513 	 * 
514 	 * @param event
515 	 */
516 	private void notifyListenersB_Safe(IComponentEvent event) {
517 		Collection<Class> componentClasses = ClassUtils.getSubclasses(event.getSource().getClass());
518 		Collection<Class> eventClasses = ClassUtils.getSubclasses(event.getClass());
519 		for (Class componentClass : componentClasses) {
520 			if (!componentEventListeners.containsKey(componentClass)) continue;
521 			Map<Class, Set<IComponentEventListener>> listeners = componentEventListeners.get(componentClass);
522 			for (Class eventClass : eventClasses) {
523 				if (!listeners.containsKey(eventClass)) continue;
524 				for (IComponentEventListener listener : listeners.get(eventClass)) {
525 					try {
526 						listener.notify(event);
527 					} catch (Exception e) {
528 						if (log.isLoggable(Level.WARNING)) log.warning(ExceptionToString.process("Exception happened during notification of event " + event + " on listener " + listener + ".", e));
529 					}
530 				}
531 			}
532 		}
533 	}
534 	
535 	/**
536 	 * Helper method used ONLY FROM innerRaiseEvent. DO NOT USE OUTSIDE THAT METHOD!
537 	 * <p><p>
538 	 * Notification is done safe-way ... every listener is notified even if an exception happens in one of them.
539 	 * <p><p>
540 	 * Notifies also if is not running (used for propagation of {@link IFatalErrorEvent}.
541 	 * 
542 	 * @param event
543 	 */
544 	private void notifyListenersC_Safe(IComponentEvent event) {
545 		if (!componentNameEventListeners.containsKey(event.getSource().getComponentId())) return;
546 		Map<Class, Set<IComponentEventListener>> listeners = componentNameEventListeners.get(event.getSource().getComponentId());
547 		Collection<Class> eventClasses = ClassUtils.getSubclasses(event.getClass());
548 		for (Class eventClass : eventClasses) {
549 			if (!listeners.containsKey(eventClass)) continue;
550 			for (IComponentEventListener listener : listeners.get(eventClass)) {
551 				try {
552 					listener.notify(event);
553 				} catch (Exception e) {
554 					if (log.isLoggable(Level.WARNING)) log.warning(ExceptionToString.process("Exception happened during notification of event " + event + " on listener " + listener + ".", e));
555 				}
556 			}
557 		}
558 	}
559 	
560 	/**
561 	 * Process new IWorldEvent - DO NOT CALL SEPARATELY - must be called only from raiseEvent(),
562 	 * that forbids recursion of its calls.
563 	 * <p><p>
564 	 * Contains the sequence in which the listeners are informed about the event.
565 	 * @param event
566 	 */
567 	private void innerRaiseEvent(IComponentEvent event) {		
568 		if (event instanceof IFatalErrorEvent) {
569 			if (log.isLoggable(Level.SEVERE)) log.severe("Fatal error happenned - component bus is stopping." + Const.NEW_LINE + ((IFatalErrorEvent)event).getSummary());
570 			queue.clear();
571 			running = false;
572 			notifyListenersA_Safe(event);
573 			notifyListenersB_Safe(event);
574 			notifyListenersC_Safe(event);
575 			return;
576 		} else {
577 			if (log.isLoggable(Level.FINE)) log.fine("Notifying " + event);
578 		}
579 		if (!isRunning()) return;
580 		notifyListenersA(event);
581 		if (!isRunning()) return;
582 		notifyListenersB(event);
583 		if (!isRunning()) return;
584 		notifyListenersC(event);
585 	}
586 	
587 	/**
588 	 * Process new IWorldEvent - DO NOT CALL SEPARATELY - must be called only from raiseEvent(),
589 	 * that forbids recursion of its calls.
590 	 * <p><p>
591 	 * Contains the sequence in which the listeners are informed about the event.
592 	 * <p><p>
593 	 * Notification is done safe-way ... every listener is notified even if an exception happens in one of them.
594 	 * 
595 	 * @param event
596 	 */
597 	private void innerRaiseEvent_Safe(IComponentEvent event) {
598 		if (event instanceof IFatalErrorEvent) {
599 			if (log.isLoggable(Level.SEVERE)) log.severe("Fatal error happenned - component bus is stopping." + Const.NEW_LINE + ((IFatalErrorEvent)event).getSummary());
600 			queue.clear();
601 			running = false;
602 		} else {
603 			if (log.isLoggable(Level.FINE)) log.fine("Notifying (safe) " + event);
604 		}
605 		notifyListenersA_Safe(event);
606 		notifyListenersB_Safe(event);
607 		notifyListenersC_Safe(event);
608 	}
609 	
610 	@Override
611 	public synchronized boolean event(IComponentEvent event) throws ComponentBusNotRunningException, ComponentBusErrorException, FatalErrorPropagatingEventException {
612 		// method is synchronized - only one thread inside at given time
613 		
614 		NullCheck.check(event, "event");
615 		if (event instanceof IResetEvent) throw new IllegalArgumentException("you can't broadcast reset event this way, use reset() instead");
616 			
617 		if (!isRunning()) {			
618 			if (event instanceof IFatalErrorEvent) {
619 				try {
620 					if (log.isLoggable(Level.WARNING)) log.warning("Component bus is not running, ignoring fatal error event from " + event.getSource() + ".");
621 				} catch (Exception e) {
622 				}
623 				return false;
624 			}
625 			throw new ComponentBusNotRunningException(event, log, this);
626 		}
627 		
628 		// is it fatal error event?
629 		if (event instanceof IFatalErrorEvent) {
630 			if (!isRunning()) {
631 				try {
632 					if (log.isLoggable(Level.WARNING)) log.warning("Component bus is not running, ignoring fatal error event from " + event.getSource() + ".");
633 				} catch (Exception e) {
634 				}
635 				return false;
636 			}
637 			// yes -> process it immediately
638 			innerRaiseEvent(event);
639 			return false;
640 		}
641 		
642 		// is this method recursively called? 
643 		if (queueProcessing) {
644 			// yes it is -> that means the previous event has not been
645 			// processed! ... store this event and allows the previous one
646 			// to be fully processed (e.g. postpone raising this event)
647 			queue.add(event);
648 			return false;
649 		}
650 		
651 		// check the queue consistency
652 		if (queue.size() > 0) {
653 			ComponentBusErrorException e = new ComponentBusErrorException("Previous events has not been fully processed! ComponenBus fatal error.", event, this);
654 			innerRaiseEvent_Safe(
655 				new ComponentBusErrorEvent(this, e)
656 			);
657 			throw e;
658 		}
659 		
660 		// add the event to the queue
661 		queue.add(event);
662 		// start processing the event
663 		processQueue();		
664 		
665 		// event has been processed
666 		return true;
667 	}
668 	
669 	@Override
670 	public synchronized void eventTransactional(IComponentEvent event) throws ComponentBusNotRunningException, ComponentBusErrorException, FatalErrorPropagatingEventException {
671 		// method is synchronized - only one thread inside at given time
672 		
673 		NullCheck.check(event, "event");
674 		if (event instanceof IResetEvent) throw new IllegalArgumentException("you can't broadcast reset event this way, use reset() instead");
675 		
676 		if (!isRunning()) {
677 			if (event instanceof IFatalErrorEvent) {
678 				try {
679 					if (log.isLoggable(Level.WARNING)) log.warning("Component bus is not running, ignoring fatal error event from " + event.getSource() + ".");
680 				} catch (Exception e) {
681 				}
682 				return;
683 			}
684 			throw new ComponentBusNotRunningException(event, log, this);
685 		}
686 		
687 		if (!queueProcessing) {
688 			// the method is not being called in the context of another event, redirect
689 			event(event);
690 			return;
691 		}
692 		 
693 		// process event - we're in transactional mode == immediately propagate the event
694 		innerRaiseEvent(event);
695 	}
696 	
697 	/**
698 	 * Must be synchronized beforehand!
699 	 */
700 	private void processQueue() throws FatalErrorPropagatingEventException, ComponentBusErrorException {
701 		// save the 'queueProcessing' state (whether we should drop the queue processing flag or not at the end of this method)
702 		boolean dropQueueProcessing = !queueProcessing;
703 		queueProcessing = true;
704 		IComponentEvent event = null;
705 		while(queue.size() != 0) {
706 			// yes we do -> do it!
707 			try {
708 			event = queue.poll();
709 			} catch (Exception e) {
710 				ComponentBusErrorException e1 = new ComponentBusErrorException("Can't poll next event.", e, this);
711 				innerRaiseEvent_Safe(
712 					new ComponentBusErrorEvent(this, e)
713 				);
714 				throw e1;
715 			}
716 			try {
717 				innerRaiseEvent(event);
718 			} catch (FatalErrorPropagatingEventException e1) {
719 				throw e1;
720 			} catch (ComponentBusErrorException e2) {
721 				throw e2;
722 			} catch (Exception e3) {
723 				innerRaiseEvent_Safe(
724 					new FatalErrorPropagatingEvent<LifecycleBus>(this, "Exception happened during the event propagation.", e3, event)
725 				);
726 				queueProcessing = false;
727 				throw new FatalErrorPropagatingEventException(event, e3, this);
728 			}
729 		}
730 		if (!isRunning()) {
731 			// fatal error has happened
732 			if (log.isLoggable(Level.SEVERE)) log.severe("Stopped.");
733 			if (event != null && (!(event instanceof IFatalErrorEvent))) {
734 				// last event we have been processing was not "fatal error"
735 				throw new FatalErrorPropagatingEventException(event, this);
736 			}
737 		}
738 		// if we should drop the queue processing...
739 		if (dropQueueProcessing) {
740 			// so be it...
741 			queueProcessing = false;
742 		}
743 	}
744 	
745 	/////
746 	//////////
747 	//
748 	// LIFECYCLE MANAGEMENT - IMPLEMENTATION OF ILifecycleBus INTERFACE
749 	//
750 	//////////
751 	/////
752 	
753 	/**
754 	 * Mutex used for synchronization.
755 	 */
756 	private Object ctrlMutex = new Object();
757 	
758 	/**
759 	 * Provided dependencies of the controlled component.
760 	 */
761 	private ComponentDependencies dependencies;
762 	
763 	/**
764 	 * Map tracking the states of dependencies.
765 	 */
766 	private Map<IToken, ComponentState> dependencyState = new HashMap<IToken, ComponentState>();
767 	
768 	/**
769 	 * Map tracking count of states of dependencies.
770 	 */
771 	private Map<ComponentState, Integer> stateCount = new HashMap<ComponentState, Integer>();
772 	
773 	/**
774 	 * State of the controlled component.
775 	 * <p><p>
776 	 * Use {@link ComponentController#setState(ComponentState)} to alter the value of the flag.
777 	 */
778 	private Flag<ComponentState> componentState = new Flag<ComponentState>(ComponentState.INSTANTIATED);
779 	
780 	/**
781 	 * Stores the fatal error that triggered the system failure.
782 	 */
783 	private IFatalErrorEvent lastFatalError = null;
784 	
785 	//
786 	// COMPONENT STATE AWAIT CLASS
787 	//
788 	
789 	private static class AwaitState implements IAccept<ComponentState> {
790 		
791 		Set<ComponentState> awaiting = new HashSet<ComponentState>();
792 		
793 		public AwaitState(ComponentState... states) {
794 			for (ComponentState state : states) {
795 				awaiting.add(state);
796 			}
797 		}
798 
799 		@Override
800 		public boolean accept(ComponentState flagValue) {
801 			return awaiting.contains(flagValue);
802 		}
803 		
804 	};
805 		
806 	//
807 	// EVENT LISTENERS
808 	//
809 	
810 	private IComponentEventListener<IStartingEvent> startingListener = new IComponentEventListener<IStartingEvent>() {
811 
812 		@Override
813 		public void notify(IStartingEvent event) {
814 			setComponentState(event.getSource().getComponentId(), ComponentState.STARTING);
815 		}
816 		
817 	};
818 	
819 	private IComponentEventListener<IStartingPausedEvent> startingPausedListener = new IComponentEventListener<IStartingPausedEvent>() {
820 
821 		@Override
822 		public void notify(IStartingPausedEvent event) {
823 			setComponentState(event.getSource().getComponentId(), ComponentState.STARTING_PAUSED);
824 		}
825 		
826 	};
827 	
828 	private IComponentEventListener<IStartedEvent> startedListener = new IComponentEventListener<IStartedEvent>() {
829 
830 		@Override
831 		public void notify(IStartedEvent event) {
832 			setComponentState(event.getSource().getComponentId(), ComponentState.RUNNING);
833 		}
834 		
835 	};
836 	
837 	private IComponentEventListener<IPausingEvent> pausingListener = new IComponentEventListener<IPausingEvent>() {
838 
839 		@Override
840 		public void notify(IPausingEvent event) {
841 			setComponentState(event.getSource().getComponentId(), ComponentState.PAUSING);
842 		}
843 		
844 	};
845 	
846 	private IComponentEventListener<IPausedEvent> pausedListener = new IComponentEventListener<IPausedEvent>() {
847 
848 		@Override
849 		public void notify(IPausedEvent event) {
850 			setComponentState(event.getSource().getComponentId(), ComponentState.PAUSED);
851 		}
852 		
853 	};
854 	
855 	private IComponentEventListener<IResumingEvent> resumingListener = new IComponentEventListener<IResumingEvent>() {
856 
857 		@Override
858 		public void notify(IResumingEvent event) {
859 			setComponentState(event.getSource().getComponentId(), ComponentState.RESUMING);
860 		}
861 		
862 	};
863 	
864 	private IComponentEventListener<IResumedEvent> resumedListener = new IComponentEventListener<IResumedEvent>() {
865 
866 		@Override
867 		public void notify(IResumedEvent event) {
868 			setComponentState(event.getSource().getComponentId(), ComponentState.RUNNING);
869 		}
870 		
871 	};
872 	
873 	private IComponentEventListener<IStoppingEvent> stoppingListener = new IComponentEventListener<IStoppingEvent>() {
874 
875 		@Override
876 		public void notify(IStoppingEvent event) {
877 			setComponentState(event.getSource().getComponentId(), ComponentState.STOPPING);
878 		}
879 		
880 	};
881 	
882 	private IComponentEventListener<IStoppedEvent> stoppedListener = new IComponentEventListener<IStoppedEvent>() {
883 
884 		@Override
885 		public void notify(IStoppedEvent event) {
886 			setComponentState(event.getSource().getComponentId(), ComponentState.STOPPED);
887 		}
888 		
889 	};
890 	
891 	private IComponentEventListener<IFatalErrorEvent> fatalErrorListener = new IComponentEventListener<IFatalErrorEvent>() {
892 
893 		@Override
894 		public void notify(IFatalErrorEvent event) {
895 			setComponentStates(ComponentState.KILLED);
896 		}
897 		
898 	};
899 	
900 	private IComponentEventListener<IResetEvent> resetEventListener = new IComponentEventListener<IResetEvent>() {
901 
902 		@Override
903 		public void notify(IResetEvent event) {
904 			setComponentStates(ComponentState.RESETED);
905 		}
906 		
907 	};
908 	
909 	/**
910 	 * Contains {@link ComponentControl} with lifecycle methods of various components identified by their ID.
911 	 */
912 	private Map<IToken, ComponentController> controls = new HashMap<IToken, ComponentController>();
913 	
914 	/**
915 	 * Map holdin {@link Flag}s with the current state of the component.
916 	 */
917 	private Map<IToken, Flag<ComponentState>> componentStates = new LazyMap<IToken, Flag<ComponentState>>() {
918 
919 		@Override
920 		protected Flag<ComponentState> create(IToken key) {
921 			return new Flag<ComponentState>(ComponentState.INSTANTIATED);
922 		}
923 		
924 	};
925 
926 	private void registerComponentStateListeners() {
927 		this.addEventListener(IStartingEvent.class,       startingListener);
928 		this.addEventListener(IStartingPausedEvent.class, startingPausedListener);
929 		this.addEventListener(IStartedEvent.class,        startedListener);
930 		this.addEventListener(IStoppingEvent.class,       stoppingListener);
931 		this.addEventListener(IStoppedEvent.class,        stoppedListener);
932 		this.addEventListener(IPausingEvent.class,        pausingListener);
933 		this.addEventListener(IPausedEvent.class,         pausedListener);
934 		this.addEventListener(IResumingEvent.class,       resumingListener);
935 		this.addEventListener(IResumedEvent.class,        resumedListener);
936 	}
937 	
938 	/**
939 	 * Sets new component state for component of 'componentId'.
940 	 * @param componentId
941 	 * @param newState
942 	 */
943 	private void setComponentState(IToken componentId, ComponentState newState) {
944 		componentStates.get(componentId).setFlag(newState);
945 	}
946 	
947 	/**
948 	 * Sets all component states to 'newState'.
949 	 * @param newState
950 	 */
951 	private void setComponentStates(ComponentState newState) {
952 		for(Flag<ComponentState> state : componentStates.values()) {
953 			state.setFlag(newState);
954 		}
955 	}
956 	
957 	@Override
958 	public <T extends IComponent> IComponentController<T> addLifecycleManagement(T component, IComponentControlHelper lifecyleMethods, ComponentDependencies componentDependencies) throws ComponentLifecycleManagementAlreadyRegisteredException {
959 		synchronized(controls) {
960 			if (controls.containsKey(component.getComponentId())) throw new ComponentLifecycleManagementAlreadyRegisteredException("Lifecycle already registered at " + this + " for component " + component.getComponentId() + ".", this);
961 			ComponentController controller = new ComponentController(component, lifecyleMethods, this, getLog(), componentDependencies);
962 			controls.put(component.getComponentId(), controller);
963 			return controller;
964 		}
965 	}
966 
967 	@Override
968 	public ImmutableFlag<ComponentState> getComponentState(IToken componentId) {
969 		return componentStates.get(componentId).getImmutable();
970 	}
971 
972 	@Override
973 	public ImmutableFlag<ComponentState> getComponentState(Class<? extends IComponent> cls) throws MoreComponentsForClassException {
974 		IComponent component = getComponent(cls);
975 		if (component == null) return null;
976 		return getComponentState(component.getComponentId());
977 	}
978 
979 	@Override
980 	public void removeLifecycleManagement(IComponent component) {
981 		synchronized(controls) {
982 			controls.remove(component.getComponentId());
983 		}
984 	}
985 
986 }
987