Event driven architecture refactored.

1. Renamed Message to Event and Event to AbstractEvent
2. Generified Event and Handler
3. Updated EventDispatcher to make unsafe configuration impossible
4. Updated UML diagram accordingly
This commit is contained in:
Oleg 2016-03-08 00:56:08 -08:00
parent 35d6a54831
commit afb897300b
13 changed files with 115 additions and 131 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 78 KiB

After

Width:  |  Height:  |  Size: 57 KiB

View File

@ -4,7 +4,7 @@
<class id="1" language="java" name="com.iluwatar.eda.model.User" project="event-driven-architecture"
file="/event-driven-architecture/src/main/java/com/iluwatar/eda/model/User.java" binary="false"
corner="BOTTOM_RIGHT">
<position height="-1" width="-1" x="937" y="618"/>
<position height="-1" width="-1" x="437" y="535"/>
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
sort-features="false" accessors="true" visibility="true">
<attributes public="true" package="true" protected="true" private="true" static="true"/>
@ -15,7 +15,7 @@
project="event-driven-architecture"
file="/event-driven-architecture/src/main/java/com/iluwatar/eda/handler/UserUpdatedEventHandler.java" binary="false"
corner="BOTTOM_RIGHT">
<position height="-1" width="-1" x="936" y="90"/>
<position height="-1" width="-1" x="763" y="379"/>
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
sort-features="false" accessors="true" visibility="true">
<attributes public="true" package="true" protected="true" private="true" static="true"/>
@ -26,17 +26,17 @@
project="event-driven-architecture"
file="/event-driven-architecture/src/main/java/com/iluwatar/eda/handler/UserCreatedEventHandler.java" binary="false"
corner="BOTTOM_RIGHT">
<position height="101" width="200" x="41" y="37"/>
<position height="-1" width="-1" x="596" y="272"/>
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
sort-features="false" accessors="true" visibility="true">
<attributes public="true" package="true" protected="true" private="true" static="true"/>
<operations public="true" package="true" protected="true" private="true" static="true"/>
</display>
</class>
<interface id="4" language="java" name="com.iluwatar.eda.framework.Message" project="event-driven-architecture"
file="/event-driven-architecture/src/main/java/com/iluwatar/eda/framework/Message.java" binary="false"
<interface id="4" language="java" name="com.iluwatar.eda.framework.Event" project="event-driven-architecture"
file="/event-driven-architecture/src/main/java/com/iluwatar/eda/framework/Event.java" binary="false"
corner="BOTTOM_RIGHT">
<position height="-1" width="-1" x="298" y="189"/>
<position height="-1" width="-1" x="188" y="121"/>
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
sort-features="false" accessors="true" visibility="true">
<attributes public="true" package="true" protected="true" private="true" static="true"/>
@ -46,7 +46,7 @@
<interface id="5" language="java" name="com.iluwatar.eda.framework.Handler" project="event-driven-architecture"
file="/event-driven-architecture/src/main/java/com/iluwatar/eda/framework/Handler.java" binary="false"
corner="BOTTOM_RIGHT">
<position height="-1" width="-1" x="532" y="89"/>
<position height="-1" width="-1" x="755" y="58"/>
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
sort-features="false" accessors="true" visibility="true">
<attributes public="true" package="true" protected="true" private="true" static="true"/>
@ -56,7 +56,7 @@
<class id="6" language="java" name="com.iluwatar.eda.framework.EventDispatcher" project="event-driven-architecture"
file="/event-driven-architecture/src/main/java/com/iluwatar/eda/framework/EventDispatcher.java" binary="false"
corner="BOTTOM_RIGHT">
<position height="-1" width="-1" x="613" y="292"/>
<position height="-1" width="-1" x="499" y="122"/>
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
sort-features="false" accessors="true" visibility="true">
<attributes public="true" package="true" protected="true" private="true" static="true"/>
@ -66,7 +66,7 @@
<class id="7" language="java" name="com.iluwatar.eda.event.UserCreatedEvent" project="event-driven-architecture"
file="/event-driven-architecture/src/main/java/com/iluwatar/eda/event/UserCreatedEvent.java" binary="false"
corner="BOTTOM_RIGHT">
<position height="-1" width="-1" x="145" y="618"/>
<position height="-1" width="-1" x="102" y="380"/>
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
sort-features="false" accessors="true" visibility="true">
<attributes public="true" package="true" protected="true" private="true" static="true"/>
@ -76,17 +76,17 @@
<class id="8" language="java" name="com.iluwatar.eda.event.UserUpdatedEvent" project="event-driven-architecture"
file="/event-driven-architecture/src/main/java/com/iluwatar/eda/event/UserUpdatedEvent.java" binary="false"
corner="BOTTOM_RIGHT">
<position height="-1" width="-1" x="769" y="455"/>
<position height="-1" width="-1" x="320" y="382"/>
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
sort-features="false" accessors="true" visibility="true">
<attributes public="true" package="true" protected="true" private="true" static="true"/>
<operations public="true" package="true" protected="true" private="true" static="true"/>
</display>
</class>
<class id="9" language="java" name="com.iluwatar.eda.event.Event" project="event-driven-architecture"
file="/event-driven-architecture/src/main/java/com/iluwatar/eda/event/Event.java" binary="false"
<class id="9" language="java" name="com.iluwatar.eda.event.AbstractEvent" project="event-driven-architecture"
file="/event-driven-architecture/src/main/java/com/iluwatar/eda/event/AbstractEvent.java" binary="false"
corner="BOTTOM_RIGHT">
<position height="-1" width="-1" x="299" y="460"/>
<position height="-1" width="-1" x="188" y="240"/>
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
sort-features="false" accessors="true" visibility="true">
<attributes public="true" package="true" protected="true" private="true" static="true"/>
@ -94,99 +94,87 @@
</display>
</class>
<dependency id="10">
<bendpoint x="869" y="253"/>
<end type="SOURCE" refId="3"/>
<end type="TARGET" refId="1"/>
</dependency>
<dependency id="11">
<end type="SOURCE" refId="2"/>
<end type="TARGET" refId="1"/>
</dependency>
<dependency id="12">
<end type="SOURCE" refId="2"/>
<end type="TARGET" refId="8"/>
</dependency>
<dependency id="11">
<bendpoint x="140" y="196"/>
<end type="SOURCE" refId="3"/>
<end type="TARGET" refId="9"/>
</dependency>
<dependency id="12">
<bendpoint x="17" y="90"/>
<bendpoint x="17" y="708"/>
<bendpoint x="939" y="703"/>
<end type="SOURCE" refId="3"/>
<end type="TARGET" refId="1"/>
</dependency>
<dependency id="13">
<bendpoint x="935" y="318"/>
<bendpoint x="936" y="417"/>
<end type="SOURCE" refId="2"/>
<end type="TARGET" refId="1"/>
</dependency>
<dependency id="14">
<bendpoint x="757" y="378"/>
<end type="SOURCE" refId="2"/>
<end type="TARGET" refId="9"/>
</dependency>
<generalization id="15">
<end type="SOURCE" refId="7"/>
<end type="TARGET" refId="9"/>
</generalization>
<association id="16">
<end type="SOURCE" refId="8" navigable="false">
<attribute id="17" name="user"/>
<multiplicity id="18" minimum="0" maximum="1"/>
</end>
<end type="TARGET" refId="1" navigable="true"/>
<display labels="true" multiplicity="true"/>
</association>
<realization id="19">
<realization id="13">
<end type="SOURCE" refId="2"/>
<end type="TARGET" refId="5"/>
</realization>
<dependency id="20">
<end type="SOURCE" refId="5"/>
<end type="TARGET" refId="9"/>
</dependency>
<dependency id="21">
<bendpoint x="301" y="114"/>
<end type="SOURCE" refId="5"/>
<end type="TARGET" refId="4"/>
</dependency>
<realization id="22">
<end type="SOURCE" refId="9"/>
<end type="TARGET" refId="4"/>
</realization>
<dependency id="23">
<end type="SOURCE" refId="6"/>
<end type="TARGET" refId="9"/>
</dependency>
<generalization id="24">
<end type="SOURCE" refId="8"/>
<generalization id="14">
<end type="SOURCE" refId="7"/>
<end type="TARGET" refId="9"/>
</generalization>
<dependency id="25">
<bendpoint x="141" y="250"/>
<realization id="15">
<end type="SOURCE" refId="3"/>
<end type="TARGET" refId="7"/>
</dependency>
<association id="26">
<end type="TARGET" refId="5"/>
</realization>
<association id="16">
<end type="SOURCE" refId="6" navigable="false">
<attribute id="27" name="handlers">
<position height="19" width="56" x="449" y="175"/>
<attribute id="17" name="handlers">
<position height="19" width="56" x="672" y="144"/>
</attribute>
<multiplicity id="28" minimum="0" maximum="2147483647">
<position height="17" width="23" x="574" y="173"/>
<multiplicity id="18" minimum="0" maximum="2147483647">
<position height="17" width="23" x="797" y="142"/>
</multiplicity>
</end>
<end type="TARGET" refId="5" navigable="true"/>
<display labels="true" multiplicity="true"/>
</association>
<association id="29">
<end type="SOURCE" refId="7" navigable="false">
<attribute id="30" name="user"/>
<multiplicity id="31" minimum="0" maximum="1"/>
<realization id="19">
<end type="SOURCE" refId="9"/>
<end type="TARGET" refId="4"/>
</realization>
<dependency id="20">
<end type="SOURCE" refId="6"/>
<end type="TARGET" refId="4"/>
</dependency>
<dependency id="21">
<bendpoint x="187" y="57"/>
<end type="SOURCE" refId="5"/>
<end type="TARGET" refId="4"/>
</dependency>
<association id="22">
<end type="SOURCE" refId="8" navigable="false">
<attribute id="23" name="user">
<position height="0" width="0" x="-500" y="-83"/>
</attribute>
<multiplicity id="24" minimum="0" maximum="1">
<position height="0" width="0" x="-500" y="-83"/>
</multiplicity>
</end>
<end type="TARGET" refId="1" navigable="true"/>
<display labels="true" multiplicity="true"/>
</association>
<realization id="32">
<generalization id="25">
<end type="SOURCE" refId="8"/>
<end type="TARGET" refId="9"/>
</generalization>
<association id="26">
<end type="SOURCE" refId="7" navigable="false">
<attribute id="27" name="user">
<position height="0" width="0" x="-500" y="-83"/>
</attribute>
<multiplicity id="28" minimum="0" maximum="1">
<position height="0" width="0" x="-500" y="-83"/>
</multiplicity>
</end>
<end type="TARGET" refId="1" navigable="true"/>
<display labels="true" multiplicity="true"/>
</association>
<dependency id="29">
<bendpoint x="308" y="303"/>
<end type="SOURCE" refId="3"/>
<end type="TARGET" refId="5"/>
</realization>
<end type="TARGET" refId="7"/>
</dependency>
<classifier-display autosize="true" stereotype="true" package="true" initial-value="true" signature="true"
sort-features="false" accessors="true" visibility="true">
<attributes public="true" package="true" protected="true" private="true" static="true"/>

