Add DeadEvent #9
@ -0,0 +1,32 @@
|
||||
package dev.kske.eventbus.core;
|
||||
|
||||
/**
|
||||
* Wraps an event that was dispatched but for which no handler has been bound.
|
||||
* <p>
|
||||
* Handling dead events is useful as it can identify a poorly configured event distribution.
|
||||
*
|
||||
* @author Kai S. K. Engelbart
|
||||
* @since 1.1.0
|
||||
*/
|
||||
public final class DeadEvent {
|
||||
|
||||
private final EventBus eventBus;
|
||||
private final Object event;
|
||||
|
||||
DeadEvent(EventBus eventBus, Object event) {
|
||||
this.eventBus = eventBus;
|
||||
this.event = event;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the event bus that originated this event
|
||||
* @since 1.1.0
|
||||
*/
|
||||
public EventBus getEventBus() { return eventBus; }
|
||||
|
||||
/**
|
||||
delvh marked this conversation as resolved
Outdated
|
||||
* @return the event that could not be delivered
|
||||
* @since 1.1.0
|
||||
*/
|
||||
public Object getEvent() { return event; }
|
||||
}
|
@ -73,13 +73,18 @@ public final class EventBus {
|
||||
var state = dispatchState.get();
|
||||
state.isDispatching = true;
|
||||
|
||||
for (var handler : getHandlersFor(event.getClass()))
|
||||
Iterator<EventHandler> handlers = getHandlersFor(event.getClass());
|
||||
if (handlers.hasNext()) {
|
||||
kske marked this conversation as resolved
delvh
commented
that if should be useless as the
loop also checks in the first iteration,
loop. that **if** should be useless as the
```java
while() {}
```
loop also checks in the first iteration,
which is exactly the difference to the
```java
do{}while()
```
loop.
kske
commented
I need the I need the `else (if)` case here as well, but unfortunately this is not Python.
|
||||
while (handlers.hasNext())
|
||||
if (state.isCancelled) {
|
||||
logger.log(Level.INFO, "Cancelled dispatching event {0}", event);
|
||||
state.isCancelled = false;
|
||||
break;
|
||||
} else {
|
||||
handler.execute(event);
|
||||
handlers.next().execute(event);
|
||||
}
|
||||
} else if (!(event instanceof DeadEvent)) {
|
||||
kske marked this conversation as resolved
delvh
commented
this would be a little bit different then. this would be a little bit different then.
kske
commented
That's why I use the if statement. I could use a boolean flag instead, but the iterator logic should be more efficient and arguably more readable here. That's why I use the if statement. I could use a boolean flag instead, but the iterator logic should be more efficient and arguably more readable here.
|
||||
dispatch(new DeadEvent(this, event));
|
||||
}
|
||||
|
||||
// Reset dispatch state
|
||||
@ -89,25 +94,26 @@ public final class EventBus {
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches for the event handlers bound to an event class.
|
||||
* Searches for the event handlers bound to an event class. This includes polymorphic handlers
|
||||
* that are bound to a supertype of the event class.
|
||||
*
|
||||
* @param eventClass the event class to use for the search
|
||||
* @return all event handlers registered for the event class
|
||||
* @return an iterator over the applicable handlers in descending order of priority
|
||||
* @since 0.0.1
|
||||
*/
|
||||
private List<EventHandler> getHandlersFor(Class<?> eventClass) {
|
||||
private Iterator<EventHandler> getHandlersFor(Class<?> eventClass) {
|
||||
|
||||
// Get handlers defined for the event class
|
||||
Set<EventHandler> handlers = bindings.getOrDefault(eventClass, new TreeSet<>());
|
||||
TreeSet<EventHandler> handlers = bindings.getOrDefault(eventClass, new TreeSet<>());
|
||||
|
||||
// Get subtype handlers
|
||||
// Get polymorphic handlers
|
||||
for (var binding : bindings.entrySet())
|
||||
if (binding.getKey().isAssignableFrom(eventClass))
|
||||
for (var handler : binding.getValue())
|
||||
if (handler.isPolymorphic())
|
||||
delvh marked this conversation as resolved
delvh
commented
Why do you need that now? Why do you need that now?
kske
commented
I don't, but why unnecessarily obfuscate the type? The fact that this is a tree set is important here as it guarantees the event handler order, so the variable type might as well reflect this. I don't, but why unnecessarily obfuscate the type? The fact that this is a tree set is important here as it guarantees the event handler order, so the variable type might as well reflect this.
|
||||
handlers.add(handler);
|
||||
|
||||
return new ArrayList<>(handlers);
|
||||
return handlers.iterator();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -68,7 +68,7 @@ final class EventHandler implements Comparable<EventHandler> {
|
||||
* Compares this to another event handler based on priority. In case of equal priority a
|
||||
* non-zero value based on hash codes is returned.
|
||||
* <p>
|
||||
* This is used to retrieve event handlers in order of descending priority from a tree set.
|
||||
* This is used to retrieve event handlers in descending order of priority from a tree set.
|
||||
*
|
||||
* @since 0.0.1
|
||||
*/
|
||||
|
@ -0,0 +1,37 @@
|
||||
package dev.kske.eventbus.core;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
import org.junit.jupiter.api.*;
|
||||
|
||||
/**
|
||||
* Tests the dispatching of a dead event if an event could not be delivered.
|
||||
*
|
||||
* @author Kai S. K. Engelbart
|
||||
* @since 1.1.0
|
||||
*/
|
||||
class DeadTest {
|
||||
|
||||
EventBus bus;
|
||||
String event = "This event has no handler";
|
||||
boolean deadEventHandled;
|
||||
|
||||
@BeforeEach
|
||||
void registerListener() {
|
||||
bus = new EventBus();
|
||||
bus.registerListener(this);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testDeadEvent() {
|
||||
bus.dispatch(event);
|
||||
assertTrue(deadEventHandled);
|
||||
}
|
||||
|
||||
@Event
|
||||
void onDeadEvent(DeadEvent deadEvent) {
|
||||
assertEquals(bus, deadEvent.getEventBus());
|
||||
assertEquals(event, deadEvent.getEvent());
|
||||
deadEventHandled = true;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user
I have ammended my original commit.