Resolves checkstyle errors for event-* (#1070)

* Reduces checkstyle errors in event-aggregator

* Reduces checkstyle errors in event-asynchronous

* Reduces checkstyle errors in event-driven-architecture

* Reduces checkstyle errors in event-queue

* Reduces checkstyle errors in event-sourcing
This commit is contained in:
Anurag Agarwal 2019-11-10 23:07:10 +05:30 committed by Ilkka Seppälä
parent 7c888e8886
commit 5ae2ce6e2e
38 changed files with 208 additions and 229 deletions

View File

@ -27,24 +27,22 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
/** /**
*
* A system with lots of objects can lead to complexities when a client wants to subscribe to * A system with lots of objects can lead to complexities when a client wants to subscribe to
* events. The client has to find and register for each object individually, if each object has * events. The client has to find and register for each object individually, if each object has
* multiple events then each event requires a separate subscription. * multiple events then each event requires a separate subscription.
* <p>
* An Event Aggregator acts as a single source of events for many objects. It registers for all the
* events of the many objects allowing clients to register with just the aggregator.
* <p>
* In the example {@link LordBaelish}, {@link LordVarys} and {@link Scout} deliver events to
* {@link KingsHand}. {@link KingsHand}, the event aggregator, then delivers the events to
* {@link KingJoffrey}.
* *
* <p>An Event Aggregator acts as a single source of events for many objects. It registers for all
* the events of the many objects allowing clients to register with just the aggregator.
*
* <p>In the example {@link LordBaelish}, {@link LordVarys} and {@link Scout} deliver events to
* {@link KingsHand}. {@link KingsHand}, the event aggregator, then delivers the events to {@link
* KingJoffrey}.
*/ */
public class App { public class App {
/** /**
* Program entry point * Program entry point.
* *
* @param args command line args * @param args command line args
*/ */
public static void main(String[] args) { public static void main(String[] args) {

View File

@ -24,9 +24,7 @@
package com.iluwatar.event.aggregator; package com.iluwatar.event.aggregator;
/** /**
*
* Event enumeration. * Event enumeration.
*
*/ */
public enum Event { public enum Event {

View File

@ -27,9 +27,7 @@ import java.util.LinkedList;
import java.util.List; import java.util.List;
/** /**
*
* EventEmitter is the base class for event producers that can be observed. * EventEmitter is the base class for event producers that can be observed.
*
*/ */
public abstract class EventEmitter { public abstract class EventEmitter {

View File

@ -24,9 +24,7 @@
package com.iluwatar.event.aggregator; package com.iluwatar.event.aggregator;
/** /**
*
* Observers of events implement this interface. * Observers of events implement this interface.
*
*/ */
public interface EventObserver { public interface EventObserver {

View File

@ -27,9 +27,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
/** /**
*
* KingJoffrey observes events from {@link KingsHand}. * KingJoffrey observes events from {@link KingsHand}.
*
*/ */
public class KingJoffrey implements EventObserver { public class KingJoffrey implements EventObserver {

View File

@ -24,9 +24,7 @@
package com.iluwatar.event.aggregator; package com.iluwatar.event.aggregator;
/** /**
*
* KingsHand observes events from multiple sources and delivers them to listeners. * KingsHand observes events from multiple sources and delivers them to listeners.
*
*/ */
public class KingsHand extends EventEmitter implements EventObserver { public class KingsHand extends EventEmitter implements EventObserver {

View File

@ -24,9 +24,7 @@
package com.iluwatar.event.aggregator; package com.iluwatar.event.aggregator;
/** /**
*
* LordBaelish produces events. * LordBaelish produces events.
*
*/ */
public class LordBaelish extends EventEmitter { public class LordBaelish extends EventEmitter {

View File

@ -24,9 +24,7 @@
package com.iluwatar.event.aggregator; package com.iluwatar.event.aggregator;
/** /**
*
* LordVarys produces events. * LordVarys produces events.
*
*/ */
public class LordVarys extends EventEmitter { public class LordVarys extends EventEmitter {

View File

@ -24,9 +24,7 @@
package com.iluwatar.event.aggregator; package com.iluwatar.event.aggregator;
/** /**
*
* Scout produces events. * Scout produces events.
*
*/ */
public class Scout extends EventEmitter { public class Scout extends EventEmitter {

View File

@ -24,9 +24,7 @@
package com.iluwatar.event.aggregator; package com.iluwatar.event.aggregator;
/** /**
* * Weekday enumeration.
* Weekday enumeration
*
*/ */
public enum Weekday { public enum Weekday {

View File

@ -23,38 +23,38 @@
package com.iluwatar.event.asynchronous; package com.iluwatar.event.asynchronous;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.util.Properties; import java.util.Properties;
import java.util.Scanner; import java.util.Scanner;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/** /**
* This application demonstrates the <b>Event-based Asynchronous</b> pattern. Essentially, users (of
* the pattern) may choose to run events in an Asynchronous or Synchronous mode. There can be
* multiple Asynchronous events running at once but only one Synchronous event can run at a time.
* Asynchronous events are synonymous to multi-threads. The key point here is that the threads run
* in the background and the user is free to carry on with other processes. Once an event is
* complete, the appropriate listener/callback method will be called. The listener then proceeds to
* carry out further processing depending on the needs of the user.
* *
* This application demonstrates the <b>Event-based Asynchronous</b> pattern. Essentially, users (of the pattern) may * <p>The {@link EventManager} manages the events/threads that the user creates. Currently, the
* choose to run events in an Asynchronous or Synchronous mode. There can be multiple Asynchronous events running at * supported event operations are: <code>start</code>, <code>stop</code>, <code>getStatus</code>.
* once but only one Synchronous event can run at a time. Asynchronous events are synonymous to multi-threads. The key * For Synchronous events, the user is unable to start another (Synchronous) event if one is already
* point here is that the threads run in the background and the user is free to carry on with other processes. Once an * running at the time. The running event would have to either be stopped or completed before a new
* event is complete, the appropriate listener/callback method will be called. The listener then proceeds to carry out * event can be started.
* further processing depending on the needs of the user.
* *
* The {@link EventManager} manages the events/threads that the user creates. Currently, the supported event operations * <p>The Event-based Asynchronous Pattern makes available the advantages of multithreaded
* are: <code>start</code>, <code>stop</code>, <code>getStatus</code>. For Synchronous events, the user is unable to * applications while hiding many of the complex issues inherent in multithreaded design. Using a
* start another (Synchronous) event if one is already running at the time. The running event would have to either be * class that supports this pattern can allow you to:- (1) Perform time-consuming tasks, such as
* stopped or completed before a new event can be started. * downloads and database operations, "in the background," without interrupting your application.
* * (2) Execute multiple operations simultaneously, receiving notifications when each completes. (3)
* The Event-based Asynchronous Pattern makes available the advantages of multithreaded applications while hiding many * Wait for resources to become available without stopping ("hanging") your application. (4)
* of the complex issues inherent in multithreaded design. Using a class that supports this pattern can allow you to:- * Communicate with pending asynchronous operations using the familiar events-and-delegates model.
* (1) Perform time-consuming tasks, such as downloads and database operations, "in the background," without
* interrupting your application. (2) Execute multiple operations simultaneously, receiving notifications when each
* completes. (3) Wait for resources to become available without stopping ("hanging") your application. (4) Communicate
* with pending asynchronous operations using the familiar events-and-delegates model.
* *
* @see EventManager * @see EventManager
* @see Event * @see Event
*
*/ */
public class App { public class App {
@ -67,8 +67,7 @@ public class App {
/** /**
* Program entry point. * Program entry point.
* *
* @param args * @param args command line args
* command line args
*/ */
public static void main(String[] args) { public static void main(String[] args) {
App app = new App(); App app = new App();
@ -78,8 +77,9 @@ public class App {
} }
/** /**
* App can run in interactive mode or not. Interactive mode == Allow user interaction with command line. * App can run in interactive mode or not. Interactive mode == Allow user interaction with command
* Non-interactive is a quick sequential run through the available {@link EventManager} operations. * line. Non-interactive is a quick sequential run through the available {@link EventManager}
* operations.
*/ */
public void setUp() { public void setUp() {
Properties prop = new Properties(); Properties prop = new Properties();
@ -118,24 +118,24 @@ public class App {
try { try {
// Create an Asynchronous event. // Create an Asynchronous event.
int aEventId = eventManager.createAsync(60); int asyncEventId = eventManager.createAsync(60);
LOGGER.info("Async Event [{}] has been created.", aEventId); LOGGER.info("Async Event [{}] has been created.", asyncEventId);
eventManager.start(aEventId); eventManager.start(asyncEventId);
LOGGER.info("Async Event [{}] has been started.", aEventId); LOGGER.info("Async Event [{}] has been started.", asyncEventId);
// Create a Synchronous event. // Create a Synchronous event.
int sEventId = eventManager.create(60); int syncEventId = eventManager.create(60);
LOGGER.info("Sync Event [{}] has been created.", sEventId); LOGGER.info("Sync Event [{}] has been created.", syncEventId);
eventManager.start(sEventId); eventManager.start(syncEventId);
LOGGER.info("Sync Event [{}] has been started.", sEventId); LOGGER.info("Sync Event [{}] has been started.", syncEventId);
eventManager.status(aEventId); eventManager.status(asyncEventId);
eventManager.status(sEventId); eventManager.status(syncEventId);
eventManager.cancel(aEventId); eventManager.cancel(asyncEventId);
LOGGER.info("Async Event [{}] has been stopped.", aEventId); LOGGER.info("Async Event [{}] has been stopped.", asyncEventId);
eventManager.cancel(sEventId); eventManager.cancel(syncEventId);
LOGGER.info("Sync Event [{}] has been stopped.", sEventId); LOGGER.info("Sync Event [{}] has been stopped.", syncEventId);
} catch (MaxNumOfEventsAllowedException | LongRunningEventException | EventDoesNotExistException } catch (MaxNumOfEventsAllowedException | LongRunningEventException | EventDoesNotExistException
| InvalidOperationException e) { | InvalidOperationException e) {
@ -211,7 +211,8 @@ public class App {
int eventId = eventManager.createAsync(eventTime); int eventId = eventManager.createAsync(eventTime);
eventManager.start(eventId); eventManager.start(eventId);
LOGGER.info("Egg [{}] is being boiled.", eventId); LOGGER.info("Egg [{}] is being boiled.", eventId);
} catch (MaxNumOfEventsAllowedException | LongRunningEventException | EventDoesNotExistException e) { } catch (MaxNumOfEventsAllowedException | LongRunningEventException
| EventDoesNotExistException e) {
LOGGER.error(e.getMessage()); LOGGER.error(e.getMessage());
} }
} else if (eventType.equalsIgnoreCase("S")) { } else if (eventType.equalsIgnoreCase("S")) {
@ -219,8 +220,8 @@ public class App {
int eventId = eventManager.create(eventTime); int eventId = eventManager.create(eventTime);
eventManager.start(eventId); eventManager.start(eventId);
LOGGER.info("Egg [{}] is being boiled.", eventId); LOGGER.info("Egg [{}] is being boiled.", eventId);
} catch (MaxNumOfEventsAllowedException | InvalidOperationException | LongRunningEventException } catch (MaxNumOfEventsAllowedException | InvalidOperationException
| EventDoesNotExistException e) { | LongRunningEventException | EventDoesNotExistException e) {
LOGGER.error(e.getMessage()); LOGGER.error(e.getMessage());
} }
} else { } else {

View File

@ -27,9 +27,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
/** /**
*
* Each Event runs as a separate/individual thread. * Each Event runs as a separate/individual thread.
*
*/ */
public class Event implements IEvent, Runnable { public class Event implements IEvent, Runnable {
@ -43,9 +41,10 @@ public class Event implements IEvent, Runnable {
private ThreadCompleteListener eventListener; private ThreadCompleteListener eventListener;
/** /**
* Constructor.
* *
* @param eventId event ID * @param eventId event ID
* @param eventTime event time * @param eventTime event time
* @param isSynchronous is of synchronous type * @param isSynchronous is of synchronous type
*/ */
public Event(final int eventId, final int eventTime, final boolean isSynchronous) { public Event(final int eventId, final int eventTime, final boolean isSynchronous) {

View File

@ -24,7 +24,7 @@
package com.iluwatar.event.asynchronous; package com.iluwatar.event.asynchronous;
/** /**
* Custom Exception Class for Non Existent Event * Custom Exception Class for Non Existent Event.
*/ */
public class EventDoesNotExistException extends Exception { public class EventDoesNotExistException extends Exception {

View File

@ -29,29 +29,28 @@ import java.util.Random;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
/** /**
* * EventManager handles and maintains a pool of event threads. {@link Event} threads are created
* EventManager handles and maintains a pool of event threads. {@link Event} threads are created upon user request. Thre * upon user request. Thre are two types of events; Asynchronous and Synchronous. There can be
* are two types of events; Asynchronous and Synchronous. There can be multiple Asynchronous events running at once but * multiple Asynchronous events running at once but only one Synchronous event running at a time.
* only one Synchronous event running at a time. Currently supported event operations are: start, stop, and getStatus. * Currently supported event operations are: start, stop, and getStatus. Once an event is complete,
* Once an event is complete, it then notifies EventManager through a listener. The EventManager then takes the event * it then notifies EventManager through a listener. The EventManager then takes the event out of
* out of the pool. * the pool.
*
*/ */
public class EventManager implements ThreadCompleteListener { public class EventManager implements ThreadCompleteListener {
public static final int MAX_RUNNING_EVENTS = 1000; // Just don't wanna have too many running events. :) public static final int MAX_RUNNING_EVENTS = 1000;
// Just don't wanna have too many running events. :)
public static final int MIN_ID = 1; public static final int MIN_ID = 1;
public static final int MAX_ID = MAX_RUNNING_EVENTS; public static final int MAX_ID = MAX_RUNNING_EVENTS;
public static final int MAX_EVENT_TIME = 1800; // in seconds / 30 minutes. public static final int MAX_EVENT_TIME = 1800; // in seconds / 30 minutes.
private int currentlyRunningSyncEvent = -1; private int currentlyRunningSyncEvent = -1;
private Random rand; private Random rand;
private Map<Integer, Event> eventPool; private Map<Integer, Event> eventPool;
private static final String DOES_NOT_EXIST = " does not exist."; private static final String DOES_NOT_EXIST = " does not exist.";
/** /**
* EventManager constructor. * EventManager constructor.
*
*/ */
public EventManager() { public EventManager() {
rand = new Random(1); rand = new Random(1);
@ -65,14 +64,15 @@ public class EventManager implements ThreadCompleteListener {
* @param eventTime Time an event should run for. * @param eventTime Time an event should run for.
* @return eventId * @return eventId
* @throws MaxNumOfEventsAllowedException When too many events are running at a time. * @throws MaxNumOfEventsAllowedException When too many events are running at a time.
* @throws InvalidOperationException No new synchronous events can be created when one is already running. * @throws InvalidOperationException No new synchronous events can be created when one is
* @throws LongRunningEventException Long running events are not allowed in the app. * already running.
* @throws LongRunningEventException Long running events are not allowed in the app.
*/ */
public int create(int eventTime) public int create(int eventTime)
throws MaxNumOfEventsAllowedException, InvalidOperationException, LongRunningEventException { throws MaxNumOfEventsAllowedException, InvalidOperationException, LongRunningEventException {
if (currentlyRunningSyncEvent != -1) { if (currentlyRunningSyncEvent != -1) {
throw new InvalidOperationException( throw new InvalidOperationException("Event [" + currentlyRunningSyncEvent + "] is still"
"Event [" + currentlyRunningSyncEvent + "] is still running. Please wait until it finishes and try again."); + " running. Please wait until it finishes and try again.");
} }
int eventId = createEvent(eventTime, true); int eventId = createEvent(eventTime, true);
@ -87,16 +87,18 @@ public class EventManager implements ThreadCompleteListener {
* @param eventTime Time an event should run for. * @param eventTime Time an event should run for.
* @return eventId * @return eventId
* @throws MaxNumOfEventsAllowedException When too many events are running at a time. * @throws MaxNumOfEventsAllowedException When too many events are running at a time.
* @throws LongRunningEventException Long running events are not allowed in the app. * @throws LongRunningEventException Long running events are not allowed in the app.
*/ */
public int createAsync(int eventTime) throws MaxNumOfEventsAllowedException, LongRunningEventException { public int createAsync(int eventTime) throws MaxNumOfEventsAllowedException,
LongRunningEventException {
return createEvent(eventTime, false); return createEvent(eventTime, false);
} }
private int createEvent(int eventTime, boolean isSynchronous) private int createEvent(int eventTime, boolean isSynchronous)
throws MaxNumOfEventsAllowedException, LongRunningEventException { throws MaxNumOfEventsAllowedException, LongRunningEventException {
if (eventPool.size() == MAX_RUNNING_EVENTS) { if (eventPool.size() == MAX_RUNNING_EVENTS) {
throw new MaxNumOfEventsAllowedException("Too many events are running at the moment. Please try again later."); throw new MaxNumOfEventsAllowedException("Too many events are running at the moment."
+ " Please try again later.");
} }
if (eventTime >= MAX_EVENT_TIME) { if (eventTime >= MAX_EVENT_TIME) {
@ -185,7 +187,8 @@ public class EventManager implements ThreadCompleteListener {
} }
/** /**
* Returns a pseudo-random number between min and max, inclusive. The difference between min and max can be at most * Returns a pseudo-random number between min and max, inclusive. The difference between min and
* max can be at most
* <code>Integer.MAX_VALUE - 1</code>. * <code>Integer.MAX_VALUE - 1</code>.
*/ */
private int generateId() { private int generateId() {

View File

@ -24,8 +24,7 @@
package com.iluwatar.event.asynchronous; package com.iluwatar.event.asynchronous;
/** /**
* Events that fulfill the start stop and list out current status behaviour * Events that fulfill the start stop and list out current status behaviour follow this interface.
* follow this interface
*/ */
public interface IEvent { public interface IEvent {

View File

@ -24,7 +24,7 @@
package com.iluwatar.event.asynchronous; package com.iluwatar.event.asynchronous;
/** /**
* Type of Exception raised when the Operation being invoked is Invalid * Type of Exception raised when the Operation being invoked is Invalid.
*/ */
public class InvalidOperationException extends Exception { public class InvalidOperationException extends Exception {

View File

@ -24,7 +24,7 @@
package com.iluwatar.event.asynchronous; package com.iluwatar.event.asynchronous;
/** /**
* Type of Exception raised when the Operation being invoked is Long Running * Type of Exception raised when the Operation being invoked is Long Running.
*/ */
public class LongRunningEventException extends Exception { public class LongRunningEventException extends Exception {

View File

@ -24,7 +24,7 @@
package com.iluwatar.event.asynchronous; package com.iluwatar.event.asynchronous;
/** /**
* Type of Exception raised when the max number of allowed events is exceeded * Type of Exception raised when the max number of allowed events is exceeded.
*/ */
public class MaxNumOfEventsAllowedException extends Exception { public class MaxNumOfEventsAllowedException extends Exception {

View File

@ -34,11 +34,11 @@ import com.iluwatar.eda.model.User;
/** /**
* An event-driven architecture (EDA) is a framework that orchestrates behavior around the * An event-driven architecture (EDA) is a framework that orchestrates behavior around the
* production, detection and consumption of events as well as the responses they evoke. An event is * production, detection and consumption of events as well as the responses they evoke. An event is
* any identifiable occurrence that has significance for system hardware or software. <p> The * any identifiable occurrence that has significance for system hardware or software.
* example below uses an {@link EventDispatcher} to link/register {@link Event} objects to their
* respective handlers once an {@link Event} is dispatched, it's respective handler is invoked and
* the {@link Event} is handled accordingly.
* *
* <p>The example below uses an {@link EventDispatcher} to link/register {@link Event} objects to
* their respective handlers once an {@link Event} is dispatched, it's respective handler is invoked
* and the {@link Event} is handled accordingly.
*/ */
public class App { public class App {
@ -47,9 +47,8 @@ public class App {
* made known to the dispatcher by registering them. In this case the {@link UserCreatedEvent} is * made known to the dispatcher by registering them. In this case the {@link UserCreatedEvent} is
* bound to the UserCreatedEventHandler, whilst the {@link UserUpdatedEvent} is bound to the * bound to the UserCreatedEventHandler, whilst the {@link UserUpdatedEvent} is bound to the
* {@link UserUpdatedEventHandler}. The dispatcher can now be called to dispatch specific events. * {@link UserUpdatedEventHandler}. The dispatcher can now be called to dispatch specific events.
* When a user is saved, the {@link UserCreatedEvent} can be dispatched. * When a user is saved, the {@link UserCreatedEvent} can be dispatched. On the other hand, when a
* On the other hand, when a user is updated, {@link UserUpdatedEvent} can be dispatched. * user is updated, {@link UserUpdatedEvent} can be dispatched.
*
*/ */
public static void main(String[] args) { public static void main(String[] args) {

View File

@ -23,12 +23,12 @@
package com.iluwatar.eda.event; package com.iluwatar.eda.event;
import com.iluwatar.eda.framework.EventDispatcher;
import com.iluwatar.eda.framework.Event; import com.iluwatar.eda.framework.Event;
import com.iluwatar.eda.framework.EventDispatcher;
/** /**
* The {@link AbstractEvent} 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
* system. In this example we have two types of events defined. * your system. In this example we have two types of events defined.
* <ul> * <ul>
* <li>{@link UserCreatedEvent} - used when a user is created</li> * <li>{@link UserCreatedEvent} - used when a user is created</li>
* <li>{@link UserUpdatedEvent} - used when a user is updated</li> * <li>{@link UserUpdatedEvent} - used when a user is updated</li>
@ -38,9 +38,8 @@ import com.iluwatar.eda.framework.Event;
public abstract class AbstractEvent implements Event { public abstract class AbstractEvent implements Event {
/** /**
* Returns the event type as a {@link Class} object * Returns the event type as a {@link Class} object In this example, this method is used by the
* In this example, this method is used by the {@link EventDispatcher} to * {@link EventDispatcher} to dispatch events depending on their type.
* dispatch events depending on their type.
* *
* @return the AbstractEvent type as a {@link Class}. * @return the AbstractEvent type as a {@link Class}.
*/ */

View File

@ -26,9 +26,9 @@ package com.iluwatar.eda.event;
import com.iluwatar.eda.model.User; import com.iluwatar.eda.model.User;
/** /**
* The {@link UserCreatedEvent} should should be dispatched whenever a user has been created. * The {@link UserCreatedEvent} should should be dispatched whenever a user has been created. This
* This class can be extended to contain details about the user has been created. In this example, * class can be extended to contain details about the user has been created. In this example, the
* the entire {@link User} object is passed on as data with the event. * entire {@link User} object is passed on as data with the event.
*/ */
public class UserCreatedEvent extends AbstractEvent { public class UserCreatedEvent extends AbstractEvent {

View File

@ -26,9 +26,9 @@ package com.iluwatar.eda.event;
import com.iluwatar.eda.model.User; import com.iluwatar.eda.model.User;
/** /**
* The {@link UserUpdatedEvent} should should be dispatched whenever a user has been updated. * The {@link UserUpdatedEvent} should should be dispatched whenever a user has been updated. This
* This class can be extended to contain details about the user has been updated. In this example, * class can be extended to contain details about the user has been updated. In this example, the
* the entire {@link User} object is passed on as data with the event. * entire {@link User} object is passed on as data with the event.
*/ */
public class UserUpdatedEvent extends AbstractEvent { public class UserUpdatedEvent extends AbstractEvent {

View File

@ -24,14 +24,15 @@
package com.iluwatar.eda.framework; package com.iluwatar.eda.framework;
/** /**
* A {@link Event} 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
* to a specific {@link Handler}. * Handler}.
*/ */
public interface Event { public interface Event {
/** /**
* Returns the message type as a {@link Class} object. In this example the message type is * Returns the message type as a {@link Class} object. In this example the message type is used to
* used to handle events by their type. * handle events by their type.
*
* @return the message type as a {@link Class}. * @return the message type as a {@link Class}.
*/ */
Class<? extends Event> getType(); Class<? extends Event> getType();

View File

@ -27,8 +27,8 @@ import java.util.HashMap;
import java.util.Map; import java.util.Map;
/** /**
* Handles the routing of {@link Event} messages to associated handlers. * Handles the routing of {@link Event} messages to associated handlers. A {@link HashMap} is used
* A {@link HashMap} is used to store the association between events and their respective handlers. * to store the association between events and their respective handlers.
*/ */
public class EventDispatcher { public class EventDispatcher {

View File

@ -24,16 +24,18 @@
package com.iluwatar.eda.framework; package com.iluwatar.eda.framework;
/** /**
* This interface can be implemented to handle different types of messages. * This interface can be implemented to handle different types of messages. Every handler is
* Every handler is responsible for a single of type message * responsible for a single of type message
*
* @param <E> Handler can handle events of type E * @param <E> Handler can handle events of type E
*/ */
public interface Handler<E extends Event> { public interface Handler<E extends Event> {
/** /**
* The onEvent method should implement and handle behavior related to the event. * The onEvent method should implement and handle behavior related to the event. This can be as
* This can be as simple as calling another service to handle the event on publishing the event on * simple as calling another service to handle the event on publishing the event on a queue to be
* a queue to be consumed by other sub systems. * consumed by other sub systems.
*
* @param event the {@link Event} object to be handled. * @param event the {@link Event} object to be handled.
*/ */
void onEvent(E event); void onEvent(E event);

View File

@ -27,8 +27,8 @@ import com.iluwatar.eda.event.UserCreatedEvent;
import com.iluwatar.eda.event.UserUpdatedEvent; import com.iluwatar.eda.event.UserUpdatedEvent;
/** /**
* This {@link User} class is a basic pojo used to demonstrate user data sent along with * This {@link User} class is a basic pojo used to demonstrate user data sent along with the {@link
* the {@link UserCreatedEvent} and {@link UserUpdatedEvent} events. * UserCreatedEvent} and {@link UserUpdatedEvent} events.
*/ */
public class User { public class User {

View File

@ -23,40 +23,40 @@
package com.iluwatar.event.queue; package com.iluwatar.event.queue;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.BufferedReader; import java.io.BufferedReader;
import java.io.IOException; import java.io.IOException;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import javax.sound.sampled.UnsupportedAudioFileException; import javax.sound.sampled.UnsupportedAudioFileException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/** /**
* Event or message queues provide an asynchronous communications protocol, meaning that the sender * Event or message queues provide an asynchronous communications protocol, meaning that the sender
* and receiver of the message do not need to interact with the message queue at the same time. * and receiver of the message do not need to interact with the message queue at the same time.
* Events or messages placed onto the queue are stored until the recipient retrieves them. Event * Events or messages placed onto the queue are stored until the recipient retrieves them. Event or
* or message queues have implicit or explicit limits on the size of data that may be transmitted * message queues have implicit or explicit limits on the size of data that may be transmitted in a
* in a single message and the number of messages that may remain outstanding on the queue. * single message and the number of messages that may remain outstanding on the queue. A queue
* A queue stores a series of notifications or requests in first-in, first-out order. * stores a series of notifications or requests in first-in, first-out order. Sending a notification
* Sending a notification enqueues the request and returns. The request processor then processes * enqueues the request and returns. The request processor then processes items from the queue at a
* items from the queue at a later time. * later time.
*/ */
public class App { public class App {
private static final Logger LOGGER = LoggerFactory.getLogger(App.class); private static final Logger LOGGER = LoggerFactory.getLogger(App.class);
/** /**
* Program entry point. * Program entry point.
* *
* @param args command line args * @param args command line args
* @throws IOException when there is a problem with the audio file loading * @throws IOException when there is a problem with the audio file loading
* @throws UnsupportedAudioFileException when the loaded audio file is unsupported * @throws UnsupportedAudioFileException when the loaded audio file is unsupported
*/ */
public static void main(String[] args) throws UnsupportedAudioFileException, IOException, InterruptedException { public static void main(String[] args) throws UnsupportedAudioFileException, IOException,
InterruptedException {
Audio audio = Audio.getInstance(); Audio audio = Audio.getInstance();
audio.playSound(audio.getAudioStream("./etc/Bass-Drum-1.wav"), -10.0f); audio.playSound(audio.getAudioStream("./etc/Bass-Drum-1.wav"), -10.0f);
audio.playSound(audio.getAudioStream("./etc/Closed-Hi-Hat-1.wav"), -8.0f); audio.playSound(audio.getAudioStream("./etc/Closed-Hi-Hat-1.wav"), -8.0f);
LOGGER.info("Press Enter key to stop the program..."); LOGGER.info("Press Enter key to stop the program...");
try (BufferedReader br = new BufferedReader(new InputStreamReader(System.in))) { try (BufferedReader br = new BufferedReader(new InputStreamReader(System.in))) {
br.read(); br.read();

View File

@ -23,22 +23,20 @@
package com.iluwatar.event.queue; package com.iluwatar.event.queue;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import javax.sound.sampled.AudioInputStream; import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem; import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Clip; import javax.sound.sampled.Clip;
import javax.sound.sampled.LineUnavailableException; import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.UnsupportedAudioFileException; import javax.sound.sampled.UnsupportedAudioFileException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/** /**
* This class implements the Event Queue pattern. * This class implements the Event Queue pattern.
* @author mkuprivecz
* *
* @author mkuprivecz
*/ */
public class Audio { public class Audio {
private static final Logger LOGGER = LoggerFactory.getLogger(Audio.class); private static final Logger LOGGER = LoggerFactory.getLogger(Audio.class);
@ -73,9 +71,10 @@ public class Audio {
updateThread.join(); updateThread.join();
updateThread = null; updateThread = null;
} }
/** /**
* This method check the Update Method's thread is started. * This method check the Update Method's thread is started.
*
* @return boolean * @return boolean
*/ */
public synchronized boolean isServiceRunning() { public synchronized boolean isServiceRunning() {
@ -83,8 +82,8 @@ public class Audio {
} }
/** /**
* Starts the thread for the Update Method pattern if it was not started previously. * Starts the thread for the Update Method pattern if it was not started previously. Also when the
* Also when the thread is is ready initializes the indexes of the queue * thread is is ready initializes the indexes of the queue
*/ */
public void init() { public void init() {
if (updateThread == null) { if (updateThread == null) {
@ -96,9 +95,9 @@ public class Audio {
} }
startThread(); startThread();
} }
/** /**
* This is a synchronized thread starter * This is a synchronized thread starter.
*/ */
private synchronized void startThread() { private synchronized void startThread() {
if (!updateThread.isAlive()) { if (!updateThread.isAlive()) {
@ -110,8 +109,9 @@ public class Audio {
/** /**
* This method adds a new audio into the queue. * This method adds a new audio into the queue.
*
* @param stream is the AudioInputStream for the method * @param stream is the AudioInputStream for the method
* @param volume is the level of the audio's volume * @param volume is the level of the audio's volume
*/ */
public void playSound(AudioInputStream stream, float volume) { public void playSound(AudioInputStream stream, float volume) {
init(); init();
@ -128,10 +128,9 @@ public class Audio {
getPendingAudio()[tailIndex] = new PlayMessage(stream, volume); getPendingAudio()[tailIndex] = new PlayMessage(stream, volume);
tailIndex = (tailIndex + 1) % MAX_PENDING; tailIndex = (tailIndex + 1) % MAX_PENDING;
} }
/** /**
* This method uses the Update Method pattern. * This method uses the Update Method pattern. It takes the audio from the queue and plays it
* It takes the audio from the queue and plays it
*/ */
private void update() { private void update() {
// If there are no pending requests, do nothing. // If there are no pending requests, do nothing.
@ -155,11 +154,12 @@ public class Audio {
} }
/** /**
* Returns the AudioInputStream of a file * Returns the AudioInputStream of a file.
*
* @param filePath is the path of the audio file * @param filePath is the path of the audio file
* @return AudioInputStream * @return AudioInputStream
* @throws UnsupportedAudioFileException when the audio file is not supported * @throws UnsupportedAudioFileException when the audio file is not supported
* @throws IOException when the file is not readable * @throws IOException when the file is not readable
*/ */
public AudioInputStream getAudioStream(String filePath) public AudioInputStream getAudioStream(String filePath)
throws UnsupportedAudioFileException, IOException { throws UnsupportedAudioFileException, IOException {
@ -167,7 +167,8 @@ public class Audio {
} }
/** /**
* Returns with the message array of the queue * Returns with the message array of the queue.
*
* @return PlayMessage[] * @return PlayMessage[]
*/ */
public PlayMessage[] getPendingAudio() { public PlayMessage[] getPendingAudio() {

View File

@ -27,15 +27,15 @@ import javax.sound.sampled.AudioInputStream;
/** /**
* The Event Queue's queue will store the instances of this class. * The Event Queue's queue will store the instances of this class.
* @author mkuprivecz
* *
* @author mkuprivecz
*/ */
public class PlayMessage { public class PlayMessage {
private AudioInputStream stream; private AudioInputStream stream;
private float volume; private float volume;
public PlayMessage(AudioInputStream stream, float volume) { public PlayMessage(AudioInputStream stream, float volume) {
setStream(stream); setStream(stream);
setVolume(volume); setVolume(volume);

View File

@ -42,13 +42,13 @@ import org.slf4j.LoggerFactory;
* transactional data, and maintain full audit trails and history that can enable compensating * transactional data, and maintain full audit trails and history that can enable compensating
* actions. * actions.
* *
* This App class is an example usage of Event Sourcing pattern. As an example, two bank account is * <p>This App class is an example usage of Event Sourcing pattern. As an example, two bank account
* created, then some money deposit and transfer actions are taken so a new state of accounts is * is created, then some money deposit and transfer actions are taken so a new state of accounts is
* created. At that point, state is cleared in order to represent a system shot down. After the shot * created. At that point, state is cleared in order to represent a system shot down. After the shot
* down, system state is recovered by re-creating the past events from event journal. Then state is * down, system state is recovered by re-creating the past events from event journal. Then state is
* printed so a user can view the last state is same with the state before system shot down. * printed so a user can view the last state is same with the state before system shot down.
* *
* Created by Serdar Hamzaogullari on 06.08.2017. * <p>Created by Serdar Hamzaogullari on 06.08.2017.
*/ */
public class App { public class App {
@ -86,10 +86,10 @@ public class App {
LOGGER.info("Do some money operations............"); LOGGER.info("Do some money operations............");
eventProcessor.process(new MoneyDepositEvent( eventProcessor.process(new MoneyDepositEvent(
2, new Date().getTime(), ACCOUNT_OF_DAENERYS, new BigDecimal("100000"))); 2, new Date().getTime(), ACCOUNT_OF_DAENERYS, new BigDecimal("100000")));
eventProcessor.process(new MoneyDepositEvent( eventProcessor.process(new MoneyDepositEvent(
3, new Date().getTime(), ACCOUNT_OF_JON, new BigDecimal("100"))); 3, new Date().getTime(), ACCOUNT_OF_JON, new BigDecimal("100")));
eventProcessor.process(new MoneyTransferEvent( eventProcessor.process(new MoneyTransferEvent(
4, new Date().getTime(), new BigDecimal("10000"), ACCOUNT_OF_DAENERYS, 4, new Date().getTime(), new BigDecimal("10000"), ACCOUNT_OF_DAENERYS,

View File

@ -32,11 +32,11 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
/** /**
* This is the Account class that holds the account info, the account number, * This is the Account class that holds the account info, the account number, account owner name and
* account owner name and money of the account. Account class also have the business logic of events * money of the account. Account class also have the business logic of events that effects this
* that effects this account. * account.
* *
* Created by Serdar Hamzaogullari on 06.08.2017. * <p>Created by Serdar Hamzaogullari on 06.08.2017.
*/ */
public class Account { public class Account {
@ -45,14 +45,15 @@ public class Account {
private final int accountNo; private final int accountNo;
private final String owner; private final String owner;
private BigDecimal money; private BigDecimal money;
private static final String MSG = "Some external api for only realtime execution could be called here."; private static final String MSG =
"Some external api for only realtime execution could be called here.";
/** /**
* Instantiates a new Account. * Instantiates a new Account.
* *
* @param accountNo the account no * @param accountNo the account no
* @param owner the owner * @param owner the owner
*/ */
public Account(int accountNo, String owner) { public Account(int accountNo, String owner) {
this.accountNo = accountNo; this.accountNo = accountNo;

View File

@ -27,12 +27,11 @@ import com.iluwatar.event.sourcing.domain.Account;
import com.iluwatar.event.sourcing.state.AccountAggregate; import com.iluwatar.event.sourcing.state.AccountAggregate;
/** /**
* This is the class that implements account create event. * This is the class that implements account create event. Holds the necessary info for an account
* Holds the necessary info for an account create event. * create event. Implements the process function that finds the event related domain objects and
* Implements the process function that finds the event related * calls the related domain object's handle event functions
* domain objects and calls the related domain object's handle event functions
* *
* Created by Serdar Hamzaogullari on 06.08.2017. * <p>Created by Serdar Hamzaogullari on 06.08.2017.
*/ */
public class AccountCreateEvent extends DomainEvent { public class AccountCreateEvent extends DomainEvent {
@ -42,10 +41,10 @@ public class AccountCreateEvent extends DomainEvent {
/** /**
* Instantiates a new Account create event. * Instantiates a new Account create event.
* *
* @param sequenceId the sequence id * @param sequenceId the sequence id
* @param createdTime the created time * @param createdTime the created time
* @param accountNo the account no * @param accountNo the account no
* @param owner the owner * @param owner the owner
*/ */
public AccountCreateEvent(long sequenceId, long createdTime, int accountNo, String owner) { public AccountCreateEvent(long sequenceId, long createdTime, int accountNo, String owner) {
super(sequenceId, createdTime, "AccountCreateEvent"); super(sequenceId, createdTime, "AccountCreateEvent");

View File

@ -28,7 +28,7 @@ import java.io.Serializable;
/** /**
* This is the base class for domain events. All events must extend this class. * This is the base class for domain events. All events must extend this class.
* *
* Created by Serdar Hamzaogullari on 06.08.2017. * <p>Created by Serdar Hamzaogullari on 06.08.2017.
*/ */
public abstract class DomainEvent implements Serializable { public abstract class DomainEvent implements Serializable {
@ -40,8 +40,8 @@ public abstract class DomainEvent implements Serializable {
/** /**
* Instantiates a new Domain event. * Instantiates a new Domain event.
* *
* @param sequenceId the sequence id * @param sequenceId the sequence id
* @param createdTime the created time * @param createdTime the created time
* @param eventClassName the event class name * @param eventClassName the event class name
*/ */
public DomainEvent(long sequenceId, long createdTime, String eventClassName) { public DomainEvent(long sequenceId, long createdTime, String eventClassName) {

View File

@ -28,12 +28,11 @@ import com.iluwatar.event.sourcing.state.AccountAggregate;
import java.math.BigDecimal; import java.math.BigDecimal;
/** /**
* This is the class that implements money deposit event. * This is the class that implements money deposit event. Holds the necessary info for a money
* Holds the necessary info for a money deposit event. * deposit event. Implements the process function that finds the event related domain objects and
* Implements the process function that finds the event related * calls the related domain object's handle event functions
* domain objects and calls the related domain object's handle event functions
* *
* Created by Serdar Hamzaogullari on 06.08.2017. * <p>Created by Serdar Hamzaogullari on 06.08.2017.
*/ */
public class MoneyDepositEvent extends DomainEvent { public class MoneyDepositEvent extends DomainEvent {
@ -43,10 +42,10 @@ public class MoneyDepositEvent extends DomainEvent {
/** /**
* Instantiates a new Money deposit event. * Instantiates a new Money deposit event.
* *
* @param sequenceId the sequence id * @param sequenceId the sequence id
* @param createdTime the created time * @param createdTime the created time
* @param accountNo the account no * @param accountNo the account no
* @param money the money * @param money the money
*/ */
public MoneyDepositEvent(long sequenceId, long createdTime, int accountNo, BigDecimal money) { public MoneyDepositEvent(long sequenceId, long createdTime, int accountNo, BigDecimal money) {
super(sequenceId, createdTime, "MoneyDepositEvent"); super(sequenceId, createdTime, "MoneyDepositEvent");

View File

@ -28,12 +28,11 @@ import com.iluwatar.event.sourcing.state.AccountAggregate;
import java.math.BigDecimal; import java.math.BigDecimal;
/** /**
* This is the class that implements money transfer event. * This is the class that implements money transfer event. Holds the necessary info for a money
* Holds the necessary info for a money transfer event. * transfer event. Implements the process function that finds the event related domain objects and
* Implements the process function that finds the event related * calls the related domain object's handle event functions
* domain objects and calls the related domain object's handle event functions
* *
* Created by Serdar Hamzaogullari on 06.08.2017. * <p>Created by Serdar Hamzaogullari on 06.08.2017.
*/ */
public class MoneyTransferEvent extends DomainEvent { public class MoneyTransferEvent extends DomainEvent {
@ -44,14 +43,14 @@ public class MoneyTransferEvent extends DomainEvent {
/** /**
* Instantiates a new Money transfer event. * Instantiates a new Money transfer event.
* *
* @param sequenceId the sequence id * @param sequenceId the sequence id
* @param createdTime the created time * @param createdTime the created time
* @param money the money * @param money the money
* @param accountNoFrom the account no from * @param accountNoFrom the account no from
* @param accountNoTo the account no to * @param accountNoTo the account no to
*/ */
public MoneyTransferEvent(long sequenceId, long createdTime, BigDecimal money, int accountNoFrom, public MoneyTransferEvent(long sequenceId, long createdTime, BigDecimal money, int accountNoFrom,
int accountNoTo) { int accountNoTo) {
super(sequenceId, createdTime, "MoneyTransferEvent"); super(sequenceId, createdTime, "MoneyTransferEvent");
this.money = money; this.money = money;
this.accountNoFrom = accountNoFrom; this.accountNoFrom = accountNoFrom;

View File

@ -26,11 +26,10 @@ package com.iluwatar.event.sourcing.processor;
import com.iluwatar.event.sourcing.event.DomainEvent; import com.iluwatar.event.sourcing.event.DomainEvent;
/** /**
* This is the implementation of event processor. * This is the implementation of event processor. All events are processed by this class. This
* All events are processed by this class. * processor uses processorJournal to persist and recover events.
* This processor uses processorJournal to persist and recover events.
* *
* Created by Serdar Hamzaogullari on 06.08.2017. * <p>Created by Serdar Hamzaogullari on 06.08.2017.
*/ */
public class DomainEventProcessor { public class DomainEventProcessor {

View File

@ -43,15 +43,14 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
/** /**
* This is the implementation of event journal. * This is the implementation of event journal. This implementation serialize/deserialize the events
* This implementation serialize/deserialize the events with JSON * with JSON and writes/reads them on a Journal.json file at the working directory.
* and writes/reads them on a Journal.json file at the working directory.
* *
* Created by Serdar Hamzaogullari on 06.08.2017. * <p>Created by Serdar Hamzaogullari on 06.08.2017.
*/ */
public class JsonFileJournal { public class JsonFileJournal {
private final File aFile; private final File file;
private final List<String> events = new ArrayList<>(); private final List<String> events = new ArrayList<>();
private int index = 0; private int index = 0;
@ -59,10 +58,10 @@ public class JsonFileJournal {
* Instantiates a new Json file journal. * Instantiates a new Json file journal.
*/ */
public JsonFileJournal() { public JsonFileJournal() {
aFile = new File("Journal.json"); file = new File("Journal.json");
if (aFile.exists()) { if (file.exists()) {
try (BufferedReader input = new BufferedReader( try (BufferedReader input = new BufferedReader(
new InputStreamReader(new FileInputStream(aFile), "UTF-8"))) { new InputStreamReader(new FileInputStream(file), "UTF-8"))) {
String line; String line;
while ((line = input.readLine()) != null) { while ((line = input.readLine()) != null) {
events.add(line); events.add(line);
@ -88,14 +87,14 @@ public class JsonFileJournal {
jsonElement = gson.toJsonTree(domainEvent, AccountCreateEvent.class); jsonElement = gson.toJsonTree(domainEvent, AccountCreateEvent.class);
} else if (domainEvent instanceof MoneyDepositEvent) { } else if (domainEvent instanceof MoneyDepositEvent) {
jsonElement = gson.toJsonTree(domainEvent, MoneyDepositEvent.class); jsonElement = gson.toJsonTree(domainEvent, MoneyDepositEvent.class);
} else if (domainEvent instanceof MoneyTransferEvent) { } else if (domainEvent instanceof MoneyTransferEvent) {
jsonElement = gson.toJsonTree(domainEvent, MoneyTransferEvent.class); jsonElement = gson.toJsonTree(domainEvent, MoneyTransferEvent.class);
} else { } else {
throw new RuntimeException("Journal Event not recegnized"); throw new RuntimeException("Journal Event not recegnized");
} }
try (Writer output = new BufferedWriter( try (Writer output = new BufferedWriter(
new OutputStreamWriter(new FileOutputStream(aFile, true), "UTF-8"))) { new OutputStreamWriter(new FileOutputStream(file, true), "UTF-8"))) {
String eventString = jsonElement.toString(); String eventString = jsonElement.toString();
output.write(eventString + "\r\n"); output.write(eventString + "\r\n");
} catch (IOException e) { } catch (IOException e) {
@ -108,7 +107,7 @@ public class JsonFileJournal {
* Reset. * Reset.
*/ */
public void reset() { public void reset() {
aFile.delete(); file.delete();
} }
@ -135,7 +134,7 @@ public class JsonFileJournal {
domainEvent = gson.fromJson(jsonElement, MoneyDepositEvent.class); domainEvent = gson.fromJson(jsonElement, MoneyDepositEvent.class);
} else if (eventClassName.equals("MoneyTransferEvent")) { } else if (eventClassName.equals("MoneyTransferEvent")) {
domainEvent = gson.fromJson(jsonElement, MoneyTransferEvent.class); domainEvent = gson.fromJson(jsonElement, MoneyTransferEvent.class);
} else { } else {
throw new RuntimeException("Journal Event not recegnized"); throw new RuntimeException("Journal Event not recegnized");
} }

View File

@ -28,10 +28,9 @@ import java.util.HashMap;
import java.util.Map; import java.util.Map;
/** /**
* This is the static accounts map holder class. * This is the static accounts map holder class. This class holds the state of the accounts.
* This class holds the state of the accounts.
* *
* Created by Serdar Hamzaogullari on 06.08.2017. * <p>Created by Serdar Hamzaogullari on 06.08.2017.
*/ */
public class AccountAggregate { public class AccountAggregate {