View File

@ -22,9 +22,9 @@
*/
package com.iluwatar.eda;
import com.iluwatar.eda.event.Event;
import com.iluwatar.eda.event.UserCreatedEvent;
import com.iluwatar.eda.event.UserUpdatedEvent;
import com.iluwatar.eda.framework.Event;
import com.iluwatar.eda.framework.EventDispatcher;
import com.iluwatar.eda.handler.UserCreatedEventHandler;
import com.iluwatar.eda.handler.UserUpdatedEventHandler;
@ -53,12 +53,12 @@ public class App {
public static void main(String[] args) {
EventDispatcher dispatcher = new EventDispatcher();
dispatcher.registerChannel(UserCreatedEvent.class, new UserCreatedEventHandler());
dispatcher.registerChannel(UserUpdatedEvent.class, new UserUpdatedEventHandler());
dispatcher.registerHandler(UserCreatedEvent.class, new UserCreatedEventHandler());
dispatcher.registerHandler(UserUpdatedEvent.class, new UserUpdatedEventHandler());
User user = new User("iluwatar");
dispatcher.onEvent(new UserCreatedEvent(user));
dispatcher.onEvent(new UserUpdatedEvent(user));
dispatcher.dispatch(new UserCreatedEvent(user));
dispatcher.dispatch(new UserUpdatedEvent(user));
}
}

