View Javadoc

1   package cz.cuni.amis.pogamut.base.component.bus;
2   
3   import java.util.Set;
4   
5   import cz.cuni.amis.pogamut.base.component.IComponent;
6   import cz.cuni.amis.pogamut.base.component.bus.event.IFatalErrorEvent;
7   import cz.cuni.amis.pogamut.base.component.bus.event.IResetEvent;
8   import cz.cuni.amis.pogamut.base.component.bus.exception.ComponentBusErrorException;
9   import cz.cuni.amis.pogamut.base.component.bus.exception.ComponentBusNotRunningException;
10  import cz.cuni.amis.pogamut.base.component.bus.exception.ComponentIdClashException;
11  import cz.cuni.amis.pogamut.base.component.bus.exception.FatalErrorPropagatingEventException;
12  import cz.cuni.amis.pogamut.base.component.bus.exception.MoreComponentsForClassException;
13  import cz.cuni.amis.pogamut.base.component.bus.exception.ResetFailedException;
14  import cz.cuni.amis.utils.token.IToken;
15  
16  /**
17   * Component bus is meant as "event bus". Every agent will have exactly one component bus
18   * that serves as general-purpose event propagation bus.
19   * <p><p>
20   * Component bus stops its work when {@link IFatalErrorEvent} is passed to the component bus
21   * or an exception is thrown by any listener.
22   * <p><p>
23   * Every component that uses the bus should register at least one listener - listener for {@link IFatalErrorEvent} events
24   * as it is something as "global exception". Whenever the component is notified about the fatal error, it should stop its work.
25   * <p><p>
26   * Also - whenever the component catches an exception that it can't handle, it is bound to raise {@link IFatalErrorEvent} to 
27   * notify the system that it is failing. If the component is not a critical piece of the puzzle, it may raise different event.
28   * 
29   * @author Jimmy
30   */
31  public interface IComponentBus extends IComponent {
32  
33  	//
34  	//
35  	// UTILITY METHODS
36  	//
37  	//
38  	
39  	/**
40  	 * Whether the bus is propagating events.
41  	 * <p><p>
42  	 * Whenever {@link IFatalErrorEvent} is caught - the component bus will stop working immediately and propagate
43  	 * the fatal error as the last event (so if you will receive {@link IFatalErrorEvent} inside your object then it
44  	 * is pointless to send more events to the bus.
45  	 * <p><p>
46  	 * The only way to make the bus working is to reset() it.
47  	 * <p><p>
48  	 * Use this method to examine whether {@link IFatalErrorEvent} occured on the bus (and was broadcast) or not.
49  	 * 
50  	 * @return
51  	 */
52  	public boolean isRunning();
53  	
54  	/**
55  	 * Restarts the bus and the whole agent system.
56  	 * <p><p>
57  	 * Broadcasts {@link IResetEvent} event. All components should stop working upon reset event and reinitialize their inner data structures
58  	 * into the initial state. If reset is not possible, the component should throw an exception.
59  	 * <p><p>
60  	 * If exception is caught during the reset(), the {@link IFatalErrorEvent} is propagated and the component bus won't start.
61  	 * <p><p> 
62  	 * If reset() is called, when the component bus is still running, it first broadcasts {@link IFatalErrorEvent}.
63  	 * <p><p>
64  	 * Note that you can't propagate any events during the reset (they will be discarded).
65  	 * 
66  	 *  @throws ResetFailedException thrown when an exception happens during reset operation, nested exception is available through {@link Exception#getCause()}
67  	 */
68  	public void reset() throws ResetFailedException;
69  	
70  	
71  	//
72  	//
73  	// COMPONENTS
74  	//
75  	//
76  	
77  	/**
78  	 * Registers component into the bus.
79  	 * <p><p>
80  	 * If different component with the same {@link IComponent#getComponentId()} is already registered, 
81  	 * than it throws {@link ComponentIdClashException} and broadcast {@link IFatalErrorEvent}. 
82  	 * 
83  	 * @param component
84  	 * @throws ComponentIdClashException
85  	 */
86  	public void register(IComponent component) throws ComponentIdClashException;
87  	
88  	/**
89  	 * Removes component from the bus.
90  	 * 
91  	 * @param component
92  	 */
93  	public void remove(IComponent component);
94  	
95  	/**
96  	 * Returns registered component of 'componentId'.
97  	 * <p><p>
98  	 * Returns null if no such component exists.
99  	 * 
100 	 * @param componentId
101 	 * @return
102 	 */
103 	public IComponent getComponent(IToken componentId);
104 	
105 	/**
106 	 * Returns component of class 'cls', if there is more then one component for that
107 	 * class than an exception is thrown.
108 	 * <p><p>
109 	 * If no components exist for 'cls', returns empty set.
110 	 * 
111 	 * @param <T>
112 	 * @param cls
113 	 * @return
114 	 * @throws MoreComponentsForClassException
115 	 */
116 	public <T> T getComponent(Class<T> cls) throws MoreComponentsForClassException;
117 	
118 	/**
119 	 * Return all registered components that descend from / implement class 'cls'.
120 	 * 
121 	 * @param cls
122 	 * @return
123 	 */
124 	public <T> Set<T> getComponents(Class<T> cls);
125 	
126 	//
127 	//
128 	// EVENT LISTENERS
129 	// 
130 	//
131 	
132 	/**
133 	 * Attach listener to all events of class 'event'.
134 	 * 
135 	 * @param event
136 	 * @param listener
137 	 */
138 	public void addEventListener(Class<?> event, IComponentEventListener<?> listener);
139 
140 	/**
141 	 * Attach listener to all events of class 'event' that is produced by any component of class 'component'.
142 	 * 
143 	 * @param event
144 	 * @param component
145 	 * @param listener
146 	 */
147 	public void addEventListener(Class<?> event, Class<?> component, IComponentEventListener<?> listener);
148 
149 	/**
150 	 * Attach listener to all events of class 'event' that is produced by \component with name 'componentName'.
151 	 * <p><p>
152 	 * Note that every component should have unique ID in the context of component bus instance.
153 	 * <p><p>
154 	 * @param event
155 	 * @param componentName
156 	 * @param listener
157 	 */
158 	public void addEventListener(Class<?> event, IToken componentName, IComponentEventListener<?> listener);
159 	
160 	/**
161 	 * Attach listener to all events of class 'event' that is produced by the 'component'.
162 	 * <p><p>
163 	 * Note that every component should have unique ID in the context of component bus instance.
164 	 * <p><p>
165 	 * @param event
166 	 * @param component
167 	 * @param listener
168 	 */
169 	public void addEventListener(Class<?> event, IComponent component, IComponentEventListener<?> listener);
170 	
171 	/**
172 	 * Tests whether 'listener' is listening on events of class 'class'.
173 	 * @param event
174 	 * @param listener
175 	 * @return
176 	 */
177 	public boolean isListening(Class<?> event, IComponentEventListener<?> listener);
178 	
179 	/**
180 	 * Tests whether 'listener' is listening on events of class 'event' on components of class 'component'.
181 	 * 
182 	 * @param event
183 	 * @param component
184 	 * @param listener
185 	 */
186 	public boolean isListening(Class<?> event, Class<?> component, IComponentEventListener<?> listener);
187 	
188 	/**
189 	 * Tests whether 'listener' is listening on events of class 'event' on component of name 'componentName'.
190 	 * 
191 	 * @param event
192 	 * @param componentName
193 	 * @param listener
194 	 * @return
195 	 */
196 	public boolean isListening(Class<?> event, IToken componentName, IComponentEventListener<?> listener);
197 	
198 	/**
199 	 * Tests whether 'listener' is listening on events of class 'event' on the 'component'.
200 	 * 
201 	 * @param event
202 	 * @param component
203 	 * @param listener
204 	 * @return
205 	 */
206 	public boolean isListening(Class<?> event, IComponent component, IComponentEventListener<?> listener);
207 	
208 	/**
209 	 * Removes 'listener' from event 'event'.
210 	 * 
211 	 * @param event
212 	 * @param listener
213 	 */
214 	public void removeEventListener(Class<?> event, IComponentEventListener<?> listener);
215 	
216 	/**
217 	 * Removes 'listener' from event 'event' on component 'component'.
218 	 * @param event
219 	 * @param component
220 	 * @param listener
221 	 */
222 	public void removeEventListener(Class<?> event, Class<?> component, IComponentEventListener<?> listener);
223 	
224 	/**
225 	 * Removes 'listener' from event 'event' on component of name 'componentName'.
226 	 * @param event
227 	 * @param componentName
228 	 * @param listener
229 	 */
230 	public void removeEventListener(Class<?> event, IToken componentName, IComponentEventListener<?> listener);
231 	
232 	/**
233 	 * Removes 'listener' from event 'event' on the 'component'.
234 	 * @param event
235 	 * @param component
236 	 * @param listener
237 	 */
238 	public void removeEventListener(Class<?> event, IComponent component, IComponentEventListener<?> listener);
239 	
240 	//
241 	//
242 	// EVENTS PROPAGATION
243 	//
244 	//
245 	
246 	/**
247 	 * Propagates new event.
248 	 * <p><p>
249 	 * If this event is produced as an answer to other event (that is in the context of the listener call),
250 	 * than the event will be propagated after all listeners reacting to current event finishes.
251 	 * That is - the event will be postponed.
252 	 * <p><p>
253 	 * Can't be used to propagate {@link IResetEvent}. 
254 	 * 
255 	 * @param event
256 	 * @param whether the event has been processed or it has been added to the queue for the future invocation
257 	 * 
258 	 * @throws ComponentBusNotRunningException thrown when the bus is not running
259 	 * @throws ComponentBusErrorException bus exception (report to authors)
260 	 * @throws FatalErrorPropagatingEventException thrown when some listener throws an exception during the event propagation (use {@link Exception#getCause()} to get the original exception).'
261 	 * 
262 	 * @return whether the event has been propagated
263 	 */
264 	public boolean event(IComponentEvent<?> event) throws ComponentBusNotRunningException, ComponentBusErrorException, FatalErrorPropagatingEventException;
265 	
266 	/**
267 	 * Propagates new event in the context of current event (if called within the context of event).
268 	 * <p><p>
269 	 * If this method is called from in the context of some listener - then the event will be immediately propagate
270 	 * (unless some other eventTransactional() call is made). It allows you to create chain of events that create
271 	 * something like "transaction". If exception is thrown during this process, every listener will be notified about
272 	 * that and may act accordingly.
273 	 * <p><p>
274 	 * Note that if this method is not called in the context of listener then it will be postponed as if event() method 
275 	 * is called.
276 	 * <p><p>
277 	 * Can't be used to propagate {@link IResetEvent}.
278 	 * 
279 	 * @param event
280 	 * 
281  	 * @throws ComponentBusNotRunningException thrown when the bus is not running
282 	 * @throws ComponentBusErrorException whenever an exception happened during the propagation of the event (wrapped exception is accessible under {@link Exception#getCause()})
283  	 * @throws FatalErrorPropagatingEventException thrown when some listener throws an exception during the event propagation (use {@link Exception#getCause()} to get the original exception).
284 	 */
285 	public void eventTransactional(IComponentEvent<?> event) throws ComponentBusNotRunningException, ComponentBusErrorException, FatalErrorPropagatingEventException;
286 	
287 }