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 }