View File

@ -23,10 +23,10 @@
package com.iluwatar.eda.event;
import com.iluwatar.eda.framework.EventDispatcher;
import com.iluwatar.eda.framework.Message;
import com.iluwatar.eda.framework.Event;
/**
* The {@link Event} class serves as a base class for defining custom events happening with your
* The {@link AbstractEvent} class serves as a base class for defining custom events happening with your
* system. In this example we have two types of events defined.
* <ul>
* <li>{@link UserCreatedEvent} - used when a user is created</li>
@ -34,16 +34,16 @@ import com.iluwatar.eda.framework.Message;
* </ul>
* Events can be distinguished using the {@link #getType() getType} method.
*/
public class Event implements Message {
public abstract class AbstractEvent implements Event {
/**
* Returns the event type as a {@link Class} object
* In this example, this method is used by the {@link EventDispatcher} to
* dispatch events depending on their type.
*
* @return the Event type as a {@link Class}.
* @return the AbstractEvent type as a {@link Class}.
*/
public Class<? extends Message> getType() {
public Class<? extends Event> getType() {
return getClass();
}
}

View File

@ -29,7 +29,7 @@ import com.iluwatar.eda.model.User;
* This class can be extended to contain details about the user has been created. In this example,
* the entire {@link User} object is passed on as data with the event.
*/
public class UserCreatedEvent extends Event {
public class UserCreatedEvent extends AbstractEvent {
private User user;

View File

@ -29,7 +29,7 @@ import com.iluwatar.eda.model.User;
* This class can be extended to contain details about the user has been updated. In this example,
* the entire {@link User} object is passed on as data with the event.
*/
public class UserUpdatedEvent extends Event {
public class UserUpdatedEvent extends AbstractEvent {
private User user;

View File

@ -23,15 +23,15 @@
package com.iluwatar.eda.framework;
/**
* A {@link Message} is an object with a specific type that is associated
* A {@link Event} is an object with a specific type that is associated
* to a specific {@link Handler}.
*/
public interface Message {
public interface Event {
/**
* Returns the message type as a {@link Class} object. In this example the message type is
* used to handle events by their type.
* @return the message type as a {@link Class}.
*/
Class<? extends Message> getType();
Class<? extends Event> getType();
}

View File

@ -22,19 +22,16 @@
*/
package com.iluwatar.eda.framework;
import com.iluwatar.eda.event.Event;
import java.util.HashMap;
import java.util.Map;
/**
* Handles the routing of {@link Event} messages to associated handlers.
* A {@link HashMap} is used to store the association between events and their respective handlers.
*
*/
public class EventDispatcher {
private Map<Class<? extends Event>, Handler<?>> handlers;
private Map<Class<? extends Event>, Handler<? extends Event>> handlers;
public EventDispatcher() {
handlers = new HashMap<>();
@ -46,8 +43,8 @@ public class EventDispatcher {
* @param eventType The {@link Event} to be registered
* @param handler The {@link Handler} that will be handling the {@link Event}
*/
public void registerChannel(Class<? extends Event> eventType,
Handler<?> handler) {
public <E extends Event> void registerHandler(Class<E> eventType,
Handler<E> handler) {
handlers.put(eventType, handler);
}
@ -56,8 +53,12 @@ public class EventDispatcher {
*
* @param event The {@link Event} to be dispatched
*/
public void onEvent(Event event) {
handlers.get(event.getClass()).onEvent(event);
@SuppressWarnings("unchecked")
public <E extends Event> void dispatch(E event) {
Handler<E> handler = (Handler<E>) handlers.get(event.getClass());
if (handler != null) {
handler.onEvent(event);
}
}
}

View File

@ -22,13 +22,11 @@
*/
package com.iluwatar.eda.framework;
import com.iluwatar.eda.event.Event;
/**
* This interface can be implemented to handle different types of messages.
* Every handler is responsible for a single of type message
*/
public interface Handler<E extends Message> {
public interface Handler<E extends Event> {
/**
* The onEvent method should implement and handle behavior related to the event.
@ -36,5 +34,5 @@ public interface Handler<E extends Message> {
* a queue to be consumed by other sub systems.
* @param event the {@link Event} object to be handled.
*/
void onEvent(Event event);
void onEvent(E event);
}

View File

@ -22,7 +22,6 @@
*/
package com.iluwatar.eda.handler;
import com.iluwatar.eda.event.Event;
import com.iluwatar.eda.event.UserCreatedEvent;
import com.iluwatar.eda.framework.Handler;
@ -32,9 +31,10 @@ import com.iluwatar.eda.framework.Handler;
public class UserCreatedEventHandler implements Handler<UserCreatedEvent> {
@Override
public void onEvent(Event message) {
public void onEvent(UserCreatedEvent event) {
UserCreatedEvent userCreatedEvent = (UserCreatedEvent) message;
System.out.printf("User with %s has been Created!", userCreatedEvent.getUser().getUsername());
System.out.println(String.format(
"User '%s' has been Created!", event.getUser().getUsername()));
}
}

View File

@ -22,7 +22,6 @@
*/
package com.iluwatar.eda.handler;
import com.iluwatar.eda.event.Event;
import com.iluwatar.eda.event.UserUpdatedEvent;
import com.iluwatar.eda.framework.Handler;
@ -32,9 +31,9 @@ import com.iluwatar.eda.framework.Handler;
public class UserUpdatedEventHandler implements Handler<UserUpdatedEvent> {
@Override
public void onEvent(Event message) {
public void onEvent(UserUpdatedEvent event) {
UserUpdatedEvent userUpdatedEvent = (UserUpdatedEvent) message;
System.out.printf("User with %s has been Updated!", userUpdatedEvent.getUser().getUsername());
System.out.println(String.format(
"User '%s' has been Updated!", event.getUser().getUsername()));
}
}

View File

@ -29,13 +29,13 @@ import org.junit.Test;
import static org.junit.Assert.assertEquals;
/**
* {@link UserCreatedEventTest} tests and verifies {@link Event} behaviour.
* {@link UserCreatedEventTest} tests and verifies {@link AbstractEvent} behaviour.
*/
public class UserCreatedEventTest {
/**
* This unit test should correctly return the {@link Event} class type when calling the
* {@link Event#getType() getType} method.
* This unit test should correctly return the {@link AbstractEvent} class type when calling the
* {@link AbstractEvent#getType() getType} method.
*/
@Test
public void testGetEventType() {

View File

@ -22,7 +22,6 @@
*/
package com.iluwatar.eda.framework;
import com.iluwatar.eda.framework.EventDispatcher;
import com.iluwatar.eda.event.UserCreatedEvent;
import com.iluwatar.eda.event.UserUpdatedEvent;
import com.iluwatar.eda.handler.UserCreatedEventHandler;
@ -49,8 +48,8 @@ public class EventDispatcherTest {
EventDispatcher dispatcher = spy(new EventDispatcher());
UserCreatedEventHandler userCreatedEventHandler = spy(new UserCreatedEventHandler());
UserUpdatedEventHandler userUpdatedEventHandler = spy(new UserUpdatedEventHandler());
dispatcher.registerChannel(UserCreatedEvent.class, userCreatedEventHandler);
dispatcher.registerChannel(UserUpdatedEvent.class, userUpdatedEventHandler);
dispatcher.registerHandler(UserCreatedEvent.class, userCreatedEventHandler);
dispatcher.registerHandler(UserUpdatedEvent.class, userUpdatedEventHandler);
User user = new User("iluwatar");
@ -58,15 +57,14 @@ public class EventDispatcherTest {
UserUpdatedEvent userUpdatedEvent = new UserUpdatedEvent(user);
//fire a userCreatedEvent and verify that userCreatedEventHandler has been invoked.
dispatcher.onEvent(userCreatedEvent);
dispatcher.dispatch(userCreatedEvent);
verify(userCreatedEventHandler).onEvent(userCreatedEvent);
verify(dispatcher).onEvent(userCreatedEvent);
verify(dispatcher).dispatch(userCreatedEvent);
//fire a userCreatedEvent and verify that userUpdatedEventHandler has been invoked.
dispatcher.onEvent(userUpdatedEvent);
dispatcher.dispatch(userUpdatedEvent);
verify(userUpdatedEventHandler).onEvent(userUpdatedEvent);
verify(dispatcher).onEvent(userUpdatedEvent);
verify(dispatcher).dispatch(userUpdatedEvent);
}
}