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 }